You've already forked KernelSU-Next
mirror of
https://github.com/KernelSU-Next/KernelSU-Next.git
synced 2025-08-27 23:46:34 +00:00
Compare commits
109 Commits
v1.0.8
...
next-susfs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db7d73c202 | ||
|
|
e15652c758 | ||
|
|
194ba5820a | ||
|
|
2165241049 | ||
|
|
0c6c0a512c | ||
|
|
d88bffdba2 | ||
|
|
278b1226dc | ||
|
|
89c9b1b8b8 | ||
|
|
b04f45c278 | ||
|
|
e4a6ade958 | ||
|
|
6fe4fcbce0 | ||
|
|
52112a7ee3 | ||
|
|
81f4f09d0c | ||
|
|
2241696498 | ||
|
|
514c5458ed | ||
|
|
d30bb33a9c | ||
|
|
ec7fe6b039 | ||
|
|
3fd61e0ee5 | ||
|
|
8fc85993f1 | ||
|
|
df07860e44 | ||
|
|
bd03c296a1 | ||
|
|
14b7861f44 | ||
|
|
3c421b1362 | ||
|
|
c6b60a24e8 | ||
|
|
1baedd89b7 | ||
|
|
b567e9b275 | ||
|
|
3ba5b028d4 | ||
|
|
4d633a1e0e | ||
|
|
f08fcec777 | ||
|
|
afe6ad7261 | ||
|
|
54b26fd32c | ||
|
|
4b56b14a4f | ||
|
|
9b4c6057a0 | ||
|
|
873740ef1c | ||
|
|
ad80c1ea77 | ||
|
|
d5c6f0affb | ||
|
|
162056f9ff | ||
|
|
3af1d0354d | ||
|
|
6adb2eaf51 | ||
|
|
ce91e4fedb | ||
|
|
a36390ea03 | ||
|
|
e31e0271cb | ||
|
|
b97fc2bec2 | ||
|
|
10875ee190 | ||
|
|
fdb01c918a | ||
|
|
6afa86d2ae | ||
|
|
25fa6b7b9b | ||
|
|
a361fa3272 | ||
|
|
4a9733c078 | ||
|
|
31aa571bc2 | ||
|
|
58167a4289 | ||
|
|
a8bfd1cc7d | ||
|
|
58aeb2697a | ||
|
|
7f68766dc4 | ||
|
|
310c0573c6 | ||
|
|
d1aad01df3 | ||
|
|
9733b92d30 | ||
|
|
aaf776f421 | ||
|
|
5e33aee99f | ||
|
|
4e3f06d405 | ||
|
|
98b9863041 | ||
|
|
29ae76d1fb | ||
|
|
2c3841558e | ||
|
|
c8b357e31b | ||
|
|
3ad02ff50b | ||
|
|
6a54b30a9d | ||
|
|
b0cb3bb4c2 | ||
|
|
7f957be99b | ||
|
|
a54c319d55 | ||
|
|
2c71531533 | ||
|
|
5c61a70e5a | ||
|
|
fdf1d61735 | ||
|
|
93dc61e113 | ||
|
|
d80a3ebcda | ||
|
|
4270fd8b1e | ||
|
|
764dbc3782 | ||
|
|
080ab9a952 | ||
|
|
a9cab5ccfd | ||
|
|
3d44602537 | ||
|
|
88eb2a2723 | ||
|
|
e272e557b0 | ||
|
|
2a4794e422 | ||
|
|
818bdbead6 | ||
|
|
76249fa67d | ||
|
|
ed50b57b57 | ||
|
|
f05f776a08 | ||
|
|
c9b79c3016 | ||
|
|
3ff10d6622 | ||
|
|
b95d2b69b6 | ||
|
|
2cd8453877 | ||
|
|
b7300b0525 | ||
|
|
3a278d560f | ||
|
|
03fa2eddb2 | ||
|
|
b74e953ad2 | ||
|
|
39717b0a3f | ||
|
|
7f0eccd3d5 | ||
|
|
78eb3b0b22 | ||
|
|
39f20bf573 | ||
|
|
092eb1b23d | ||
|
|
30e2ed5db5 | ||
|
|
dc7ae2db5f | ||
|
|
b3b7ef1cb3 | ||
|
|
4de4d1e091 | ||
|
|
0beea57ab7 | ||
|
|
49aee1ff4c | ||
|
|
f7a3699fe3 | ||
|
|
66d42de599 | ||
|
|
d562594ae1 | ||
|
|
02afc6710c |
33
.github/ISSUE_TEMPLATE/add_device.yml
vendored
33
.github/ISSUE_TEMPLATE/add_device.yml
vendored
@@ -1,33 +0,0 @@
|
||||
name: Contribute to Unofficially Supported Devices
|
||||
description: Add your device kernel source to KernelSU Next's Unofficially Supported Device List
|
||||
title: "[Add Device]: "
|
||||
labels: ["add-device"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for supporting KernelSU Next!
|
||||
- type: input
|
||||
id: repo-url
|
||||
attributes:
|
||||
label: Repository URL
|
||||
description: Your repository URL
|
||||
placeholder: https://github.com/rifsxd/KernelSU-Next
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: device
|
||||
attributes:
|
||||
label: Device
|
||||
description: Please describe the device maintained by you.
|
||||
placeholder: GKI 2.0 Device
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: Code of Conduct
|
||||
description: By submitting this issue, you should be the maintainer of the repository.
|
||||
options:
|
||||
- label: I'm the maintainer of this repository
|
||||
required: true
|
||||
72
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
72
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,72 +0,0 @@
|
||||
name: Bug report
|
||||
description: Create a report to help us improve KernelSU Next
|
||||
labels: [Bug]
|
||||
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Please check before submitting an issue
|
||||
options:
|
||||
- label: I have searched the issues and haven't found anything relevant
|
||||
required: true
|
||||
|
||||
- label: I will upload bugreport file in KernelSU Manager - Settings - Report log
|
||||
required: true
|
||||
|
||||
- label: I know how to reproduce the issue which may not be specific to my device
|
||||
required: false
|
||||
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the bug
|
||||
description: A clear and concise description of what the bug is
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: To Reproduce
|
||||
description: Steps to reproduce the behaviour
|
||||
placeholder: |
|
||||
- 1. Go to '...'
|
||||
- 2. Click on '....'
|
||||
- 3. Scroll down to '....'
|
||||
- 4. See error
|
||||
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: A clear and concise description of what you expected to happen.
|
||||
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: If applicable, add screenshots to help explain your problem.
|
||||
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Logs
|
||||
description: If applicable, add crash or any other logs to help us figure out the problem.
|
||||
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Device info
|
||||
value: |
|
||||
- Device:
|
||||
- OS Version:
|
||||
- KernelSU Version:
|
||||
- Kernel Version:
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context about the problem here.
|
||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
5
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,5 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Feature Request
|
||||
url: https://t.me/ksunext/578
|
||||
about: "We do not accept external Feature Requests anymore, check the link for more details."
|
||||
11
.github/ISSUE_TEMPLATE/custom.yml
vendored
11
.github/ISSUE_TEMPLATE/custom.yml
vendored
@@ -1,11 +0,0 @@
|
||||
name: Custom issue template
|
||||
description: WARNING! If you are reporting a bug but use this template, the issue will be closed directly.
|
||||
title: '[Custom]'
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: "Describe your problem."
|
||||
validations:
|
||||
required: true
|
||||
|
||||
38
.github/dependabot.yml
vendored
38
.github/dependabot.yml
vendored
@@ -1,38 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
groups:
|
||||
actions:
|
||||
patterns:
|
||||
- "*"
|
||||
- package-ecosystem: cargo
|
||||
directory: userspace/ksud_magic
|
||||
schedule:
|
||||
interval: daily
|
||||
allow:
|
||||
- dependency-type: "all"
|
||||
groups:
|
||||
crates:
|
||||
patterns:
|
||||
- "*"
|
||||
- package-ecosystem: cargo
|
||||
directory: userspace/ksud_overlayfs
|
||||
schedule:
|
||||
interval: daily
|
||||
allow:
|
||||
- dependency-type: "all"
|
||||
groups:
|
||||
crates:
|
||||
patterns:
|
||||
- "*"
|
||||
- package-ecosystem: gradle
|
||||
directory: manager
|
||||
schedule:
|
||||
interval: daily
|
||||
groups:
|
||||
maven:
|
||||
patterns:
|
||||
- "*"
|
||||
71
.github/manifests/android-14-avd_x86_64.xml
vendored
71
.github/manifests/android-14-avd_x86_64.xml
vendored
@@ -1,71 +0,0 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!--https://ci.android.com/builds/submitted/9964412/kernel_virt_x86_64/latest/manifest_9964412.xml-->
|
||||
<manifest>
|
||||
<remote name="aosp" fetch="https://android.googlesource.com/" review="https://android.googlesource.com/" />
|
||||
|
||||
<default revision="master" remote="aosp" sync-j="4" />
|
||||
|
||||
<superproject name="kernel/superproject" remote="aosp" revision="common-android14-6.1" />
|
||||
|
||||
<project path="build/kernel" name="kernel/build" revision="b0377a072bb3f78cdacfd6d809914a9d1b0c0148">
|
||||
<linkfile dest="tools/bazel" src="kleaf/bazel.sh" />
|
||||
|
||||
<linkfile dest="WORKSPACE" src="kleaf/bazel.WORKSPACE" />
|
||||
|
||||
<linkfile dest="build/build.sh" src="build.sh" />
|
||||
|
||||
<linkfile dest="build/build_abi.sh" src="build_abi.sh" />
|
||||
|
||||
<linkfile dest="build/build_test.sh" src="build_test.sh" />
|
||||
|
||||
<linkfile dest="build/build_utils.sh" src="build_utils.sh" />
|
||||
|
||||
<linkfile dest="build/config.sh" src="config.sh" />
|
||||
|
||||
<linkfile dest="build/envsetup.sh" src="envsetup.sh" />
|
||||
|
||||
<linkfile dest="build/_setup_env.sh" src="_setup_env.sh" />
|
||||
|
||||
<linkfile dest="build/multi-switcher.sh" src="multi-switcher.sh" />
|
||||
|
||||
<linkfile dest="build/abi" src="abi" />
|
||||
|
||||
<linkfile dest="build/static_analysis" src="static_analysis" />
|
||||
</project>
|
||||
|
||||
<project path="common" name="kernel/common" revision="7e35917775b8b3e3346a87f294e334e258bf15e6">
|
||||
<linkfile dest=".source_date_epoch_dir" src="." />
|
||||
</project>
|
||||
|
||||
<project path="kernel/tests" name="kernel/tests" revision="c90a1c1b226b975cc31e709fa96fc1c6ecdbe272" />
|
||||
|
||||
<project path="kernel/configs" name="kernel/configs" revision="52a7267d6a9f9efabf3cb43839bb5e7f7ff05be3" />
|
||||
|
||||
<project path="common-modules/virtual-device" name="kernel/common-modules/virtual-device" revision="0d03de3246301028775f05ea388c2c444344a268" />
|
||||
|
||||
<project path="prebuilts/clang/host/linux-x86" name="platform/prebuilts/clang/host/linux-x86" clone-depth="1" revision="4f7e5adc160ab726ac5bafb260de98e612904c50" />
|
||||
|
||||
<project path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8" clone-depth="1" revision="f7b0d5b0ee369864d5ac3e96ae24ec9e2b6a52da" />
|
||||
|
||||
<project path="prebuilts/build-tools" name="platform/prebuilts/build-tools" clone-depth="1" revision="dc92e06585a7647bf739a2309a721b82fcfa01d4" />
|
||||
|
||||
<project path="prebuilts/clang-tools" name="platform/prebuilts/clang-tools" clone-depth="1" revision="5611871963f54c688d3ac49e527aecdef21e8567" />
|
||||
|
||||
<project path="prebuilts/kernel-build-tools" name="kernel/prebuilts/build-tools" clone-depth="1" revision="2597cb1b5525e419b7fa806373be673054a68d29" />
|
||||
|
||||
<project path="tools/mkbootimg" name="platform/system/tools/mkbootimg" revision="2680066d0844544b3e78d6022cd21321d31837c3" />
|
||||
|
||||
<project path="prebuilts/bazel/linux-x86_64" name="platform/prebuilts/bazel/linux-x86_64" clone-depth="1" revision="4fdb9395071ff22118311d434d697c2b6fd887b4" />
|
||||
|
||||
<project path="prebuilts/jdk/jdk11" name="platform/prebuilts/jdk/jdk11" clone-depth="1" revision="491e6aa056676f29c4541f71bd738e4e876e4ba2" />
|
||||
|
||||
<project path="prebuilts/ndk-r23" name="toolchain/prebuilts/ndk/r23" clone-depth="1" revision="19ac7e4eded12adb99d4f613490dde6dd0e72664" />
|
||||
|
||||
<project path="external/bazel-skylib" name="platform/external/bazel-skylib" revision="f998e5dc13c03f0eae9e373263d3afff0932c738" />
|
||||
|
||||
<project path="build/bazel_common_rules" name="platform/build/bazel_common_rules" revision="707b2c5fe3d0d7d934a93e00a8a4062e83557831" />
|
||||
|
||||
<project path="external/stardoc" name="platform/external/stardoc" revision="e83f522ee95419e55d2c5654aa6e0143beeef595" />
|
||||
|
||||
<project path="external/python/absl-py" name="platform/external/python/absl-py" revision="393d0b1e3f0fea3e95944a2fd3282cc9f76d4f14" />
|
||||
</manifest>
|
||||
89
.github/manifests/android-15-avd_aarch64.xml
vendored
89
.github/manifests/android-15-avd_aarch64.xml
vendored
@@ -1,89 +0,0 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!-- https://ci.android.com/builds/submitted/11577653/kernel_virt_aarch64/latest/manifest_11577653.xml -->
|
||||
<manifest>
|
||||
<remote name="aosp" fetch="https://android.googlesource.com/" review="https://android.googlesource.com/" />
|
||||
|
||||
<default revision="main" remote="aosp" sync-j="4" />
|
||||
|
||||
<superproject name="kernel/superproject" remote="aosp" revision="common-android15-6.6" />
|
||||
|
||||
<project path="build/kernel" name="kernel/build" groups="ddk" revision="9a2196a1ec1048c2869750c9d3969c88ac18adcd">
|
||||
<linkfile dest="tools/bazel" src="kleaf/bazel.sh" />
|
||||
|
||||
<linkfile dest="WORKSPACE" src="kleaf/bazel.WORKSPACE" />
|
||||
|
||||
<linkfile dest="MODULE.bazel" src="kleaf/bzlmod/bazel.MODULE.bazel" />
|
||||
|
||||
<linkfile dest="WORKSPACE.bzlmod" src="kleaf/bzlmod/bazel.WORKSPACE.bzlmod" />
|
||||
</project>
|
||||
|
||||
<project path="common" name="kernel/common" revision="ac1a7c65ff1bc7ece5569d62f02b121b4f2364f8" />
|
||||
|
||||
<project path="kernel/common-patches" name="kernel/common-patches" revision="3807ce65081de12ef4baa2a04487306672685160">
|
||||
<linkfile dest="common/patches" src="android-mainline" />
|
||||
</project>
|
||||
|
||||
<project path="kernel/tests" name="kernel/tests" revision="ca9fd66f5b48abc92990c9c770f73380b428362b" />
|
||||
|
||||
<project path="kernel/configs" name="kernel/configs" revision="be625f2ccf377a75d0ea86c082c716c322b8d4c6" />
|
||||
|
||||
<project path="common-modules/virtual-device" name="kernel/common-modules/virtual-device" revision="60a24583ac921279e40a44f818040e40abb3ef46" />
|
||||
|
||||
<project path="prebuilts/clang/host/linux-x86" name="platform/prebuilts/clang/host/linux-x86" revision="93a1369ba33743a87bdf0183373f590a36ff7cb1" clone-depth="1" groups="ddk" />
|
||||
|
||||
<project path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8" clone-depth="1" groups="ddk" revision="cef8f53bb61fbdb02dbf4d433004f6cb637c3bc6" />
|
||||
|
||||
<project path="prebuilts/build-tools" name="platform/prebuilts/build-tools" clone-depth="1" groups="ddk" revision="5aca9957ab19d2668c7f1da1954bbe89652d5fed" />
|
||||
|
||||
<project path="prebuilts/clang-tools" name="platform/prebuilts/clang-tools" clone-depth="1" revision="69f9fb9b8e75c6f1ff01f380d5251757785bb823" />
|
||||
|
||||
<project path="prebuilts/kernel-build-tools" name="kernel/prebuilts/build-tools" clone-depth="1" groups="ddk" revision="b09295493adc8d804b6d24286660f6e451e387fd" />
|
||||
|
||||
<project path="prebuilts/rust" name="platform/prebuilts/rust" revision="adc0e5499c3ddac831ca596d12cbef8d9747f737" clone-depth="1" />
|
||||
|
||||
<project path="prebuilts/tradefed" name="platform/tools/tradefederation/prebuilts" clone-depth="1" revision="a76ca09c5593e22e65b0d823d508882c6c64c13e" />
|
||||
|
||||
<project path="prebuilts/asuite" name="platform/prebuilts/asuite" clone-depth="1" revision="24510f175cb313a92241500efee917c2930d5d30" />
|
||||
|
||||
<project path="tools/mkbootimg" name="platform/system/tools/mkbootimg" revision="28b7934249c2885db8b561f1439d74663fcdce93" />
|
||||
|
||||
<project path="prebuilts/jdk/jdk11" name="platform/prebuilts/jdk/jdk11" revision="c6c90521b7c317f13d41bbd9336a8d45ee202cec" clone-depth="1" groups="ddk" />
|
||||
|
||||
<project path="prebuilts/ndk-r26" name="toolchain/prebuilts/ndk/r26" clone-depth="1" groups="ddk" revision="e535051ebc04204cec44bde38f62385d63180388" />
|
||||
|
||||
<project path="external/bazel-skylib" name="platform/external/bazel-skylib" groups="ddk" revision="6b103c40d8113f001475d5e13672922ef2aa0e5a" />
|
||||
|
||||
<project path="build/bazel_common_rules" name="platform/build/bazel_common_rules" groups="ddk" revision="2a10807a06153b5862da0369f4b6b368afc2dd08" />
|
||||
|
||||
<project path="external/libcap-ng" name="platform/external/libcap-ng" revision="2bcc92ae19481dd2b8d3ce3abdfbbee49261abe6" />
|
||||
|
||||
<project path="external/libcap" name="platform/external/libcap" revision="d7d1a0a38c5be06a7e7d6391d140b54878836f48" />
|
||||
|
||||
<project path="external/stardoc" name="platform/external/stardoc" groups="ddk" revision="f31250f9f5b03834d9964aaee7a3794c1d73d4a2" />
|
||||
|
||||
<project path="external/python/absl-py" name="platform/external/python/absl-py" groups="ddk" revision="9ae5a78fc57c3cd539398373ae39601a8b923e62" />
|
||||
|
||||
<project path="external/bazelbuild-bazel-central-registry" name="platform/external/bazelbuild-bazel-central-registry" revision="3422f064566c274ea66633442521704d4a22486d" groups="ddk" />
|
||||
|
||||
<project path="external/bazelbuild-platforms" name="platform/external/bazelbuild-platforms" groups="ddk" revision="e352aabd0131f3ac3f340282a43ba85ffc3fe8fa" />
|
||||
|
||||
<project path="external/bazelbuild-apple_support" name="platform/external/bazelbuild-apple_support" groups="ddk" revision="f6003e1e3763f8aad9fb9acae79cfa5fff9ae988" />
|
||||
|
||||
<project path="external/bazelbuild-rules_cc" name="platform/external/bazelbuild-rules_cc" groups="ddk" revision="f0df148dbeb9b9ed3816aad328ebe7c65efaaa24" />
|
||||
|
||||
<project path="external/bazelbuild-rules_java" name="platform/external/bazelbuild-rules_java" groups="ddk" revision="8e548c7053dffd1717d565f0409a88992f401da1" />
|
||||
|
||||
<project path="external/bazelbuild-rules_license" name="platform/external/bazelbuild-rules_license" groups="ddk" revision="f578df4fd057ffe2023728444759535685631548" />
|
||||
|
||||
<project path="external/bazelbuild-rules_pkg" name="platform/external/bazelbuild-rules_pkg" groups="ddk" revision="429887dfd8db834498ad95e99043f771a3882af0" />
|
||||
|
||||
<project path="external/bazelbuild-rules_python" name="platform/external/bazelbuild-rules_python" groups="ddk" revision="f71847ac898655b67634bb14e77a7408c4fb5e00" />
|
||||
|
||||
<project path="external/bazelbuild-rules_rust" name="platform/external/bazelbuild-rules_rust" groups="ddk" revision="1520b49835be9122c2424231357d4db80069cc38" />
|
||||
|
||||
<project path="external/pigz" name="platform/external/pigz" groups="ddk" revision="9bc9fa17d499ddde88b77820f6d063e16c0cdd42" />
|
||||
|
||||
<project path="external/zlib" name="platform/external/zlib" groups="ddk" revision="eff168fd731068a3faddd9aae056875e10014a51" />
|
||||
|
||||
<project path="external/zopfli" name="platform/external/zopfli" groups="ddk" revision="36c79f00e5229800d2aaa13fc42c301ec8ef1153" />
|
||||
</manifest>
|
||||
89
.github/manifests/android-15-avd_x86_64.xml
vendored
89
.github/manifests/android-15-avd_x86_64.xml
vendored
@@ -1,89 +0,0 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!-- https://ci.android.com/builds/submitted/11577653/kernel_virt_x86_64/latest/manifest_11577653.xml -->
|
||||
<manifest>
|
||||
<remote name="aosp" fetch="https://android.googlesource.com/" review="https://android.googlesource.com/" />
|
||||
|
||||
<default revision="main" remote="aosp" sync-j="4" />
|
||||
|
||||
<superproject name="kernel/superproject" remote="aosp" revision="common-android15-6.6" />
|
||||
|
||||
<project path="build/kernel" name="kernel/build" groups="ddk" revision="9a2196a1ec1048c2869750c9d3969c88ac18adcd">
|
||||
<linkfile dest="tools/bazel" src="kleaf/bazel.sh" />
|
||||
|
||||
<linkfile dest="WORKSPACE" src="kleaf/bazel.WORKSPACE" />
|
||||
|
||||
<linkfile dest="MODULE.bazel" src="kleaf/bzlmod/bazel.MODULE.bazel" />
|
||||
|
||||
<linkfile dest="WORKSPACE.bzlmod" src="kleaf/bzlmod/bazel.WORKSPACE.bzlmod" />
|
||||
</project>
|
||||
|
||||
<project path="common" name="kernel/common" revision="ac1a7c65ff1bc7ece5569d62f02b121b4f2364f8" />
|
||||
|
||||
<project path="kernel/common-patches" name="kernel/common-patches" revision="3807ce65081de12ef4baa2a04487306672685160">
|
||||
<linkfile dest="common/patches" src="android-mainline" />
|
||||
</project>
|
||||
|
||||
<project path="kernel/tests" name="kernel/tests" revision="ca9fd66f5b48abc92990c9c770f73380b428362b" />
|
||||
|
||||
<project path="kernel/configs" name="kernel/configs" revision="be625f2ccf377a75d0ea86c082c716c322b8d4c6" />
|
||||
|
||||
<project path="common-modules/virtual-device" name="kernel/common-modules/virtual-device" revision="60a24583ac921279e40a44f818040e40abb3ef46" />
|
||||
|
||||
<project path="prebuilts/clang/host/linux-x86" name="platform/prebuilts/clang/host/linux-x86" revision="93a1369ba33743a87bdf0183373f590a36ff7cb1" clone-depth="1" groups="ddk" />
|
||||
|
||||
<project path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8" clone-depth="1" groups="ddk" revision="cef8f53bb61fbdb02dbf4d433004f6cb637c3bc6" />
|
||||
|
||||
<project path="prebuilts/build-tools" name="platform/prebuilts/build-tools" clone-depth="1" groups="ddk" revision="5aca9957ab19d2668c7f1da1954bbe89652d5fed" />
|
||||
|
||||
<project path="prebuilts/clang-tools" name="platform/prebuilts/clang-tools" clone-depth="1" revision="69f9fb9b8e75c6f1ff01f380d5251757785bb823" />
|
||||
|
||||
<project path="prebuilts/kernel-build-tools" name="kernel/prebuilts/build-tools" clone-depth="1" groups="ddk" revision="b09295493adc8d804b6d24286660f6e451e387fd" />
|
||||
|
||||
<project path="prebuilts/rust" name="platform/prebuilts/rust" revision="adc0e5499c3ddac831ca596d12cbef8d9747f737" clone-depth="1" />
|
||||
|
||||
<project path="prebuilts/tradefed" name="platform/tools/tradefederation/prebuilts" clone-depth="1" revision="a76ca09c5593e22e65b0d823d508882c6c64c13e" />
|
||||
|
||||
<project path="prebuilts/asuite" name="platform/prebuilts/asuite" clone-depth="1" revision="24510f175cb313a92241500efee917c2930d5d30" />
|
||||
|
||||
<project path="tools/mkbootimg" name="platform/system/tools/mkbootimg" revision="28b7934249c2885db8b561f1439d74663fcdce93" />
|
||||
|
||||
<project path="prebuilts/jdk/jdk11" name="platform/prebuilts/jdk/jdk11" revision="c6c90521b7c317f13d41bbd9336a8d45ee202cec" clone-depth="1" groups="ddk" />
|
||||
|
||||
<project path="prebuilts/ndk-r26" name="toolchain/prebuilts/ndk/r26" clone-depth="1" groups="ddk" revision="e535051ebc04204cec44bde38f62385d63180388" />
|
||||
|
||||
<project path="external/bazel-skylib" name="platform/external/bazel-skylib" groups="ddk" revision="6b103c40d8113f001475d5e13672922ef2aa0e5a" />
|
||||
|
||||
<project path="build/bazel_common_rules" name="platform/build/bazel_common_rules" groups="ddk" revision="2a10807a06153b5862da0369f4b6b368afc2dd08" />
|
||||
|
||||
<project path="external/libcap-ng" name="platform/external/libcap-ng" revision="2bcc92ae19481dd2b8d3ce3abdfbbee49261abe6" />
|
||||
|
||||
<project path="external/libcap" name="platform/external/libcap" revision="d7d1a0a38c5be06a7e7d6391d140b54878836f48" />
|
||||
|
||||
<project path="external/stardoc" name="platform/external/stardoc" groups="ddk" revision="f31250f9f5b03834d9964aaee7a3794c1d73d4a2" />
|
||||
|
||||
<project path="external/python/absl-py" name="platform/external/python/absl-py" groups="ddk" revision="9ae5a78fc57c3cd539398373ae39601a8b923e62" />
|
||||
|
||||
<project path="external/bazelbuild-bazel-central-registry" name="platform/external/bazelbuild-bazel-central-registry" revision="3422f064566c274ea66633442521704d4a22486d" groups="ddk" />
|
||||
|
||||
<project path="external/bazelbuild-platforms" name="platform/external/bazelbuild-platforms" groups="ddk" revision="e352aabd0131f3ac3f340282a43ba85ffc3fe8fa" />
|
||||
|
||||
<project path="external/bazelbuild-apple_support" name="platform/external/bazelbuild-apple_support" groups="ddk" revision="f6003e1e3763f8aad9fb9acae79cfa5fff9ae988" />
|
||||
|
||||
<project path="external/bazelbuild-rules_cc" name="platform/external/bazelbuild-rules_cc" groups="ddk" revision="f0df148dbeb9b9ed3816aad328ebe7c65efaaa24" />
|
||||
|
||||
<project path="external/bazelbuild-rules_java" name="platform/external/bazelbuild-rules_java" groups="ddk" revision="8e548c7053dffd1717d565f0409a88992f401da1" />
|
||||
|
||||
<project path="external/bazelbuild-rules_license" name="platform/external/bazelbuild-rules_license" groups="ddk" revision="f578df4fd057ffe2023728444759535685631548" />
|
||||
|
||||
<project path="external/bazelbuild-rules_pkg" name="platform/external/bazelbuild-rules_pkg" groups="ddk" revision="429887dfd8db834498ad95e99043f771a3882af0" />
|
||||
|
||||
<project path="external/bazelbuild-rules_python" name="platform/external/bazelbuild-rules_python" groups="ddk" revision="f71847ac898655b67634bb14e77a7408c4fb5e00" />
|
||||
|
||||
<project path="external/bazelbuild-rules_rust" name="platform/external/bazelbuild-rules_rust" groups="ddk" revision="1520b49835be9122c2424231357d4db80069cc38" />
|
||||
|
||||
<project path="external/pigz" name="platform/external/pigz" groups="ddk" revision="9bc9fa17d499ddde88b77820f6d063e16c0cdd42" />
|
||||
|
||||
<project path="external/zlib" name="platform/external/zlib" groups="ddk" revision="eff168fd731068a3faddd9aae056875e10014a51" />
|
||||
|
||||
<project path="external/zopfli" name="platform/external/zopfli" groups="ddk" revision="36c79f00e5229800d2aaa13fc42c301ec8ef1153" />
|
||||
</manifest>
|
||||
64
.github/scripts/build_a12.sh
vendored
64
.github/scripts/build_a12.sh
vendored
@@ -1,64 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
build_from_image() {
|
||||
export TITLE
|
||||
TITLE=kernel-aarch64-${1//Image-/}
|
||||
echo "[+] title: $TITLE"
|
||||
|
||||
export PATCH_LEVEL
|
||||
PATCH_LEVEL=$(echo "$1" | awk -F_ '{ print $2}')
|
||||
echo "[+] patch level: $PATCH_LEVEL"
|
||||
|
||||
echo '[+] Download prebuilt ramdisk'
|
||||
GKI_URL=https://dl.google.com/android/gki/gki-certified-boot-android12-5.10-"${PATCH_LEVEL}"_r1.zip
|
||||
FALLBACK_URL=https://dl.google.com/android/gki/gki-certified-boot-android12-5.10-2023-01_r1.zip
|
||||
status=$(curl -sL -w "%{http_code}" "$GKI_URL" -o /dev/null)
|
||||
if [ "$status" = "200" ]; then
|
||||
curl -Lo gki-kernel.zip "$GKI_URL"
|
||||
else
|
||||
echo "[+] $GKI_URL not found, using $FALLBACK_URL"
|
||||
curl -Lo gki-kernel.zip "$FALLBACK_URL"
|
||||
fi
|
||||
unzip gki-kernel.zip && rm gki-kernel.zip
|
||||
|
||||
echo '[+] Unpack prebuilt boot.img'
|
||||
BOOT_IMG=$(find . -maxdepth 1 -name "boot*.img")
|
||||
$UNPACK_BOOTIMG --boot_img="$BOOT_IMG"
|
||||
rm "$BOOT_IMG"
|
||||
|
||||
echo '[+] Building Image.gz'
|
||||
$GZIP -n -k -f -9 Image >Image.gz
|
||||
|
||||
echo '[+] Building boot.img'
|
||||
$MKBOOTIMG --header_version 4 --kernel Image --output boot.img --ramdisk out/ramdisk --os_version 12.0.0 --os_patch_level "${PATCH_LEVEL}"
|
||||
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
||||
|
||||
echo '[+] Building boot-gz.img'
|
||||
$MKBOOTIMG --header_version 4 --kernel Image.gz --output boot-gz.img --ramdisk out/ramdisk --os_version 12.0.0 --os_patch_level "${PATCH_LEVEL}"
|
||||
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot-gz.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
||||
|
||||
echo '[+] Building boot-lz4.img'
|
||||
$MKBOOTIMG --header_version 4 --kernel Image.lz4 --output boot-lz4.img --ramdisk out/ramdisk --os_version 12.0.0 --os_patch_level "${PATCH_LEVEL}"
|
||||
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot-lz4.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
||||
|
||||
echo '[+] Compress images'
|
||||
for image in boot*.img; do
|
||||
$GZIP -n -f -9 "$image"
|
||||
mv "$image".gz "${1//Image-/}"-"$image".gz
|
||||
done
|
||||
|
||||
echo "[+] Images to upload"
|
||||
find . -type f -name "*.gz"
|
||||
|
||||
# find . -type f -name "*.gz" -exec python3 "$GITHUB_WORKSPACE"/KernelSU-Next/scripts/ksunextbot.py {} +
|
||||
}
|
||||
|
||||
for dir in Image*; do
|
||||
if [ -d "$dir" ]; then
|
||||
echo "----- Building $dir -----"
|
||||
cd "$dir"
|
||||
build_from_image "$dir"
|
||||
cd ..
|
||||
fi
|
||||
done
|
||||
43
.github/scripts/build_a13.sh
vendored
43
.github/scripts/build_a13.sh
vendored
@@ -1,43 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
build_from_image() {
|
||||
export TITLE
|
||||
TITLE=kernel-aarch64-${1//Image-/}
|
||||
|
||||
echo "[+] title: $TITLE"
|
||||
echo '[+] Building Image.gz'
|
||||
$GZIP -n -k -f -9 Image >Image.gz
|
||||
|
||||
echo '[+] Building boot.img'
|
||||
$MKBOOTIMG --header_version 4 --kernel Image --output boot.img
|
||||
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
||||
|
||||
echo '[+] Building boot-gz.img'
|
||||
$MKBOOTIMG --header_version 4 --kernel Image.gz --output boot-gz.img
|
||||
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot-gz.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
||||
|
||||
echo '[+] Building boot-lz4.img'
|
||||
$MKBOOTIMG --header_version 4 --kernel Image.lz4 --output boot-lz4.img
|
||||
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot-lz4.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
||||
|
||||
echo '[+] Compress images'
|
||||
for image in boot*.img; do
|
||||
$GZIP -n -f -9 "$image"
|
||||
mv "$image".gz "${1//Image-/}"-"$image".gz
|
||||
done
|
||||
|
||||
echo '[+] Images to upload'
|
||||
find . -type f -name "*.gz"
|
||||
|
||||
# find . -type f -name "*.gz" -exec python3 "$GITHUB_WORKSPACE"/KernelSU-Next/scripts/ksunextbot.py {} +
|
||||
}
|
||||
|
||||
for dir in Image*; do
|
||||
if [ -d "$dir" ]; then
|
||||
echo "----- Building $dir -----"
|
||||
cd "$dir"
|
||||
build_from_image "$dir"
|
||||
cd ..
|
||||
fi
|
||||
done
|
||||
137
.github/workflows/avd-kernel.yml
vendored
137
.github/workflows/avd-kernel.yml
vendored
@@ -1,137 +0,0 @@
|
||||
name: GKI Kernel Build
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
version_name:
|
||||
required: true
|
||||
type: string
|
||||
description: >
|
||||
With SUBLEVEL of kernel,
|
||||
for example: android12-5.10.66
|
||||
arch:
|
||||
required: true
|
||||
type: string
|
||||
description: >
|
||||
Build arch: aarch64/x86_64
|
||||
debug:
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
manifest_name:
|
||||
required: false
|
||||
type: string
|
||||
description: >
|
||||
Local repo manifest xml path,
|
||||
typically for AVD kernel build.
|
||||
secrets:
|
||||
BOOT_SIGN_KEY:
|
||||
required: false
|
||||
CHAT_ID:
|
||||
required: false
|
||||
BOT_TOKEN:
|
||||
required: false
|
||||
MESSAGE_THREAD_ID:
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build ${{ inputs.version_name }}
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Maximize build space
|
||||
uses: easimon/maximize-build-space@master
|
||||
with:
|
||||
root-reserve-mb: 8192
|
||||
temp-reserve-mb: 2048
|
||||
remove-dotnet: 'true'
|
||||
remove-android: 'true'
|
||||
remove-haskell: 'true'
|
||||
remove-codeql: 'true'
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
path: KernelSU-Next
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup need_upload
|
||||
id: need_upload
|
||||
run: |
|
||||
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
||||
echo "UPLOAD=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "UPLOAD=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Setup kernel source
|
||||
run: |
|
||||
echo "Free space:"
|
||||
df -h
|
||||
cd $GITHUB_WORKSPACE
|
||||
sudo apt-get install repo -y
|
||||
mkdir android-kernel && cd android-kernel
|
||||
repo init --depth=1 -u https://android.googlesource.com/kernel/manifest -m "$GITHUB_WORKSPACE/KernelSU-Next/.github/manifests/${{ inputs.manifest_name }}" --repo-rev=v2.16
|
||||
repo --version
|
||||
repo --trace sync -c -j$(nproc --all) --no-tags
|
||||
df -h
|
||||
|
||||
- name: Setup KernelSU-Next
|
||||
env:
|
||||
PATCH_PATH: ${{ inputs.patch_path }}
|
||||
IS_DEBUG_KERNEL: ${{ inputs.debug }}
|
||||
run: |
|
||||
cd $GITHUB_WORKSPACE/android-kernel
|
||||
echo "[+] KernelSU-Next setup"
|
||||
GKI_ROOT=$(pwd)
|
||||
echo "[+] GKI_ROOT: $GKI_ROOT"
|
||||
echo "[+] Copy KernelSU-Next driver to $GKI_ROOT/common/drivers"
|
||||
ln -sf $GITHUB_WORKSPACE/KernelSU-Next/kernel $GKI_ROOT/common/drivers/kernelsu
|
||||
echo "[+] Add KernelSU-Next driver to Makefile"
|
||||
DRIVER_MAKEFILE=$GKI_ROOT/common/drivers/Makefile
|
||||
DRIVER_KCONFIG=$GKI_ROOT/common/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 $GKI_ROOT/common/ && git apply $GITHUB_WORKSPACE/KernelSU-Next/.github/patches/$PATCH_PATH/*.patch || echo "[-] No patch found"
|
||||
|
||||
if [ "$IS_DEBUG_KERNEL" = "true" ]; then
|
||||
echo "[+] Enable debug features for kernel"
|
||||
printf "\nccflags-y += -DCONFIG_KSU_DEBUG\n" >> $GITHUB_WORKSPACE/KernelSU-Next/kernel/Makefile
|
||||
fi
|
||||
repo status
|
||||
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: Make working directory clean to avoid dirty
|
||||
working-directory: android-kernel
|
||||
run: |
|
||||
rm common/android/abi_gki_protected_exports_* || echo "No protected exports!"
|
||||
git config --global user.email "bot@kernelsu.org"
|
||||
git config --global user.name "KernelSU-NextBot"
|
||||
cd common/ && git add -A && git commit -a -m "Add KernelSU-Next"
|
||||
repo status
|
||||
|
||||
- name: Build kernel
|
||||
working-directory: android-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
|
||||
tools/bazel run --config=fast --config=stamp --lto=thin //common-modules/virtual-device:virtual_device_${{ inputs.arch }}_dist -- --dist_dir=dist
|
||||
NAME=kernel-${{ inputs.arch }}-avd-${{ inputs.version_name }}-${{ env.kernelsu_version }}
|
||||
TARGET_IMAGE=dist/bzImage
|
||||
if [ ! -e $TARGET_IMAGE ]; then
|
||||
TARGET_IMAGE=dist/Image
|
||||
fi
|
||||
mv $TARGET_IMAGE $NAME
|
||||
echo "file_path=android-kernel/$NAME" >> $GITHUB_ENV
|
||||
|
||||
- name: Upload Kernel
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: kernel-${{ inputs.arch }}-avd-${{ inputs.version_name }}-${{ env.kernelsu_version }}
|
||||
path: "${{ env.file_path }}"
|
||||
62
.github/workflows/build-debug-kernel.yml
vendored
62
.github/workflows/build-debug-kernel.yml
vendored
@@ -1,62 +0,0 @@
|
||||
name: Build debug kernel
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-debug-kernel-a12:
|
||||
uses: ./.github/workflows/gki-kernel.yml
|
||||
with:
|
||||
version: android12-5.10
|
||||
version_name: android12-5.10.236
|
||||
tag: android12-5.10-2025-05
|
||||
os_patch_level: 2025-05
|
||||
patch_path: "5.10"
|
||||
debug: true
|
||||
build-debug-kernel-a13:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- version: "5.10"
|
||||
sub_level: 236
|
||||
os_patch_level: 2025-05
|
||||
- version: "5.15"
|
||||
sub_level: 180
|
||||
os_patch_level: 2025-05
|
||||
uses: ./.github/workflows/gki-kernel.yml
|
||||
with:
|
||||
version: android13-${{ matrix.version }}
|
||||
version_name: android13-${{ matrix.version }}.${{ matrix.sub_level }}
|
||||
tag: android13-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
||||
patch_path: ${{ matrix.version }}
|
||||
debug: true
|
||||
build-debug-kernel-a14:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- version: "5.15"
|
||||
sub_level: 180
|
||||
os_patch_level: 2025-05
|
||||
- version: "6.1"
|
||||
sub_level: 138
|
||||
os_patch_level: 2025-06
|
||||
uses: ./.github/workflows/gki-kernel.yml
|
||||
with:
|
||||
version: android14-${{ matrix.version }}
|
||||
version_name: android14-${{ matrix.version }}.${{ matrix.sub_level }}
|
||||
tag: android14-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
||||
patch_path: ${{ matrix.version }}
|
||||
debug: true
|
||||
build-debug-kernel-a15:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- version: "6.6"
|
||||
sub_level: 89
|
||||
os_patch_level: 2025-06
|
||||
uses: ./.github/workflows/gki-kernel.yml
|
||||
with:
|
||||
version: android15-${{ matrix.version }}
|
||||
version_name: android15-${{ matrix.version }}.${{ matrix.sub_level }}
|
||||
tag: android15-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
||||
patch_path: ${{ matrix.version }}
|
||||
debug: true
|
||||
120
.github/workflows/build-kernel-a12.yml
vendored
120
.github/workflows/build-kernel-a12.yml
vendored
@@ -1,120 +0,0 @@
|
||||
name: Build Kernel - Android 12
|
||||
on:
|
||||
push:
|
||||
branches: [ "next" ]
|
||||
paths:
|
||||
- ".github/workflows/build-kernel-a12.yml"
|
||||
- ".github/workflows/gki-kernel.yml"
|
||||
- ".github/scripts/build_a12.sh"
|
||||
- "kernel/**"
|
||||
pull_request:
|
||||
branches: [ "next" ]
|
||||
paths:
|
||||
- ".github/workflows/build-kernel-a12.yml"
|
||||
- ".github/workflows/gki-kernel.yml"
|
||||
- ".github/scripts/build-a12.sh"
|
||||
- "kernel/**"
|
||||
workflow_call:
|
||||
jobs:
|
||||
build-kernel:
|
||||
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/next'
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- 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:
|
||||
version: android12-5.10
|
||||
version_name: android12-5.10.${{ matrix.sub_level }}
|
||||
tag: android12-5.10-${{ matrix.os_patch_level }}
|
||||
os_patch_level: ${{ matrix.os_patch_level }}
|
||||
patch_path: "5.10"
|
||||
|
||||
upload-artifacts:
|
||||
needs: build-kernel
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/next' ) || github.ref_type == 'tag' || github.ref == 'refs/heads/next' }}
|
||||
env:
|
||||
CHAT_ID: ${{ secrets.CHAT_ID }}
|
||||
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||
COMMIT_URL: ${{ github.event.head_commit.url }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
path: KernelSU-Next
|
||||
fetch-depth: 0
|
||||
|
||||
- name: List artifacts
|
||||
run: |
|
||||
tree
|
||||
|
||||
- name: Download prebuilt toolchain
|
||||
run: |
|
||||
AOSP_MIRROR=https://android.googlesource.com
|
||||
BRANCH=main-kernel-build-2024
|
||||
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
|
||||
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
|
||||
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
|
||||
pip3 install telethon
|
||||
|
||||
- name: Set boot sign key
|
||||
env:
|
||||
BOOT_SIGN_KEY: ${{ secrets.BOOT_SIGN_KEY }}
|
||||
run: |
|
||||
if [ ! -z "$BOOT_SIGN_KEY" ]; then
|
||||
echo "$BOOT_SIGN_KEY" > ./kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
||||
fi
|
||||
|
||||
- name: Bot session cache
|
||||
id: bot_session_cache
|
||||
uses: actions/cache@v4
|
||||
if: false
|
||||
with:
|
||||
path: scripts/ksunextbot.session
|
||||
key: ${{ runner.os }}-bot-session
|
||||
|
||||
- name: Build boot images
|
||||
run: |
|
||||
export AVBTOOL=$GITHUB_WORKSPACE/kernel-build-tools/linux-x86/bin/avbtool
|
||||
export GZIP=$GITHUB_WORKSPACE/build-tools/path/linux-x86/gzip
|
||||
export LZ4=$GITHUB_WORKSPACE/build-tools/path/linux-x86/lz4
|
||||
export MKBOOTIMG=$GITHUB_WORKSPACE/mkbootimg/mkbootimg.py
|
||||
export UNPACK_BOOTIMG=$GITHUB_WORKSPACE/mkbootimg/unpack_bootimg.py
|
||||
cd $GITHUB_WORKSPACE/KernelSU-Next
|
||||
export VERSION=$(($(git rev-list --count HEAD) + 10200))
|
||||
echo "VERSION: $VERSION"
|
||||
cd -
|
||||
bash $GITHUB_WORKSPACE/KernelSU-Next/.github/scripts/build_a12.sh
|
||||
|
||||
- name: Display structure of boot files
|
||||
run: ls -R
|
||||
|
||||
- name: Upload images artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: boot-images-android12
|
||||
path: Image-android12*/*.img.gz
|
||||
|
||||
check-build-kernel:
|
||||
if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/next'
|
||||
uses: ./.github/workflows/gki-kernel.yml
|
||||
with:
|
||||
version: android12-5.10
|
||||
version_name: android12-5.10.236
|
||||
tag: android12-5.10-2025-05
|
||||
os_patch_level: 2025-05
|
||||
patch_path: "5.10"
|
||||
163
.github/workflows/build-kernel-a13.yml
vendored
163
.github/workflows/build-kernel-a13.yml
vendored
@@ -1,163 +0,0 @@
|
||||
name: Build Kernel - Android 13
|
||||
on:
|
||||
push:
|
||||
branches: [ "next" ]
|
||||
paths:
|
||||
- ".github/workflows/build-kernel-a13.yml"
|
||||
- ".github/workflows/gki-kernel.yml"
|
||||
- ".github/scripts/build_a13.sh"
|
||||
- "kernel/**"
|
||||
pull_request:
|
||||
branches: [ "next" ]
|
||||
paths:
|
||||
- ".github/workflows/build-kernel-a13.yml"
|
||||
- ".github/workflows/gki-kernel.yml"
|
||||
- ".github/scripts/build-a13.sh"
|
||||
- "kernel/**"
|
||||
workflow_call:
|
||||
jobs:
|
||||
build-kernel:
|
||||
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/next'
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- version: "5.10"
|
||||
sub_level: 210
|
||||
os_patch_level: 2024-06
|
||||
- version: "5.10"
|
||||
sub_level: 214
|
||||
os_patch_level: 2024-07
|
||||
- version: "5.10"
|
||||
sub_level: 218
|
||||
os_patch_level: 2024-08
|
||||
- version: "5.10"
|
||||
sub_level: 223
|
||||
os_patch_level: 2024-11
|
||||
- version: "5.10"
|
||||
sub_level: 228
|
||||
os_patch_level: 2025-01
|
||||
- version: "5.10"
|
||||
sub_level: 234
|
||||
os_patch_level: 2025-03
|
||||
- version: "5.10"
|
||||
sub_level: 236
|
||||
os_patch_level: 2025-05
|
||||
- version: "5.15"
|
||||
sub_level: 149
|
||||
os_patch_level: 2024-07
|
||||
- version: "5.15"
|
||||
sub_level: 151
|
||||
os_patch_level: 2024-08
|
||||
- version: "5.15"
|
||||
sub_level: 153
|
||||
os_patch_level: 2024-09
|
||||
- version: "5.15"
|
||||
sub_level: 167
|
||||
os_patch_level: 2024-11
|
||||
- version: "5.15"
|
||||
sub_level: 170
|
||||
os_patch_level: 2025-01
|
||||
- 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:
|
||||
version: android13-${{ matrix.version }}
|
||||
version_name: android13-${{ matrix.version }}.${{ matrix.sub_level }}
|
||||
tag: android13-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
||||
os_patch_level: ${{ matrix.os_patch_level }}
|
||||
patch_path: ${{ matrix.version }}
|
||||
|
||||
upload-artifacts:
|
||||
needs: build-kernel
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/next' ) || github.ref_type == 'tag' || github.ref == 'refs/heads/next' }}
|
||||
env:
|
||||
CHAT_ID: ${{ secrets.CHAT_ID }}
|
||||
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||
COMMIT_URL: ${{ github.event.head_commit.url }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
path: KernelSU-Next
|
||||
fetch-depth: 0
|
||||
|
||||
- name: List artifacts
|
||||
run: |
|
||||
tree
|
||||
|
||||
- name: Download prebuilt toolchain
|
||||
run: |
|
||||
AOSP_MIRROR=https://android.googlesource.com
|
||||
BRANCH=main-kernel-build-2024
|
||||
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
|
||||
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
|
||||
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
|
||||
pip3 install telethon
|
||||
|
||||
- name: Set boot sign key
|
||||
env:
|
||||
BOOT_SIGN_KEY: ${{ secrets.BOOT_SIGN_KEY }}
|
||||
run: |
|
||||
if [ ! -z "$BOOT_SIGN_KEY" ]; then
|
||||
echo "$BOOT_SIGN_KEY" > ./kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
||||
fi
|
||||
|
||||
- name: Bot session cache
|
||||
id: bot_session_cache
|
||||
uses: actions/cache@v4
|
||||
if: false
|
||||
with:
|
||||
path: scripts/ksunextbot.session
|
||||
key: ${{ runner.os }}-bot-session
|
||||
|
||||
- name: Build boot images
|
||||
run: |
|
||||
export AVBTOOL=$GITHUB_WORKSPACE/kernel-build-tools/linux-x86/bin/avbtool
|
||||
export GZIP=$GITHUB_WORKSPACE/build-tools/path/linux-x86/gzip
|
||||
export LZ4=$GITHUB_WORKSPACE/build-tools/path/linux-x86/lz4
|
||||
export MKBOOTIMG=$GITHUB_WORKSPACE/mkbootimg/mkbootimg.py
|
||||
export UNPACK_BOOTIMG=$GITHUB_WORKSPACE/mkbootimg/unpack_bootimg.py
|
||||
cd $GITHUB_WORKSPACE/KernelSU-Next
|
||||
export VERSION=$(($(git rev-list --count HEAD) + 10200))
|
||||
echo "VERSION: $VERSION"
|
||||
cd -
|
||||
bash $GITHUB_WORKSPACE/KernelSU-Next/.github/scripts/build_a13.sh
|
||||
|
||||
- name: Display structure of boot files
|
||||
run: ls -R
|
||||
|
||||
- name: Upload images artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: boot-images-android13
|
||||
path: Image-android13*/*.img.gz
|
||||
|
||||
check-build-kernel:
|
||||
if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/next'
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- version: "5.10"
|
||||
sub_level: 236
|
||||
os_patch_level: 2025-05
|
||||
- version: "5.15"
|
||||
sub_level: 180
|
||||
os_patch_level: 2025-05
|
||||
uses: ./.github/workflows/gki-kernel.yml
|
||||
with:
|
||||
version: android13-${{ matrix.version }}
|
||||
version_name: android13-${{ matrix.version }}.${{ matrix.sub_level }}
|
||||
tag: android13-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
||||
os_patch_level: ${{ matrix.os_patch_level }}
|
||||
patch_path: ${{ matrix.version }}
|
||||
184
.github/workflows/build-kernel-a14.yml
vendored
184
.github/workflows/build-kernel-a14.yml
vendored
@@ -1,184 +0,0 @@
|
||||
name: Build Kernel - Android 14
|
||||
on:
|
||||
push:
|
||||
branches: [ "next" ]
|
||||
paths:
|
||||
- ".github/workflows/build-kernel-a14.yml"
|
||||
- ".github/workflows/gki-kernel.yml"
|
||||
- ".github/scripts/build_a13.sh"
|
||||
- "kernel/**"
|
||||
pull_request:
|
||||
branches: [ "next" ]
|
||||
paths:
|
||||
- ".github/workflows/build-kernel-a14.yml"
|
||||
- ".github/workflows/gki-kernel.yml"
|
||||
- ".github/scripts/build-a13.sh"
|
||||
- "kernel/**"
|
||||
workflow_call:
|
||||
jobs:
|
||||
build-kernel:
|
||||
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/next'
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- version: "5.15"
|
||||
sub_level: 149
|
||||
os_patch_level: 2024-06
|
||||
- version: "5.15"
|
||||
sub_level: 153
|
||||
os_patch_level: 2024-07
|
||||
- version: "5.15"
|
||||
sub_level: 158
|
||||
os_patch_level: 2024-08
|
||||
- version: "5.15"
|
||||
sub_level: 164
|
||||
os_patch_level: 2024-09
|
||||
- version: "5.15"
|
||||
sub_level: 167
|
||||
os_patch_level: 2024-11
|
||||
- version: "5.15"
|
||||
sub_level: 170
|
||||
os_patch_level: 2025-01
|
||||
- version: "5.15"
|
||||
sub_level: 178
|
||||
os_patch_level: 2025-03
|
||||
- version: "5.15"
|
||||
sub_level: 180
|
||||
os_patch_level: 2025-05
|
||||
- version: "6.1"
|
||||
sub_level: 78
|
||||
os_patch_level: 2024-06
|
||||
- version: "6.1"
|
||||
sub_level: 84
|
||||
os_patch_level: 2024-07
|
||||
- version: "6.1"
|
||||
sub_level: 90
|
||||
os_patch_level: 2024-08
|
||||
- version: "6.1"
|
||||
sub_level: 93
|
||||
os_patch_level: 2024-09
|
||||
- version: "6.1"
|
||||
sub_level: 99
|
||||
os_patch_level: 2024-10
|
||||
- version: "6.1"
|
||||
sub_level: 112
|
||||
os_patch_level: 2024-11
|
||||
- version: "6.1"
|
||||
sub_level: 115
|
||||
os_patch_level: 2024-12
|
||||
- version: "6.1"
|
||||
sub_level: 118
|
||||
os_patch_level: 2025-01
|
||||
- version: "6.1"
|
||||
sub_level: 124
|
||||
os_patch_level: 2025-02
|
||||
- version: "6.1"
|
||||
sub_level: 128
|
||||
os_patch_level: 2025-03
|
||||
- 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:
|
||||
version: android14-${{ matrix.version }}
|
||||
version_name: android14-${{ matrix.version }}.${{ matrix.sub_level }}
|
||||
tag: android14-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
||||
os_patch_level: ${{ matrix.os_patch_level }}
|
||||
patch_path: ${{ matrix.version }}
|
||||
|
||||
upload-artifacts:
|
||||
needs: build-kernel
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/next' ) || github.ref_type == 'tag' || github.ref == 'refs/heads/next' }}
|
||||
env:
|
||||
CHAT_ID: ${{ secrets.CHAT_ID }}
|
||||
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||
COMMIT_URL: ${{ github.event.head_commit.url }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
path: KernelSU-Next
|
||||
fetch-depth: 0
|
||||
|
||||
- name: List artifacts
|
||||
run: |
|
||||
tree
|
||||
|
||||
- name: Download prebuilt toolchain
|
||||
run: |
|
||||
AOSP_MIRROR=https://android.googlesource.com
|
||||
BRANCH=main-kernel-build-2024
|
||||
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
|
||||
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
|
||||
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
|
||||
pip3 install telethon
|
||||
|
||||
- name: Set boot sign key
|
||||
env:
|
||||
BOOT_SIGN_KEY: ${{ secrets.BOOT_SIGN_KEY }}
|
||||
run: |
|
||||
if [ ! -z "$BOOT_SIGN_KEY" ]; then
|
||||
echo "$BOOT_SIGN_KEY" > ./kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
||||
fi
|
||||
|
||||
- name: Bot session cache
|
||||
id: bot_session_cache
|
||||
uses: actions/cache@v4
|
||||
if: false
|
||||
with:
|
||||
path: scripts/ksunextbot.session
|
||||
key: ${{ runner.os }}-bot-session
|
||||
|
||||
- name: Build boot images
|
||||
run: |
|
||||
export AVBTOOL=$GITHUB_WORKSPACE/kernel-build-tools/linux-x86/bin/avbtool
|
||||
export GZIP=$GITHUB_WORKSPACE/build-tools/path/linux-x86/gzip
|
||||
export LZ4=$GITHUB_WORKSPACE/build-tools/path/linux-x86/lz4
|
||||
export MKBOOTIMG=$GITHUB_WORKSPACE/mkbootimg/mkbootimg.py
|
||||
export UNPACK_BOOTIMG=$GITHUB_WORKSPACE/mkbootimg/unpack_bootimg.py
|
||||
cd $GITHUB_WORKSPACE/KernelSU-Next
|
||||
export VERSION=$(($(git rev-list --count HEAD) + 10200))
|
||||
echo "VERSION: $VERSION"
|
||||
cd -
|
||||
bash $GITHUB_WORKSPACE/KernelSU-Next/.github/scripts/build_a13.sh
|
||||
|
||||
- name: Display structure of boot files
|
||||
run: ls -R
|
||||
|
||||
- name: Upload images artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: boot-images-android14
|
||||
path: Image-android14*/*.img.gz
|
||||
|
||||
check-build-kernel:
|
||||
if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/next'
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- version: "5.15"
|
||||
sub_level: 180
|
||||
os_patch_level: 2025-05
|
||||
- version: "6.1"
|
||||
sub_level: 138
|
||||
os_patch_level: 2025-06
|
||||
uses: ./.github/workflows/gki-kernel.yml
|
||||
with:
|
||||
version: android14-${{ matrix.version }}
|
||||
version_name: android14-${{ matrix.version }}.${{ matrix.sub_level }}
|
||||
tag: android14-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
||||
os_patch_level: ${{ matrix.os_patch_level }}
|
||||
patch_path: ${{ matrix.version }}
|
||||
151
.github/workflows/build-kernel-a15.yml
vendored
151
.github/workflows/build-kernel-a15.yml
vendored
@@ -1,151 +0,0 @@
|
||||
name: Build Kernel - Android 15
|
||||
on:
|
||||
push:
|
||||
branches: [ "next" ]
|
||||
paths:
|
||||
- ".github/workflows/build-kernel-a15.yml"
|
||||
- ".github/workflows/gki-kernel.yml"
|
||||
- ".github/scripts/build_a13.sh"
|
||||
- "kernel/**"
|
||||
pull_request:
|
||||
branches: [ "next" ]
|
||||
paths:
|
||||
- ".github/workflows/build-kernel-a15.yml"
|
||||
- ".github/workflows/gki-kernel.yml"
|
||||
- ".github/scripts/build-a13.sh"
|
||||
- "kernel/**"
|
||||
workflow_call:
|
||||
jobs:
|
||||
build-kernel:
|
||||
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/next'
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- version: "6.6"
|
||||
sub_level: 30
|
||||
os_patch_level: 2024-08
|
||||
- version: "6.6"
|
||||
sub_level: 46
|
||||
os_patch_level: 2024-09
|
||||
- version: "6.6"
|
||||
sub_level: 50
|
||||
os_patch_level: 2024-10
|
||||
- version: "6.6"
|
||||
sub_level: 56
|
||||
os_patch_level: 2024-11
|
||||
- version: "6.6"
|
||||
sub_level: 57
|
||||
os_patch_level: 2024-12
|
||||
- version: "6.6"
|
||||
sub_level: 58
|
||||
os_patch_level: 2025-01
|
||||
- version: "6.6"
|
||||
sub_level: 66
|
||||
os_patch_level: 2025-02
|
||||
- version: "6.6"
|
||||
sub_level: 77
|
||||
os_patch_level: 2025-03
|
||||
- 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:
|
||||
version: android15-${{ matrix.version }}
|
||||
version_name: android15-${{ matrix.version }}.${{ matrix.sub_level }}
|
||||
tag: android15-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
||||
os_patch_level: ${{ matrix.os_patch_level }}
|
||||
patch_path: ${{ matrix.version }}
|
||||
|
||||
upload-artifacts:
|
||||
needs: build-kernel
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/next' ) || github.ref_type == 'tag' || github.ref == 'refs/heads/next' }}
|
||||
env:
|
||||
CHAT_ID: ${{ secrets.CHAT_ID }}
|
||||
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||
COMMIT_URL: ${{ github.event.head_commit.url }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
path: KernelSU-Next
|
||||
fetch-depth: 0
|
||||
|
||||
- name: List artifacts
|
||||
run: |
|
||||
tree
|
||||
|
||||
- name: Download prebuilt toolchain
|
||||
run: |
|
||||
AOSP_MIRROR=https://android.googlesource.com
|
||||
BRANCH=main-kernel-build-2024
|
||||
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
|
||||
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
|
||||
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
|
||||
pip3 install telethon
|
||||
|
||||
- name: Set boot sign key
|
||||
env:
|
||||
BOOT_SIGN_KEY: ${{ secrets.BOOT_SIGN_KEY }}
|
||||
run: |
|
||||
if [ ! -z "$BOOT_SIGN_KEY" ]; then
|
||||
echo "$BOOT_SIGN_KEY" > ./kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
||||
fi
|
||||
|
||||
- name: Bot session cache
|
||||
id: bot_session_cache
|
||||
uses: actions/cache@v4
|
||||
if: false
|
||||
with:
|
||||
path: scripts/ksunextbot.session
|
||||
key: ${{ runner.os }}-bot-session
|
||||
|
||||
- name: Build boot images
|
||||
run: |
|
||||
export AVBTOOL=$GITHUB_WORKSPACE/kernel-build-tools/linux-x86/bin/avbtool
|
||||
export GZIP=$GITHUB_WORKSPACE/build-tools/path/linux-x86/gzip
|
||||
export LZ4=$GITHUB_WORKSPACE/build-tools/path/linux-x86/lz4
|
||||
export MKBOOTIMG=$GITHUB_WORKSPACE/mkbootimg/mkbootimg.py
|
||||
export UNPACK_BOOTIMG=$GITHUB_WORKSPACE/mkbootimg/unpack_bootimg.py
|
||||
cd $GITHUB_WORKSPACE/KernelSU-Next
|
||||
export VERSION=$(($(git rev-list --count HEAD) + 10200))
|
||||
echo "VERSION: $VERSION"
|
||||
cd -
|
||||
bash $GITHUB_WORKSPACE/KernelSU-Next/.github/scripts/build_a13.sh
|
||||
|
||||
- name: Display structure of boot files
|
||||
run: ls -R
|
||||
|
||||
- name: Upload images artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: boot-images-android15
|
||||
path: Image-android15*/*.img.gz
|
||||
|
||||
check-build-kernel:
|
||||
if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/next'
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- version: "6.6"
|
||||
sub_level: 89
|
||||
os_patch_level: 2025-06
|
||||
uses: ./.github/workflows/gki-kernel.yml
|
||||
with:
|
||||
version: android15-${{ matrix.version }}
|
||||
version_name: android15-${{ matrix.version }}.${{ matrix.sub_level }}
|
||||
tag: android15-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
||||
os_patch_level: ${{ matrix.os_patch_level }}
|
||||
patch_path: ${{ matrix.version }}
|
||||
137
.github/workflows/build-kernel-arcvm.yml
vendored
137
.github/workflows/build-kernel-arcvm.yml
vendored
@@ -1,137 +0,0 @@
|
||||
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
39
.github/workflows/build-kernel-avd.yml
vendored
@@ -1,39 +0,0 @@
|
||||
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
38
.github/workflows/build-kernel-wsa.yml
vendored
@@ -1,38 +0,0 @@
|
||||
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"
|
||||
41
.github/workflows/build-lkm.yml
vendored
41
.github/workflows/build-lkm.yml
vendored
@@ -1,41 +0,0 @@
|
||||
name: Build LKM for KernelSU-Next
|
||||
on:
|
||||
push:
|
||||
branches: [ "next" ]
|
||||
paths:
|
||||
- ".github/workflows/build-lkm.yml"
|
||||
pull_request:
|
||||
branches: [ "next" ]
|
||||
paths:
|
||||
- ".github/workflows/build-lkm.yml"
|
||||
workflow_call:
|
||||
jobs:
|
||||
build-lkm:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- version: "android12-5.10"
|
||||
sub_level: 236
|
||||
os_patch_level: 2025-05
|
||||
- version: "android13-5.10"
|
||||
sub_level: 236
|
||||
os_patch_level: 2025-05
|
||||
- version: "android13-5.15"
|
||||
sub_level: 180
|
||||
os_patch_level: 2025-05
|
||||
- version: "android14-5.15"
|
||||
sub_level: 180
|
||||
os_patch_level: 2025-05
|
||||
- version: "android14-6.1"
|
||||
sub_level: 138
|
||||
os_patch_level: 2025-06
|
||||
- version: "android15-6.6"
|
||||
sub_level: 89
|
||||
os_patch_level: 2025-06
|
||||
uses: ./.github/workflows/gki-kernel.yml
|
||||
with:
|
||||
version: ${{ matrix.version }}
|
||||
version_name: ${{ matrix.version }}.${{ matrix.sub_level }}
|
||||
tag: ${{ matrix.version }}-${{ matrix.os_patch_level }}
|
||||
os_patch_level: ${{ matrix.os_patch_level }}
|
||||
build_lkm: true
|
||||
227
.github/workflows/build-manager-ci.yml
vendored
227
.github/workflows/build-manager-ci.yml
vendored
@@ -1,227 +0,0 @@
|
||||
name: Build Manager CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "next" ]
|
||||
paths:
|
||||
- '.github/workflows/build-manager-ci.yml'
|
||||
- 'manager/**'
|
||||
- 'kernel/**'
|
||||
- 'userspace/ksud_overlayfs**'
|
||||
- 'userspace/ksud_magic/**'
|
||||
- 'userspace/susfsd/**'
|
||||
pull_request:
|
||||
branches: [ "next" ]
|
||||
paths:
|
||||
- '.github/workflows/build-manager-ci.yml'
|
||||
- 'manager/**'
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-lkm:
|
||||
uses: ./.github/workflows/build-lkm.yml
|
||||
secrets: inherit
|
||||
|
||||
build-susfsd:
|
||||
needs: build-lkm
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
uses: ./.github/workflows/susfsd.yml
|
||||
with:
|
||||
os: ${{ matrix.os }}
|
||||
|
||||
build-ksud:
|
||||
needs: build-susfsd
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- target: aarch64-linux-android
|
||||
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 }}
|
||||
os: ${{ matrix.os }}
|
||||
|
||||
build-manager:
|
||||
needs: build-ksud
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./manager
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup need_upload
|
||||
id: need_upload
|
||||
run: |
|
||||
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
||||
echo "UPLOAD=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "UPLOAD=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Write Key
|
||||
run: |
|
||||
if [ ! -z "${{ secrets.KEYSTORE }}" ]; then
|
||||
{
|
||||
echo KEYSTORE_PASSWORD='${{ secrets.KEYSTORE_PASSWORD }}'
|
||||
echo KEY_ALIAS='${{ secrets.KEY_ALIAS }}'
|
||||
echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}'
|
||||
echo KEYSTORE_FILE='key.jks'
|
||||
} >> gradle.properties
|
||||
echo ${{ secrets.KEYSTORE }} | base64 -d > key.jks
|
||||
fi
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 21
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Download susfsd
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: susfsd-linux-android
|
||||
path: .
|
||||
|
||||
- name: Copy susfsd to app jniLibs
|
||||
run: |
|
||||
mkdir -p app/src/main/jniLibs/arm64-v8a
|
||||
cp -f ../arm64-v8a/susfsd ../manager/app/src/main/jniLibs/arm64-v8a/libsusfsd.so
|
||||
|
||||
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:
|
||||
name: ksud_overlayfs-aarch64-linux-android
|
||||
path: ksud_overlayfs
|
||||
|
||||
- name: Download arm ksud_overlayfs
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
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:
|
||||
name: ksud_magic-aarch64-linux-android
|
||||
path: ksud_magic
|
||||
|
||||
- name: Download arm ksud_magic
|
||||
uses: actions/download-artifact@v4
|
||||
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: |
|
||||
{
|
||||
echo 'org.gradle.parallel=true'
|
||||
echo 'org.gradle.vfs.watch=true'
|
||||
echo 'org.gradle.jvmargs=-Xmx2048m'
|
||||
echo 'android.native.buildOutput=verbose'
|
||||
} >> gradle.properties
|
||||
sed -i 's/org.gradle.configuration-cache=true//g' gradle.properties
|
||||
chmod +x gradlew
|
||||
./gradlew clean assembleRelease
|
||||
|
||||
- name: Upload Build Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Manager
|
||||
path: manager/app/build/outputs/apk/release/*.apk
|
||||
|
||||
- name: Upload Mappings
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Mappings
|
||||
path: manager/app/build/outputs/mapping/release/
|
||||
|
||||
- name: Bot Session Cache
|
||||
if: steps.need_upload.outputs.UPLOAD == 'true'
|
||||
id: bot_session_cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: scripts/ksunextbot.session
|
||||
key: ${{ runner.os }}-bot-session
|
||||
|
||||
- name: Upload to Telegram
|
||||
if: steps.need_upload.outputs.UPLOAD == 'true'
|
||||
env:
|
||||
API_ID: ${{ secrets.API_ID }}
|
||||
API_HASH: ${{ secrets.API_HASH }}
|
||||
CHAT_ID: ${{ secrets.CHAT_ID }}
|
||||
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||
COMMIT_URL: ${{ github.event.head_commit.url }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
TITLE: CI Manager (TEST BUILD)
|
||||
run: |
|
||||
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
||||
export VERSION=$(git rev-list --count HEAD)
|
||||
APK=$(find ./app/build/outputs/apk/release -name "*.apk")
|
||||
pip3 install telethon
|
||||
python3 $GITHUB_WORKSPACE/scripts/ksunextbot.py $APK
|
||||
fi
|
||||
222
.github/workflows/build-manager-spoofed.yml
vendored
222
.github/workflows/build-manager-spoofed.yml
vendored
@@ -1,222 +0,0 @@
|
||||
name: Build Manager Spoofed
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "next" ]
|
||||
paths:
|
||||
- '.github/workflows/build-manager-ci.yml'
|
||||
- 'manager/**'
|
||||
- 'kernel/**'
|
||||
- 'userspace/ksud_overlayfs**'
|
||||
- 'userspace/ksud_magic/**'
|
||||
- 'userspace/susfsd/**'
|
||||
pull_request:
|
||||
branches: [ "next" ]
|
||||
paths:
|
||||
- '.github/workflows/build-manager-ci.yml'
|
||||
- 'manager/**'
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 12 * * *" # 6 PM UTC+6 | 12 PM UTC
|
||||
|
||||
jobs:
|
||||
build-lkm:
|
||||
uses: ./.github/workflows/build-lkm.yml
|
||||
secrets: inherit
|
||||
|
||||
build-susfsd:
|
||||
needs: build-lkm
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
uses: ./.github/workflows/susfsd.yml
|
||||
with:
|
||||
os: ${{ matrix.os }}
|
||||
|
||||
build-ksud:
|
||||
needs: build-susfsd
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- target: aarch64-linux-android
|
||||
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 }}
|
||||
os: ${{ matrix.os }}
|
||||
|
||||
build-manager:
|
||||
needs: build-ksud
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./manager
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Spoof Package ID
|
||||
run: |
|
||||
chmod +x spoof
|
||||
./spoof
|
||||
|
||||
- name: Setup need_upload
|
||||
id: need_upload
|
||||
run: |
|
||||
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
||||
echo "UPLOAD=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "UPLOAD=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Write Key
|
||||
run: |
|
||||
if [ ! -z "${{ secrets.KEYSTORE }}" ]; then
|
||||
{
|
||||
echo KEYSTORE_PASSWORD='${{ secrets.KEYSTORE_PASSWORD }}'
|
||||
echo KEY_ALIAS='${{ secrets.KEY_ALIAS }}'
|
||||
echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}'
|
||||
echo KEYSTORE_FILE='key.jks'
|
||||
} >> gradle.properties
|
||||
echo ${{ secrets.KEYSTORE }} | base64 -d > key.jks
|
||||
fi
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 21
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Download susfsd
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: susfsd-linux-android
|
||||
path: .
|
||||
|
||||
- name: Copy susfsd to app jniLibs
|
||||
run: |
|
||||
mkdir -p app/src/main/jniLibs/arm64-v8a
|
||||
cp -f ../arm64-v8a/susfsd ../manager/app/src/main/jniLibs/arm64-v8a/libsusfsd.so
|
||||
|
||||
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:
|
||||
name: ksud_overlayfs-aarch64-linux-android
|
||||
path: ksud_overlayfs
|
||||
|
||||
- name: Download arm ksud_overlayfs
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
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:
|
||||
name: ksud_magic-aarch64-linux-android
|
||||
path: ksud_magic
|
||||
|
||||
- name: Download arm ksud_magic
|
||||
uses: actions/download-artifact@v4
|
||||
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: |
|
||||
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: |
|
||||
{
|
||||
echo 'org.gradle.parallel=true'
|
||||
echo 'org.gradle.vfs.watch=true'
|
||||
echo 'org.gradle.jvmargs=-Xmx2048m'
|
||||
echo 'android.native.buildOutput=verbose'
|
||||
} >> gradle.properties
|
||||
sed -i 's/org.gradle.configuration-cache=true//g' gradle.properties
|
||||
chmod +x gradlew
|
||||
./gradlew clean assembleRelease
|
||||
|
||||
- name: Upload Build Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Manager
|
||||
path: manager/app/build/outputs/apk/release/*.apk
|
||||
|
||||
- name: Upload Mappings
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Mappings
|
||||
path: manager/app/build/outputs/mapping/release/
|
||||
|
||||
- name: Bot Session Cache
|
||||
if: steps.need_upload.outputs.UPLOAD == 'true'
|
||||
id: bot_session_cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: scripts/ksunextbot.session
|
||||
key: ${{ runner.os }}-bot-session
|
||||
|
||||
- name: Upload to Telegram
|
||||
if: steps.need_upload.outputs.UPLOAD == 'true'
|
||||
env:
|
||||
API_ID: ${{ secrets.API_ID }}
|
||||
API_HASH: ${{ secrets.API_HASH }}
|
||||
CHAT_ID: ${{ secrets.CHAT_ID }}
|
||||
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||
COMMIT_URL: ${{ github.event.head_commit.url }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
TITLE: CI Manager (SPOOFED BUILD)
|
||||
run: |
|
||||
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
||||
export VERSION=$(git rev-list --count HEAD)
|
||||
APK=$(find ./app/build/outputs/apk/release -name "*.apk")
|
||||
pip3 install telethon
|
||||
python3 $GITHUB_WORKSPACE/scripts/ksunextbot.py $APK
|
||||
fi
|
||||
215
.github/workflows/build-manager.yml
vendored
215
.github/workflows/build-manager.yml
vendored
@@ -1,215 +0,0 @@
|
||||
name: Build Manager
|
||||
|
||||
on:
|
||||
# push:
|
||||
# branches: [ "next" ]
|
||||
# paths:
|
||||
# - '.github/workflows/build-manager.yml'
|
||||
# - 'manager/**'
|
||||
# - 'kernel/**'
|
||||
# - 'userspace/ksud_overlayfs**'
|
||||
# - 'userspace/ksud_magic/**'
|
||||
# - 'userspace/susfsd/**'
|
||||
# pull_request:
|
||||
# branches: [ "next" ]
|
||||
# paths:
|
||||
# - '.github/workflows/build-manager-ci.yml'
|
||||
# - 'manager/**'
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-lkm:
|
||||
uses: ./.github/workflows/build-lkm.yml
|
||||
secrets: inherit
|
||||
|
||||
build-susfsd:
|
||||
needs: build-lkm
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
uses: ./.github/workflows/susfsd.yml
|
||||
with:
|
||||
os: ${{ matrix.os }}
|
||||
|
||||
build-ksud:
|
||||
needs: build-susfsd
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- target: aarch64-linux-android
|
||||
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 }}
|
||||
os: ${{ matrix.os }}
|
||||
|
||||
build-manager:
|
||||
needs: build-ksud
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./manager
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup need_upload
|
||||
id: need_upload
|
||||
run: |
|
||||
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
||||
echo "UPLOAD=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "UPLOAD=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Write Key
|
||||
run: |
|
||||
if [ ! -z "${{ secrets.KEYSTORE }}" ]; then
|
||||
{
|
||||
echo KEYSTORE_PASSWORD='${{ secrets.KEYSTORE_PASSWORD }}'
|
||||
echo KEY_ALIAS='${{ secrets.KEY_ALIAS }}'
|
||||
echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}'
|
||||
echo KEYSTORE_FILE='key.jks'
|
||||
} >> gradle.properties
|
||||
echo ${{ secrets.KEYSTORE }} | base64 -d > key.jks
|
||||
fi
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 21
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Download susfsd
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: susfsd-linux-android
|
||||
path: .
|
||||
|
||||
- name: Copy susfsd to app jniLibs
|
||||
run: |
|
||||
mkdir -p app/src/main/jniLibs/arm64-v8a
|
||||
cp -f ../arm64-v8a/susfsd ../manager/app/src/main/jniLibs/arm64-v8a/libsusfsd.so
|
||||
|
||||
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:
|
||||
name: ksud_overlayfs-aarch64-linux-android
|
||||
path: ksud_overlayfs
|
||||
|
||||
- name: Download arm ksud_overlayfs
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
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:
|
||||
name: ksud_magic-aarch64-linux-android
|
||||
path: ksud_magic
|
||||
|
||||
- name: Download arm ksud_magic
|
||||
uses: actions/download-artifact@v4
|
||||
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: |
|
||||
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: |
|
||||
{
|
||||
echo 'org.gradle.parallel=true'
|
||||
echo 'org.gradle.vfs.watch=true'
|
||||
echo 'org.gradle.jvmargs=-Xmx2048m'
|
||||
echo 'android.native.buildOutput=verbose'
|
||||
} >> gradle.properties
|
||||
sed -i 's/org.gradle.configuration-cache=true//g' gradle.properties
|
||||
chmod +x gradlew
|
||||
./gradlew clean assembleRelease
|
||||
|
||||
- name: Upload Build Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Manager
|
||||
path: manager/app/build/outputs/apk/release/*.apk
|
||||
|
||||
- name: Upload Mappings
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Mappings
|
||||
path: manager/app/build/outputs/mapping/release/
|
||||
|
||||
- name: Bot Session Cache
|
||||
if: steps.need_upload.outputs.UPLOAD == 'true'
|
||||
id: bot_session_cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: scripts/ksunextbot.session
|
||||
key: ${{ runner.os }}-bot-session
|
||||
|
||||
- name: Upload to Telegram
|
||||
if: steps.need_upload.outputs.UPLOAD == 'true'
|
||||
env:
|
||||
API_ID: ${{ secrets.API_ID }}
|
||||
API_HASH: ${{ secrets.API_HASH }}
|
||||
CHAT_ID: ${{ secrets.CHAT_ID }}
|
||||
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||
COMMIT_URL: ${{ github.event.head_commit.url }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
TITLE: Release Manager (STABLE BUILD)
|
||||
run: |
|
||||
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
||||
export VERSION=$(git rev-list --count HEAD)
|
||||
APK=$(find ./app/build/outputs/apk/release -name "*.apk")
|
||||
pip3 install telethon
|
||||
python3 $GITHUB_WORKSPACE/scripts/ksunextbot.py $APK
|
||||
fi
|
||||
36
.github/workflows/build-su.yml
vendored
36
.github/workflows/build-su.yml
vendored
@@ -1,36 +0,0 @@
|
||||
name: Build SU
|
||||
on:
|
||||
push:
|
||||
branches: [ "next" ]
|
||||
paths:
|
||||
- '.github/workflows/build-su.yml'
|
||||
- 'userspace/su/**'
|
||||
- 'scripts/ksunextbot.py'
|
||||
pull_request:
|
||||
branches: [ "next" ]
|
||||
paths:
|
||||
- 'userspace/su/**'
|
||||
jobs:
|
||||
build-su:
|
||||
name: Build userspace su
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup need_upload
|
||||
id: need_upload
|
||||
run: |
|
||||
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
||||
echo "UPLOAD=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "UPLOAD=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
- name: Build su
|
||||
working-directory: ./userspace/su
|
||||
run: $ANDROID_NDK/ndk-build
|
||||
- name: Upload a Build Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: su
|
||||
path: ./userspace/su/libs
|
||||
54
.github/workflows/clippy.yml
vendored
54
.github/workflows/clippy.yml
vendored
@@ -1,54 +0,0 @@
|
||||
name: Clippy check
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- next
|
||||
paths:
|
||||
- '.github/workflows/clippy.yml'
|
||||
- 'userspace/ksud_magic/**'
|
||||
- 'userspace/ksud_overlayfs/**'
|
||||
pull_request:
|
||||
branches:
|
||||
- next
|
||||
paths:
|
||||
- '.github/workflows/clippy.yml'
|
||||
- 'userspace/ksud_magic/**'
|
||||
- 'userspace/ksud_overlayfs/**'
|
||||
|
||||
env:
|
||||
RUSTFLAGS: '-Dwarnings'
|
||||
|
||||
jobs:
|
||||
clippy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust
|
||||
run: rustup update stable
|
||||
|
||||
- name: Setup Cross
|
||||
run: RUSTFLAGS="" cargo install cross
|
||||
|
||||
- name: Cache ksud_overlayfs
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: userspace/ksud_overlayfs
|
||||
|
||||
- name: Cache ksud_magic
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: userspace/ksud_magic
|
||||
|
||||
- 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_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
|
||||
261
.github/workflows/gki-kernel.yml
vendored
261
.github/workflows/gki-kernel.yml
vendored
@@ -1,261 +0,0 @@
|
||||
name: GKI Kernel Build
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
version:
|
||||
required: true
|
||||
type: string
|
||||
description: >
|
||||
Output directory of gki,
|
||||
for example: android12-5.10
|
||||
version_name:
|
||||
required: true
|
||||
type: string
|
||||
description: >
|
||||
With SUBLEVEL of kernel,
|
||||
for example: android12-5.10.66
|
||||
tag:
|
||||
required: true
|
||||
type: string
|
||||
description: >
|
||||
Part of branch name of common kernel manifest,
|
||||
for example: android12-5.10-2021-11
|
||||
os_patch_level:
|
||||
required: false
|
||||
type: string
|
||||
description: >
|
||||
Patch level of common kernel manifest,
|
||||
for example: 2021-11
|
||||
default: 2022-05
|
||||
patch_path:
|
||||
required: false
|
||||
type: string
|
||||
description: >
|
||||
Directory name of .github/patches/<patch_path>
|
||||
for example: 5.10
|
||||
use_cache:
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
embed_ksud:
|
||||
required: false
|
||||
type: string
|
||||
default: ksud-aarch64-linux-android
|
||||
description: >
|
||||
Artifact name of prebuilt ksud to be embedded
|
||||
for example: ksud-aarch64-linux-android
|
||||
debug:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
build_lkm:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
secrets:
|
||||
BOOT_SIGN_KEY:
|
||||
required: false
|
||||
CHAT_ID:
|
||||
required: false
|
||||
BOT_TOKEN:
|
||||
required: false
|
||||
MESSAGE_THREAD_ID:
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build ${{ inputs.version_name }}
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CCACHE_COMPILERCHECK: "%compiler% -dumpmachine; %compiler% -dumpversion"
|
||||
CCACHE_NOHASHDIR: "true"
|
||||
CCACHE_HARDLINK: "true"
|
||||
steps:
|
||||
- name: Maximize build space
|
||||
uses: easimon/maximize-build-space@master
|
||||
with:
|
||||
root-reserve-mb: 8192
|
||||
temp-reserve-mb: 2048
|
||||
remove-dotnet: 'true'
|
||||
remove-android: 'true'
|
||||
remove-haskell: 'true'
|
||||
remove-codeql: 'true'
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
path: KernelSU-Next
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup need_upload
|
||||
id: need_upload
|
||||
run: |
|
||||
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
||||
echo "UPLOAD=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "UPLOAD=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Setup kernel source
|
||||
run: |
|
||||
echo "Free space:"
|
||||
df -h
|
||||
cd $GITHUB_WORKSPACE
|
||||
sudo apt-get install repo -y
|
||||
mkdir android-kernel && cd android-kernel
|
||||
repo init --depth=1 --u https://android.googlesource.com/kernel/manifest -b common-${{ inputs.tag }} --repo-rev=v2.16
|
||||
REMOTE_BRANCH=$(git ls-remote https://android.googlesource.com/kernel/common ${{ inputs.tag }})
|
||||
DEFAULT_MANIFEST_PATH=.repo/manifests/default.xml
|
||||
if grep -q deprecated <<< $REMOTE_BRANCH; then
|
||||
echo "Found deprecated branch: ${{ inputs.tag }}"
|
||||
sed -i 's/"${{ inputs.tag }}"/"deprecated\/${{ inputs.tag }}"/g' $DEFAULT_MANIFEST_PATH
|
||||
cat $DEFAULT_MANIFEST_PATH
|
||||
fi
|
||||
repo --version
|
||||
repo --trace sync -c -j$(nproc --all) --no-tags
|
||||
df -h
|
||||
|
||||
- name: Setup KernelSU-Next
|
||||
env:
|
||||
PATCH_PATH: ${{ inputs.patch_path }}
|
||||
IS_DEBUG_KERNEL: ${{ inputs.debug }}
|
||||
run: |
|
||||
cd $GITHUB_WORKSPACE/android-kernel
|
||||
echo "[+] KernelSU-Next setup"
|
||||
GKI_ROOT=$(pwd)
|
||||
echo "[+] GKI_ROOT: $GKI_ROOT"
|
||||
echo "[+] Copy KernelSU-Next driver to $GKI_ROOT/common/drivers"
|
||||
ln -sf $GITHUB_WORKSPACE/KernelSU-Next/kernel $GKI_ROOT/common/drivers/kernelsu
|
||||
echo "[+] Add KernelSU-Next driver to Makefile"
|
||||
DRIVER_MAKEFILE=$GKI_ROOT/common/drivers/Makefile
|
||||
DRIVER_KCONFIG=$GKI_ROOT/common/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 Compilation Patches"
|
||||
if [ ! -e build/build.sh ]; then
|
||||
GLIBC_VERSION=$(ldd --version 2>/dev/null | head -n 1 | awk '{print $NF}')
|
||||
echo "GLIBC_VERSION: $GLIBC_VERSION"
|
||||
if [ "$(printf '%s\n' "2.38" "$GLIBC_VERSION" | sort -V | head -n1)" = "2.38" ]; then
|
||||
echo "Patching resolve_btfids/Makefile"
|
||||
cd $GKI_ROOT/common/ && sed -i '/\$(Q)\$(MAKE) -C \$(SUBCMD_SRC) OUTPUT=\$(abspath \$(dir \$@))\/ \$(abspath \$@)/s//$(Q)$(MAKE) -C $(SUBCMD_SRC) EXTRA_CFLAGS="$(CFLAGS)" OUTPUT=$(abspath $(dir $@))\/ $(abspath $@)/' tools/bpf/resolve_btfids/Makefile || echo "No patch needed."
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$IS_DEBUG_KERNEL" = "true" ]; then
|
||||
echo "[+] Enable debug features for kernel"
|
||||
printf "\nccflags-y += -DCONFIG_KSU_DEBUG\n" >> $GITHUB_WORKSPACE/KernelSU-Next/kernel/Makefile
|
||||
fi
|
||||
repo status
|
||||
echo "[+] KernelSU-Next setup done."
|
||||
|
||||
- name: Symbol magic
|
||||
run: |
|
||||
echo "[+] Export all symbol from abi_gki_aarch64.xml"
|
||||
COMMON_ROOT=$GITHUB_WORKSPACE/android-kernel/common
|
||||
KSU_ROOT=$GITHUB_WORKSPACE/KernelSU-Next
|
||||
ABI_XML=$COMMON_ROOT/android/abi_gki_aarch64.xml
|
||||
SYMBOL_LIST=$COMMON_ROOT/android/abi_gki_aarch64
|
||||
# python3 $KSU_ROOT/scripts/abi_gki_all.py $ABI_XML > $SYMBOL_LIST
|
||||
echo "[+] Add KernelSU-Next symbols"
|
||||
cat $KSU_ROOT/kernel/export_symbol.txt | awk '{sub("[ \t]+","");print " "$0}' >> $SYMBOL_LIST
|
||||
|
||||
- name: Setup ccache
|
||||
if: inputs.use_cache == true
|
||||
uses: hendrikmuhs/ccache-action@v1
|
||||
with:
|
||||
key: gki-kernel-aarch64-${{ inputs.version_name }}
|
||||
max-size: 2G
|
||||
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||
|
||||
- name: Setup for LKM
|
||||
if: ${{ inputs.build_lkm == true }}
|
||||
working-directory: android-kernel
|
||||
run: |
|
||||
pip install ast-grep-cli
|
||||
sudo apt-get install llvm-15 -y
|
||||
ast-grep -U -p '$$$ check_exports($$$) {$$$}' -r '' common/scripts/mod/modpost.c
|
||||
ast-grep -U -p 'check_exports($$$);' -r '' common/scripts/mod/modpost.c
|
||||
sed -i '/config KSU/,/help/{s/default y/default m/}' common/drivers/kernelsu/Kconfig
|
||||
echo "drivers/kernelsu/kernelsu.ko" >> common/android/gki_aarch64_modules
|
||||
|
||||
# bazel build, android14-5.15, android14-6.1 use bazel
|
||||
if [ ! -e build/build.sh ]; then
|
||||
sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' build/kernel/*.sh || echo "No unknown symbol scripts found"
|
||||
if [ -e common/modules.bzl ]; then
|
||||
sed -i 's/_COMMON_GKI_MODULES_LIST = \[/_COMMON_GKI_MODULES_LIST = \[ "drivers\/kernelsu\/kernelsu.ko",/g' common/modules.bzl
|
||||
fi
|
||||
else
|
||||
TARGET_FILE="build/kernel/build.sh"
|
||||
if [ ! -e "$TARGET_FILE" ]; then
|
||||
TARGET_FILE="build/build.sh"
|
||||
fi
|
||||
sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' $TARGET_FILE || echo "No unknown symbol in $TARGET_FILE"
|
||||
sed -i 's/if ! diff -u "\${KERNEL_DIR}\/\${MODULES_ORDER}" "\${OUT_DIR}\/modules\.order"; then/if false; then/g' $TARGET_FILE
|
||||
sed -i 's@${ROOT_DIR}/build/abi/compare_to_symbol_list@echo@g' $TARGET_FILE
|
||||
sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' build/kernel/*.sh || echo "No unknown symbol scripts found"
|
||||
fi
|
||||
|
||||
- name: Make working directory clean to avoid dirty
|
||||
working-directory: android-kernel
|
||||
run: |
|
||||
if [ -f ./common/BUILD.bazel ]; then
|
||||
sed -i '/^[[:space:]]*"protected_exports_list"[[:space:]]*:[[:space:]]*"android\/abi_gki_protected_exports_aarch64",$/d' ./common/BUILD.bazel
|
||||
fi
|
||||
rm common/android/abi_gki_protected_exports_* || echo "No protected exports!"
|
||||
git config --global user.email "bot@kernelsu.org"
|
||||
git config --global user.name "KernelSU-NextBot"
|
||||
cd common/ && git add -A && git commit -a -m "Add KernelSU-Next"
|
||||
repo status
|
||||
|
||||
- name: Build Kernel/LKM
|
||||
working-directory: android-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
|
||||
if [ -e build/build.sh ]; then
|
||||
LTO=thin BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh CC="/usr/bin/ccache clang"
|
||||
else
|
||||
tools/bazel run --disk_cache=/home/runner/.cache/bazel --config=fast --config=stamp --lto=thin //common:kernel_aarch64_dist -- --dist_dir=dist
|
||||
fi
|
||||
|
||||
- name: Prepare artifacts
|
||||
id: prepareArtifacts
|
||||
run: |
|
||||
OUTDIR=android-kernel/out/${{ inputs.version }}/dist
|
||||
if [ ! -e $OUTDIR ]; then
|
||||
OUTDIR=android-kernel/dist
|
||||
fi
|
||||
mkdir output
|
||||
if [ "${{ inputs.build_lkm}}" = "true" ]; then
|
||||
llvm-strip-15 -d $OUTDIR/kernelsu.ko
|
||||
mv $OUTDIR/kernelsu.ko ./output/${{ inputs.version }}_kernelsu.ko
|
||||
else
|
||||
cp $OUTDIR/Image ./output/
|
||||
cp $OUTDIR/Image.lz4 ./output/
|
||||
git clone https://github.com/Kernel-SU/AnyKernel3
|
||||
rm -rf ./AnyKernel3/.git
|
||||
cp $OUTDIR/Image ./AnyKernel3/
|
||||
fi
|
||||
|
||||
- name: Upload Image and Image.gz
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ inputs.build_lkm == false }}
|
||||
with:
|
||||
name: Image-${{ inputs.version_name }}_${{ inputs.os_patch_level }}
|
||||
path: ./output/*
|
||||
|
||||
- name: Upload AnyKernel3
|
||||
if: ${{ inputs.build_lkm == false }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AnyKernel3-${{ inputs.version_name }}_${{ inputs.os_patch_level }}
|
||||
path: ./AnyKernel3/*
|
||||
|
||||
- name: Upload LKM
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ inputs.build_lkm == true }}
|
||||
with:
|
||||
name: ${{ inputs.version }}-lkm
|
||||
path: ./output/*_kernelsu.ko
|
||||
84
.github/workflows/ksud.yml
vendored
84
.github/workflows/ksud.yml
vendored
@@ -1,84 +0,0 @@
|
||||
name: Build ksud
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
target:
|
||||
required: true
|
||||
type: string
|
||||
os:
|
||||
required: false
|
||||
type: string
|
||||
default: ubuntu-latest
|
||||
pack_lkm:
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
use_cache:
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ inputs.os }}
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- 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/
|
||||
|
||||
- name: Import susfsd Libraries
|
||||
run: |
|
||||
cp susfsd-linux-android/arm64-v8a/susfsd ./userspace/ksud_overlayfs/bin/aarch64/
|
||||
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
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: userspace/ksud_overlayfs
|
||||
cache-targets: false
|
||||
|
||||
- name: Cache ksud_magic
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: userspace/ksud_magic
|
||||
cache-targets: false
|
||||
|
||||
- name: Setup Cross
|
||||
run: |
|
||||
RUSTFLAGS="" cargo install cross --git https://github.com/cross-rs/cross --rev 66845c1 --force
|
||||
|
||||
- name: Build ksud
|
||||
run: |
|
||||
CROSS_NO_WARNINGS=0 cross build --target ${{ inputs.target }} --release --manifest-path ./userspace/ksud_overlayfs/Cargo.toml
|
||||
CROSS_NO_WARNINGS=0 cross build --target ${{ inputs.target }} --release --manifest-path ./userspace/ksud_magic/Cargo.toml
|
||||
|
||||
- name: Upload ksud_overlayfs artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ksud_overlayfs-${{ inputs.target }}
|
||||
path: userspace/ksud_overlayfs/target/**/release/ksud*
|
||||
|
||||
- name: Upload ksud_magic artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ksud_magic-${{ inputs.target }}
|
||||
path: userspace/ksud_magic/target/**/release/ksud*
|
||||
85
.github/workflows/release.yml
vendored
85
.github/workflows/release.yml
vendored
@@ -1,85 +0,0 @@
|
||||
name: Release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-manager:
|
||||
uses: ./.github/workflows/build-manager.yml
|
||||
secrets: inherit
|
||||
build-a12-kernel:
|
||||
uses: ./.github/workflows/build-kernel-a12.yml
|
||||
secrets: inherit
|
||||
build-a13-kernel:
|
||||
uses: ./.github/workflows/build-kernel-a13.yml
|
||||
secrets: inherit
|
||||
build-a14-kernel:
|
||||
uses: ./.github/workflows/build-kernel-a14.yml
|
||||
secrets: inherit
|
||||
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
|
||||
- build-a12-kernel
|
||||
- build-a13-kernel
|
||||
- build-a14-kernel
|
||||
- build-a15-kernel
|
||||
- build-wsa-kernel
|
||||
- build-arcvm-kernel
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
- name: Zip AnyKernel3
|
||||
run: |
|
||||
for dir in AnyKernel3-*; do
|
||||
if [ -d "$dir" ]; then
|
||||
echo "----- Zip $dir -----"
|
||||
(cd $dir && zip -r9 "$dir".zip ./* -x .git .gitignore ./*.zip && mv *.zip ..)
|
||||
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
|
||||
|
||||
- name: release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: |
|
||||
Manager/*.apk
|
||||
android*-lkm/*_kernelsu.ko
|
||||
AnyKernel3-*.zip
|
||||
boot-images-*/Image-*/*.img.gz
|
||||
kernel-WSA*.zip
|
||||
kernel-ARCVM*.zip
|
||||
ksud_magic*.zip
|
||||
ksud_overlayfs*.zip
|
||||
susfsd*.zip
|
||||
40
.github/workflows/rustfmt.yml
vendored
40
.github/workflows/rustfmt.yml
vendored
@@ -1,40 +0,0 @@
|
||||
name: Rustfmt check
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'next'
|
||||
paths:
|
||||
- '.github/workflows/rustfmt.yml'
|
||||
- 'userspace/ksud_magic/**'
|
||||
- 'userspace/ksud_overlayfs/**'
|
||||
pull_request:
|
||||
branches:
|
||||
- 'next'
|
||||
paths:
|
||||
- '.github/workflows/rustfmt.yml'
|
||||
- 'userspace/ksud_magic/**'
|
||||
- 'userspace/ksud_overlayfs/**'
|
||||
|
||||
permissions:
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
format:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
with:
|
||||
components: rustfmt
|
||||
|
||||
- uses: LoliGothick/rustfmt-check@master
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
working-directory: userspace/ksud_magic
|
||||
|
||||
- uses: LoliGothick/rustfmt-check@master
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
working-directory: userspace/ksud_overlayfs
|
||||
27
.github/workflows/shellcheck.yml
vendored
27
.github/workflows/shellcheck.yml
vendored
@@ -1,27 +0,0 @@
|
||||
name: ShellCheck
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'next'
|
||||
paths:
|
||||
- '.github/workflows/shellcheck.yml'
|
||||
- '**/*.sh'
|
||||
pull_request:
|
||||
branches:
|
||||
- 'next'
|
||||
paths:
|
||||
- '.github/workflows/shellcheck.yml'
|
||||
- '**/*.sh'
|
||||
|
||||
jobs:
|
||||
shellcheck:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Run ShellCheck
|
||||
uses: ludeeus/action-shellcheck@2.0.0
|
||||
with:
|
||||
ignore_names: gradlew
|
||||
ignore_paths: ./userspace/ksud_magic/src/installer.sh ./userspace/ksud_overlayfs/src/installer.sh
|
||||
31
.github/workflows/susfsd.yml
vendored
31
.github/workflows/susfsd.yml
vendored
@@ -1,31 +0,0 @@
|
||||
name: Build susfsd aarch64
|
||||
on:
|
||||
push:
|
||||
branches: [ "next" ]
|
||||
paths:
|
||||
- '.github/workflows/susfsd.yml'
|
||||
- 'userspace/susfsd/**'
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
inputs:
|
||||
os:
|
||||
required: false
|
||||
type: string
|
||||
default: ubuntu-latest
|
||||
jobs:
|
||||
build-susfs:
|
||||
name: Build userspace susfsd
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Build susfsd
|
||||
working-directory: ./userspace/susfsd
|
||||
run: $ANDROID_NDK/ndk-build
|
||||
- name: Upload Build Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: susfsd-linux-android
|
||||
path: ./userspace/susfsd/libs
|
||||
|
||||
106
.github/workflows/wsa-kernel.yml
vendored
106
.github/workflows/wsa-kernel.yml
vendored
@@ -1,106 +0,0 @@
|
||||
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 }}"
|
||||
@@ -1,7 +0,0 @@
|
||||
# Reporting Security Issues
|
||||
|
||||
The KernelSU team and community take security bugs in KernelSU seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.
|
||||
|
||||
To report a security issue, please use the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/tiann/KernelSU/security/advisories/new) tab, or you can mailto [weishu](mailto:twsxtd@gmail.com) directly.
|
||||
|
||||
The KernelSU team will send a response indicating the next steps in handling your report. After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
@@ -1,63 +0,0 @@
|
||||
**English** | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [Türkçe](README_TR.md) | [Português (Brasil)](README_PT-BR.md) | [한국어](README_KO.md) | [Français](README_FR.md) | [Bahasa Indonesia](README_ID.md) | [Русский](README_RU.md) | [ภาษาไทย](README_TH.md) | [Tiếng Việt](README_VI.md) | [Italiano](README_IT.md) | [Polski](README_PL.md) | [Български](README_BG.md) | [日本語](README_JA.md) | [Українська](README_UA.md)
|
||||
|
||||
# KernelSU Next
|
||||
|
||||
<img src="/assets/kernelsu_next.png" style="width: 96px;" alt="logo">
|
||||
|
||||
A kernel-based root solution for Android devices.
|
||||
|
||||
[](https://github.com/KernelSU-Next/KernelSU-Next/releases/latest)
|
||||
[](https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## Features
|
||||
|
||||
1. Kernel-based `su` and root access management.
|
||||
2. Module system based on dynamic mount system [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||
3. [App Profile](https://kernelsu.org/guide/app-profile.html): Lock up the root power in a cage.
|
||||
|
||||
## Compatibility state
|
||||
|
||||
KernelSU Next officially supports most Android kernels starting from 4.4 up to 6.6.
|
||||
- GKI 2.0 (5.10+) kernels can run pre-built images and LKM/KMI.
|
||||
- GKI 1.0 (4.19 - 5.4) kernels need to rebuilt with KernelSU driver.
|
||||
- EOL (<4.14) kernels also need to be rebuilt with KernelSU driver (3.18+ is experimental and may need some function backports).
|
||||
|
||||
Currently, only the `arm64-v8a`, `armeabi-v7a` & `x86_64` architectures are supported.
|
||||
|
||||
## Usage
|
||||
|
||||
- [Installation instruction](https://kernelsu-next.github.io/webpage/pages/installation.html)
|
||||
|
||||
## Security
|
||||
|
||||
For information on reporting security vulnerabilities in KernelSU, see [SECURITY.md](/SECURITY.md).
|
||||
|
||||
## License
|
||||
|
||||
- Files under the `kernel` directory are [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||
- All other parts except the `kernel` directory are [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
|
||||
## Donations
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT BEP20 ]
|
||||
|
||||
- TYUVMWGTcnR5svnDoX85DWHyqUAeyQcdjh [ USDT TRC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT ERC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ ETH ERC20 ]
|
||||
|
||||
- Ld238uYBuRQdZB5YwdbkuU6ektBAAUByoL [ LTC ]
|
||||
|
||||
- 19QgifcjMjSr1wB2DJcea5cxitvWVcXMT6 [ BTC ]
|
||||
|
||||
## Credits
|
||||
|
||||
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): The KernelSU idea.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): The powerful root tool.
|
||||
- [genuine](https://github.com/brevent/genuine/): APK v2 signature validation.
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): Some rootkit skills.
|
||||
- [KernelSU](https://github.com/tiann/KernelSU): Thanks to tiann, or else KernelSU Next wouldn't even exist.
|
||||
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): 💜 5ec1cff for saving KernelSU!
|
||||
@@ -1,58 +0,0 @@
|
||||
[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [Türkçe](README_TR.md) | [Português (Brasil)](README_PT-BR.md) | [한국어](README_KO.md) | [Français](README_FR.md) | [Bahasa Indonesia](README_ID.md) | [Русский](README_RU.md) | [Український](README_UA.md) | [ภาษาไทย](README_TH.md) | [Tiếng Việt](README_VI.md) | [Italiano](README_IT.md) | [Polski](README_PL.md) | **Български** | [日本語](README_JA.md)
|
||||
|
||||
# KernelSU Next
|
||||
|
||||
<img src="/assets/kernelsu_next.png" style="width: 96px;" alt="лого">
|
||||
|
||||
Ядрено решение за root достъп за Android устройства.
|
||||
|
||||
[](https://github.com/KernelSU-Next/KernelSU-Next/releases/latest)
|
||||
[](https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## Възможности
|
||||
|
||||
1. Управление на `su` и root достъп на ядрено ниво
|
||||
2. Система за модули базирана на [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS)
|
||||
3. [Профили за приложения](https://kernelsu.org/guide/app-profile.html): Ограничаване на root права за конкретни приложения
|
||||
|
||||
## Съвместимост
|
||||
|
||||
KernelSU Next официално поддържа повечето Android ядра от версия 4.4 до 6.6:
|
||||
- Ядра GKI 2.0 (5.10+) могат да използват предварително компилирани изображения и LKM/KMI
|
||||
- Ядра GKI 1.0 (4.19 - 5.4) изискват прекомпилиране с драйвера на KernelSU
|
||||
- Остарели ядра (<4.14) също изискват прекомпилиране (3.18+ е експериментална поддръжка)
|
||||
|
||||
В момента се поддържа само архитектурата `arm64-v8a`, `armeabi-v7a` & `x86_64`.
|
||||
|
||||
## Инсталация
|
||||
|
||||
- [Инструкции за инсталиране](https://ksunext.org/pages/installation.html)
|
||||
|
||||
## Сигурност
|
||||
|
||||
За докладване на уязвимости вижте [SECURITY.md](/SECURITY.md).
|
||||
|
||||
## Лиценз
|
||||
|
||||
- Файловете в директорията `kernel` са [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
- Всички останали файлове са [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
## Дарения
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT BEP20 ]
|
||||
- TYUVMWGTcnR5svnDoX85DWHyqUAeyQcdjh [ USDT TRC20 ]
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT ERC20 ]
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ ETH ERC20 ]
|
||||
- Ld238uYBuRQdZB5YwdbkuU6ektBAAUByoL [ LTC ]
|
||||
- 19QgifcjMjSr1wB2DJcea5cxitvWVcXMT6 [ BTC ]
|
||||
|
||||
## Благодарности
|
||||
|
||||
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): Идеята за KernelSU
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): Мощният root инструмент
|
||||
- [genuine](https://github.com/brevent/genuine/): Валидация на APK подписи v2
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): Rootkit техники
|
||||
- [KernelSU](https://github.com/tiann/KernelSU): Благодарности към tiann за създаването на KernelSU
|
||||
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): 💜 5ec1cff за спасяването на KernelSU
|
||||
@@ -1,49 +0,0 @@
|
||||
[English](README.md) | **简体中文** | [繁體中文](README_TW.md) | [Türkçe](README_TR.md) | [Português (Brasil)](README_PT-BR.md) | [한국어](README_KO.md) | [Français](README_FR.md) | [Bahasa Indonesia](README_ID.md) | [Русский](README_RU.md) | [Український](README_UA.md) | [ภาษาไทย](README_TH.md) | [Tiếng Việt](README_VI.md) | [Italiano](README_IT.md) | [Polski](README_PL.md) | [Български](README_BG.md) | [日本語](README_JA.md)
|
||||
|
||||
# KernelSU Next
|
||||
|
||||
<img src="/assets/kernelsu_next.png" style="width: 96px;" alt="logo">
|
||||
|
||||
安卓基于内核的 Root 方案
|
||||
|
||||
[](https://github.com/KernelSU-Next/KernelSU-Next/releases/latest)
|
||||
[](https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## 特性
|
||||
|
||||
1. 基于内核的 `SU` 和权限管理
|
||||
2. 基于动态挂载系统 [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) 的模块系统。
|
||||
3. [App Profile](https://kernelsu.org/zh_CN/guide/app-profile.html):把 Root 权限关进笼子里
|
||||
|
||||
## 兼容状态
|
||||
|
||||
KernelSU Next 支持从 4.4 到 6.6 的大多数安卓内核
|
||||
- GKI 2.0(5.10+)内核可运行预置镜像和 LKM/KMI
|
||||
- GKI 1.0(4.19 - 5.4)内核需要使用 KernelSU 内核驱动重新编译
|
||||
- EOL (<4.14) 内核也需要使用 KernelSU 内核驱动重新编译 (3.18+ 的版本处于试验阶段,可能需要移植一些功能)
|
||||
|
||||
目前只支持 `arm64-v8a`, `armeabi-v7a` & `x86_64` 架构
|
||||
|
||||
## 用法
|
||||
|
||||
- [安装说明](https://ksunext.org/pages/installation.html)
|
||||
|
||||
## 安全性
|
||||
|
||||
有关报告 KernelSU Next 漏洞的信息,请参阅 [SECURITY.md](/SECURITY.md).
|
||||
|
||||
## 许可证
|
||||
|
||||
- 目录 `kernel` 下所有文件为 [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
- `kernel` 目录以外的其他部分均为 [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
## 鸣谢
|
||||
|
||||
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): KernelSU 的灵感.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): 强大的 Root 工具.
|
||||
- [genuine](https://github.com/brevent/genuine/): APK v2 签名验证。
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): 一些 Rootkit 技巧。
|
||||
- [KernelSU](https://github.com/tiann/KernelSU): 感谢 tiann,否则 KernelSU Next 根本不会存在。
|
||||
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): 💜 5ec1cff 為了拯救 KernelSU!
|
||||
@@ -1,49 +0,0 @@
|
||||
[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [Türkçe](README_TR.md) | [Português (Brasil)](README_PT-BR.md) | [한국어](README_KO.md) | **Français** | [Bahasa Indonesia](README_ID.md) | [Русский](README_RU.md) | [Український](README_UA.md) | [ภาษาไทย](README_TH.md) | [Tiếng Việt](README_VI.md) | [Italiano](README_IT.md) | [Polski](README_PL.md) | [Български](README_BG.md) | [日本語](README_JA.md)
|
||||
|
||||
# KernelSU Next
|
||||
|
||||
<img src="/assets/kernelsu_next.png" style="width: 96px;" alt="logo">
|
||||
|
||||
Une solution root basée sur le noyau pour les appareils Android.
|
||||
|
||||
[](https://github.com/KernelSU-Next/KernelSU-Next/releases/latest)
|
||||
[](https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## Fonctionnalités
|
||||
|
||||
1. Gestion des accès root et de la commande `su` basée sur le noyau.
|
||||
2. Système de modules basé sur le système de montage dynamique [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||
3. [Profil d'application](https://kernelsu.org/guide/app-profile.html) : Enfermez la puissance du root dans une cage.
|
||||
|
||||
## État de compatibilité
|
||||
|
||||
KernelSU Next prend officiellement en charge la plupart des noyaux Android de la version 4.4 à la version 6.6.
|
||||
- Les noyaux GKI 2.0 (5.10+) peuvent exécuter des images pré-construites et des modules LKM/KMI.
|
||||
- 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`, `armeabi-v7a` & `x86_64` est pris en charge.
|
||||
|
||||
## Utilisation
|
||||
|
||||
- [Instructions d'installation](https://ksunext.org/pages/installation.html)
|
||||
|
||||
## Sécurité
|
||||
|
||||
Pour signaler des vulnérabilités de sécurité dans KernelSU, consultez [SECURITY.md](/SECURITY.md).
|
||||
|
||||
## Licence
|
||||
|
||||
- Les fichiers du répertoire `kernel` sont sous licence [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||
- Toutes les autres parties, sauf le répertoire `kernel`, sont sous licence [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
|
||||
## Crédits
|
||||
|
||||
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/) : L'idée de KernelSU.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk) : L'outil root puissant.
|
||||
- [genuine](https://github.com/brevent/genuine/) : Validation de signature APK v2.
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine) : Quelques techniques de rootkit.
|
||||
- [KernelSU](https://github.com/tiann/KernelSU) : Merci à tiann, sans qui KernelSU Next n'existerait même pas.
|
||||
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs) : 💜 5ec1cff pour avoir sauvé KernelSU !
|
||||
@@ -1,49 +0,0 @@
|
||||
[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [Türkçe](README_TR.md) | [Português (Brasil)](README_PT-BR.md) | [한국어](README_KO.md) | [Français](README_FR.md) | **Bahasa Indonesia** | [Русский](README_RU.md) | [Український](README_UA.md) | [ภาษาไทย](README_TH.md) | [Tiếng Việt](README_VI.md) | [Italiano](README_IT.md) | [Polski](README_PL.md) | [Български](README_BG.md) | [日本語](README_JA.md)
|
||||
|
||||
# KernelSU Next
|
||||
|
||||
<img src="/assets/kernelsu_next.png" style="width: 96px;" alt="logo">
|
||||
|
||||
Sebuah solusi root berbasis Kernel untuk perangkat Android.
|
||||
|
||||
[](https://github.com/KernelSU-Next/KernelSU-Next/releases/latest)
|
||||
[](https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## Fitur
|
||||
|
||||
1. Akses root dan manajemen `su` berbasis Kernel.
|
||||
2. Sistem modul berbasis sistem mount dinamis [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||
3. [Profil Aplikasi](https://kernelsu.org/guide/app-profile.html): Mengunci kekuatan root dalam sebuah kandang.
|
||||
|
||||
## Status Kompatibilitas
|
||||
|
||||
KernelSU Next secara resmi mendukung sebagian besar kernel Android mulai dari 4.4 hingga 6.6.
|
||||
- Kernel GKI 2.0 (5.10+) dapat menjalankan gambar yang telah dibangun sebelumnya dan LKM/KMI.
|
||||
- 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`, `armeabi-v7a` & `x86_64` yang didukung.
|
||||
|
||||
## Penggunaan
|
||||
|
||||
- [Petunjuk instalasi](https://ksunext.org/pages/installation.html)
|
||||
|
||||
## Keamanan
|
||||
|
||||
Untuk informasi tentang melaporkan kerentanannya di KernelSU, lihat [SECURITY.md](/SECURITY.md).
|
||||
|
||||
## Lisensi
|
||||
|
||||
- File di bawah direktori `kernel` menggunakan lisensi [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||
- Semua bagian lain kecuali direktori `kernel` menggunakan lisensi [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
|
||||
## Kredit
|
||||
|
||||
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): Ide KernelSU.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): Alat root yang kuat.
|
||||
- [genuine](https://github.com/brevent/genuine/): Validasi tanda tangan APK v2.
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): Beberapa keterampilan rootkit.
|
||||
- [KernelSU](https://github.com/tiann/KernelSU): Terima kasih kepada tiann, jika tidak, KernelSU Next bahkan tidak akan ada.
|
||||
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): 💜 5ec1cff karena menyelamatkan KernelSU!
|
||||
@@ -1,63 +0,0 @@
|
||||
[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [Türkçe](README_TR.md) | [Português (Brasil)](README_PT-BR.md) | [한국어](README_KO.md) | [Français](README_FR.md) | [Bahasa Indonesia](README_ID.md) | [Русский](README_RU.md) | [Український](README_UA.md) | [ภาษาไทย](README_TH.md) | [Tiếng Việt](README_VI.md) | **Italiano** | [Polski](README_PL.md) | [Български](README_BG.md) | [日本語](README_JA.md)
|
||||
|
||||
# KernelSU Next
|
||||
|
||||
<img src="/assets/kernelsu_next.png" style="width: 96px;" alt="logo">
|
||||
|
||||
Una soluzione root basata sul kernel per dispositivi Android.
|
||||
|
||||
[](https://github.com/KernelSU-Next/KernelSU-Next/releases/latest)
|
||||
[](https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## Caratteristiche
|
||||
|
||||
1. Gestione degli accessi `su` e root basata sul kernel.
|
||||
2. Sistema modulare basato sul sistema di montaggio dinamico [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||
3. [App Profile](https://kernelsu.org/guide/app-profile.html): Rinchiudi il potere della radice in una gabbia.
|
||||
|
||||
## Stato compatibilità
|
||||
|
||||
KernelSU Next supporta ufficialmente la maggior parte dei kernel Android dalla versione 4.4 alla 6.6.
|
||||
- I kernel GKI 2.0 (5.10+) possono eseguire immagini precostruite e LKM/KMI.
|
||||
- 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`, `armeabi-v7a` & `x86_64`.
|
||||
|
||||
## Utilizzo
|
||||
|
||||
- [Istruzioni per l'installazione](https://ksunext.org/pages/installation.html)
|
||||
|
||||
## Security
|
||||
|
||||
Per informazioni sulla segnalazione delle vulnerabilità di sicurezza in KernelSU, vedere [SECURITY.md](/SECURITY.md).
|
||||
|
||||
## Licenza
|
||||
|
||||
- I file nella directory `kernel` sono [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||
- Tutte le altre parti eccetto la directory `kernel` sono [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
|
||||
## Donazioni
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT BEP20 ]
|
||||
|
||||
- TYUVMWGTcnR5svnDoX85DWHyqUAeyQcdjh [ USDT TRC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT ERC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ ETH ERC20 ]
|
||||
|
||||
- Ld238uYBuRQdZB5YwdbkuU6ektBAAUByoL [ LTC ]
|
||||
|
||||
- 19QgifcjMjSr1wB2DJcea5cxitvWVcXMT6 [ BTC ]
|
||||
|
||||
## Crediti
|
||||
|
||||
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): L'idea di KernelSU.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): Il potente strumento di root.
|
||||
- [genuine](https://github.com/brevent/genuine/): Convalida della firma APK v2.
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): Alcune competenze sui rootkit.
|
||||
- [KernelSU](https://github.com/tiann/KernelSU): Grazie a tiann, altrimenti KernelSU Next non esisterebbe nemmeno.
|
||||
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): 💜 5ec1cff per aver salvato KernelSU!
|
||||
@@ -1,63 +0,0 @@
|
||||
[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [Türkçe](README_TR.md) | [Português (Brasil)](README_PT-BR.md) | [한국어](README_KO.md) | [Français](README_FR.md) | [Bahasa Indonesia](README_ID.md) | [Русский](README_RU.md) | [Український](README_UA.md) | [ภาษาไทย](README_TH.md) | [Tiếng Việt](README_VI.md) | [Italiano](README_IT.md) | [Polski](README_PL.md) | [Български](README_BG.md) | **日本語**
|
||||
|
||||
# KernelSU Next
|
||||
|
||||
<img src="/assets/kernelsu_next.png" style="width: 96px;" alt="logo">
|
||||
|
||||
Android デバイス用のカーネルベースな root ソリューション。
|
||||
|
||||
[](https://github.com/KernelSU-Next/KernelSU-Next/releases/latest)
|
||||
[](https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## 機能
|
||||
|
||||
1. カーネルベースの `su` および root アクセスの管理。
|
||||
2. 動的マウントシステム [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) をベースとしたモジュールシステム。
|
||||
3. [アプリプロファイル](https://kernelsu.org/guide/app-profile.html): root 権限をケージに閉じ込めます。
|
||||
|
||||
## 互換性の状態
|
||||
|
||||
KernelSU Next は 4.4 から 6.6 までのほとんどの Android カーネルを公式でサポートしています。
|
||||
- GKI 2.0 (5.10 以降) のカーネルはビルド済みイメージで LKM/KMI を実行できます。
|
||||
- GKI 1.0 (4.19 - 5.4) のカーネルは、KernelSU ドライバを使用してビルドする必要があります。
|
||||
- EOL (4.14 未満) のカーネルも KernelSU ドライバを使用して再ビルドする必要があります (3.18 以降は実験中の段階であり、一部の関数のバックポートが必要になる場合があります)。
|
||||
|
||||
現在 `arm64-v8a`, `armeabi-v7a` & `x86_64` アーキテクチャのみをサポートしています。
|
||||
|
||||
## 使い方
|
||||
|
||||
- [インストール手順](https://ksunext.org/pages/installation.html)
|
||||
|
||||
## セキュリティ
|
||||
|
||||
KernelSU のセキュリティ脆弱性の報告については [SECURITY.md](/SECURITY.md) を参照してください。
|
||||
|
||||
## ライセンス
|
||||
|
||||
- `kernel` ディレクトリ内のファイルは [GPL-2.0](https://www.gnu.org/licenses/old-licenses/gpl-2.0.ja.html) のみライセンス下にあります。
|
||||
- `kernel` ディレクトリを除くその他すべての部分は [GPL-3.0 またはそれ以降](https://www.gnu.org/licenses/gpl-3.0.html) のライセンス下にあります。
|
||||
|
||||
## 寄付
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT BEP20 ]
|
||||
|
||||
- TYUVMWGTcnR5svnDoX85DWHyqUAeyQcdjh [ USDT TRC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT ERC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ ETH ERC20 ]
|
||||
|
||||
- Ld238uYBuRQdZB5YwdbkuU6ektBAAUByoL [ LTC ]
|
||||
|
||||
- 19QgifcjMjSr1wB2DJcea5cxitvWVcXMT6 [ BTC ]
|
||||
|
||||
## クレジット
|
||||
|
||||
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): KernelSU のアイデアを考案。
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): パワフルな root ツール。
|
||||
- [genuine](https://github.com/brevent/genuine/): APK v2 署名認証。
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): いくつかの rootkit スキル。
|
||||
- [KernelSU](https://github.com/tiann/KernelSU): tiann に感謝を申し上げます。これが存在しなければ KernelSU Next は存在しませんでした。
|
||||
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): 💜 5ec1cff へ KernelSU を救ってくれてありがとう!
|
||||
@@ -1,49 +0,0 @@
|
||||
[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [Türkçe](README_TR.md) | [Português (Brasil)](README_PT-BR.md) | **한국어** | [Français](README_FR.md) | [Bahasa Indonesia](README_ID.md) | [Русский](README_RU.md) | [Український](README_UA.md) | [ภาษาไทย](README_TH.md) | [Tiếng Việt](README_VI.md) | [Italiano](README_IT.md) | [Polski](README_PL.md) | [Български](README_BG.md) | [日本語](README_JA.md)
|
||||
|
||||
# KernelSU Next
|
||||
|
||||
<img src="/assets/kernelsu_next.png" style="width: 96px;" alt="logo">
|
||||
|
||||
안드로이드 기기들을 위한 커널 기반 루팅 솔루션입니다.
|
||||
|
||||
[](https://github.com/KernelSU-Next/KernelSU-Next/releases/latest)
|
||||
[](https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## 기능
|
||||
|
||||
1. 커널 기반 `su` 및 루트 권한 관리
|
||||
2. 동적 마운트 시스템 기반 모듈 시스템 [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||
3. [App Profile](https://kernelsu.org/guide/app-profile.html): 루트 권한 제한
|
||||
|
||||
## 호환 상태
|
||||
|
||||
KernelSU Next는 공식적으로 대부분의 4.4부터 6.6의 안드로이드 커널을 지원합니다.
|
||||
- GKI 2.0 (5.10+) 커널은 미리 빌드된 이미지와 LKM/KMI를 지원합니다.
|
||||
- GKI 1.0 (4.19 - 5.4) 커널은 KernelSU 드라이버로 다시 빌드해야 합니다.
|
||||
- EOL (<4.14) 커널도 역시 KernelSU 드라이버로 다시 빌드해야 합니다.(3.18+는 실험적이며 일부 함수의 이식이 필요할 수 있습니다.).
|
||||
|
||||
현재는, `arm64-v8a`, `armeabi-v7a` & `x86_64` 만 지원됩니다.
|
||||
|
||||
## 사용 방법
|
||||
|
||||
- [설치 방법](https://ksunext.org/pages/installation.html)
|
||||
|
||||
## 보안
|
||||
|
||||
KernelSU의 보안 취약점 보고에 대한 자세한 내용은 [SECURITY.md](/SECURITY.md)를 참조하세요.
|
||||
|
||||
## 저작권 라이센스
|
||||
|
||||
- `kernel` 디렉터리의 파일은 [GPL-2.0전용](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)입니다.
|
||||
- `kernel` 디렉터리를 제외한 모든 파일은 [GPL-3.0-이상](https://www.gnu.org/licenses/gpl-3.0.html)입니다.
|
||||
|
||||
## 크레딧
|
||||
|
||||
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): KernelSU의 아이디어
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): 강력한 루팅 도구
|
||||
- [genuine](https://github.com/brevent/genuine/): APK v2 서명 검사
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): 일부 rootkit 기술
|
||||
- [KernelSU](https://github.com/tiann/KernelSU): KernelSU Next가 존재할 수 있게 해 준 tiann에게 감사드립니다.
|
||||
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): KernelSU를 구해준 5ec1cff에게 감사드립니다!
|
||||
@@ -1,63 +0,0 @@
|
||||
[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [Türkçe](README_TR.md) | [Português (Brasil)](README_PT-BR.md) | [한국어](README_KO.md) | [Français](README_FR.md) | [Bahasa Indonesia](README_ID.md) | [Русский](README_RU.md) | [Український](README_UA.md) | [ภาษาไทย](README_TH.md) | [Tiếng Việt](README_VI.md) | [Italiano](README_IT.md) | **Polski** | [Български](README_BG.md) | [日本語](README_JA.md)
|
||||
|
||||
# KernelSU Next
|
||||
|
||||
<img src="/assets/kernelsu_next.png" style="width: 96px;" alt="logo">
|
||||
|
||||
Bazujące na jądrze rozwiązanie root dla urządzeń z Androidem.
|
||||
|
||||
[](https://github.com/KernelSU-Next/KernelSU-Next/releases/latest)
|
||||
[](https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## Funkcjonalności
|
||||
|
||||
1. Oparte na jądrze `su` i zarządzanie dostępem do roota.
|
||||
2. System modułów oparty na dynamicznym systemie montowania [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||
3. [Profil aplikacji](https://kernelsu.org/guide/app-profile.html): Ujarzmij moc roota poprzez możliwość nakładania ograniczeń na uprawnienia roota dla poszczególnych aplikacji.
|
||||
|
||||
## Stan zgodności
|
||||
|
||||
KernelSU Next oficjalnie obsługuje większość jąder Androida od wersji 4.4 do 6.6.
|
||||
- Jądra GKI 2.0 (5.10+) mogą uruchamiać wstępnie przygotowane obrazy i LKM/KMI.
|
||||
- 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`, `armeabi-v7a` & `x86_64`
|
||||
|
||||
## Użycie
|
||||
|
||||
- [Instrukcja instalacji](https://ksunext.org/pages/installation.html)
|
||||
|
||||
## Bezpieczeństwo
|
||||
|
||||
Informacje na temat zgłaszania luk bezpieczeństwa w KernelSU znajdziesz w [SECURITY.md](/SECURITY.md).
|
||||
|
||||
## Licencje
|
||||
|
||||
- Pliki w katalogu `kernel` są dostępne na licencji [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||
- Wszystkie inne elementy, z wyjątkiem katalogu `kernel`, są dostępne na licencji [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
|
||||
## Darowizny
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT BEP20 ]
|
||||
|
||||
- TYUVMWGTcnR5svnDoX85DWHyqUAeyQcdjh [ USDT TRC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT ERC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ ETH ERC20 ]
|
||||
|
||||
- Ld238uYBuRQdZB5YwdbkuU6ektBAAUByoL [ LTC ]
|
||||
|
||||
- 19QgifcjMjSr1wB2DJcea5cxitvWVcXMT6 [ BTC ]
|
||||
|
||||
## Podziękowania
|
||||
|
||||
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): Idea, na której opiera się KernelSU.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): Potężne narzędzie do rootowania.
|
||||
- [genuine](https://github.com/brevent/genuine/): Walidacja podpisu APK v2.
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): Część zdolności rootkitowych.
|
||||
- [KernelSU](https://github.com/tiann/KernelSU): Dzięki tiann, bez ciebie KernelSU Next w ogóle by nie istniał.
|
||||
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): 💜 5ec1cff za uratowanie KernelSU!
|
||||
@@ -1,63 +0,0 @@
|
||||
[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [Türkçe](README_TR.md) | **Português (Brasil)** | [한국어](README_KO.md) | [Français](README_FR.md) | [Bahasa Indonesia](README_ID.md) | [Русский](README_RU.md) | [Український](README_UA.md) | [ภาษาไทย](README_TH.md) | [Tiếng Việt](README_VI.md) | [Italiano](README_IT.md) | [Polski](README_PL.md) | [Български](README_BG.md) | [日本語](README_JA.md)
|
||||
|
||||
# KernelSU Next
|
||||
|
||||
<img src="/assets/kernelsu_next.png" style="width: 96px;" alt="logo">
|
||||
|
||||
Uma solução root baseada em kernel para dispositivos Android.
|
||||
|
||||
[](https://github.com/KernelSU-Next/KernelSU-Next/releases/latest)
|
||||
[](https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## Características
|
||||
|
||||
1. `su` e gerenciamento de acesso root baseado em kernel.
|
||||
2. Sistema de módulos baseado em sistema de montagem dinâmica [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||
3. [Perfil do Aplicativo](https://kernelsu.org/pt_BR/guide/app-profile.html): Tranque o poder root em uma gaiola.
|
||||
|
||||
## Estado de compatibilidade
|
||||
|
||||
KernelSU Next suporta oficialmente a maioria dos kernels Android a partir de 4.4 até 6.6.
|
||||
- Os kernels GKI 2.0 (5.10+) podem executar imagens pré-construídas e LKM/KMI.
|
||||
- Os kernels GKI 1.0 (4.19 - 5.4) precisam ser reconstruídos com o driver KernelSU.
|
||||
- Os kernels EOL (<4.14) também precisam ser reconstruídos com o driver KernelSU (3.18+ é experimental e pode precisar portar algumas funções).
|
||||
|
||||
Atualmente, apenas as arquiteturas `arm64-v8a`, `armeabi-v7a` & `x86_64` são compatíveis.
|
||||
|
||||
## Uso
|
||||
|
||||
- [Instruções de instalação](https://ksunext.org/pages/installation.html)
|
||||
|
||||
## Segurança
|
||||
|
||||
Para obter informações sobre como relatar vulnerabilidades de segurança do KernelSU, consulte [SECURITY.md](/SECURITY.md).
|
||||
|
||||
## Licença
|
||||
|
||||
- Os arquivos no diretório `kernel` são [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||
- Todas as outras partes, exceto o diretório `kernel` são [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
|
||||
## Doações
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT BEP20 ]
|
||||
|
||||
- TYUVMWGTcnR5svnDoX85DWHyqUAeyQcdjh [ USDT TRC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT ERC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ ETH ERC20 ]
|
||||
|
||||
- Ld238uYBuRQdZB5YwdbkuU6ektBAAUByoL [ LTC ]
|
||||
|
||||
- 19QgifcjMjSr1wB2DJcea5cxitvWVcXMT6 [ BTC ]
|
||||
|
||||
## Créditos
|
||||
|
||||
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): A ideia do KernelSU.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): A poderosa ferramenta root.
|
||||
- [genuine](https://github.com/brevent/genuine/): Validação de assinatura APK v2.
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): Algumas habilidades de rootkit.
|
||||
- [KernelSU](https://github.com/tiann/KernelSU): Obrigado ao tiann, ou então o KernelSU Next nem existiria.
|
||||
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): 💜 5ec1cff por salvar o KernelSU!
|
||||
@@ -1,63 +0,0 @@
|
||||
[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [Türkçe](README_TR.md) | [Português (Brasil)](README_PT-BR.md) | [한국어](README_KO.md) | [Français](README_FR.md) | [Bahasa Indonesia](README_ID.md) | **Русский** | [Український](README_UA.md) | [ภาษาไทย](README_TH.md) | [Tiếng Việt](README_VI.md) | [Italiano](README_IT.md) | [Polski](README_PL.md) | [Български](README_BG.md) | [日本語](README_JA.md)
|
||||
|
||||
# KernelSU Next
|
||||
|
||||
<img src="/assets/kernelsu_next.png" style="width: 96px;" alt="logo">
|
||||
|
||||
Root-решение для Android на базе ядра.
|
||||
|
||||
[](https://github.com/KernelSU-Next/KernelSU-Next/releases/latest)
|
||||
[](https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## Функции
|
||||
|
||||
1. Реализация `su` и управление root-доступом прямо на уровне ядра.
|
||||
2. Динамическая система модулей, построенная на [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||
3. [Профиль для приложений](https://kernelsu.org/guide/app-profile.html): позволяет ограничить root-доступ в песочницу для отдельных приложений.
|
||||
|
||||
## Совместимость
|
||||
|
||||
KernelSU Next работает с большинством ядер Android (4.4 - 6.6):
|
||||
- GKI 2.0 (5.10+) могут использовать предсобранные образы и LKM/KMI.
|
||||
- GKI 1.0 (4.19 - 5.4) требуют пересборки с драйвером KernelSU.
|
||||
- EOL (<4.14) также требуют пересборки с драйвером KernelSU (версии 3.18+ экспериментальные и могут потребовать некоторые функции бэкпортов).
|
||||
|
||||
Сейчас поддерживается только `arm64-v8a`, `armeabi-v7a` & `x86_64`.
|
||||
|
||||
## Использование
|
||||
|
||||
- [Инструкция по установке](https://ksunext.org/pages/installation.html)
|
||||
|
||||
## Безопасность
|
||||
|
||||
Если нашли баг, посмотри [SECURITY.md](/SECURITY.md) — там гайд, как сообщить о проблеме.
|
||||
|
||||
## Лицензия
|
||||
|
||||
- Всё, что в директории `kernel`, — [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||
- Остальной код, кроме директории `kernel`, под [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
|
||||
## Донаты
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT BEP20 ]
|
||||
|
||||
- TYUVMWGTcnR5svnDoX85DWHyqUAeyQcdjh [ USDT TRC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT ERC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ ETH ERC20 ]
|
||||
|
||||
- Ld238uYBuRQdZB5YwdbkuU6ektBAAUByoL [ LTC ]
|
||||
|
||||
- 19QgifcjMjSr1wB2DJcea5cxitvWVcXMT6 [ BTC ]
|
||||
|
||||
## Благодарность
|
||||
|
||||
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): Идея KernelSU.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): Топовый инструмент для root.
|
||||
- [genuine](https://github.com/brevent/genuine/): Валидация подписи APK v2.
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): Некоторые навыки rootkit.
|
||||
- [KernelSU](https://github.com/tiann/KernelSU): Спасибо tiann, без него KernelSU Next даже не существовал бы.
|
||||
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): 💜 5ec1cff за сохранение KernelSU!
|
||||
@@ -1,63 +0,0 @@
|
||||
[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [Türkçe](README_TR.md) | [Português (Brasil)](README_PT-BR.md) | [한국어](README_KO.md) | [Français](README_FR.md) | [Bahasa Indonesia](README_ID.md) | [Русский](README_RU.md) | [Український](README_UA.md) | **ภาษาไทย** | [Tiếng Việt](README_VI.md) | [Italiano](README_IT.md) | [Polski](README_PL.md) | [Български](README_BG.md) | [日本語](README_JA.md)
|
||||
|
||||
# KernelSU Next
|
||||
|
||||
<img src="/assets/kernelsu_next.png" style="width: 96px;" alt="logo">
|
||||
|
||||
โซลูชั่นรูทบนพื้นฐานเคอร์เนลสำหรับอุปกรณ์ Android
|
||||
|
||||
[](https://github.com/KernelSU-Next/KernelSU-Next/releases/latest)
|
||||
[](https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## คุณสมบัติ
|
||||
|
||||
1. จัดการการเข้าถึงรูท และ `su` บนพื้นฐานเคอร์เนล
|
||||
2. ระบบโมดูลแบบไดนามิกเมานต์ [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS)
|
||||
3. [App Profile](https://kernelsu.org/guide/app-profile.html): จำกัดสิทธิ์เข้าถึงรูทสำหรับแอปต่างๆ
|
||||
|
||||
## การเข้ากันในอุปกรณ์ต่างๆ
|
||||
|
||||
KernelSU Next รองรับแบบเป็นทางการตั้งแต่เคอร์เนลแอนดรอยด์ 4.4 ถึง 6.6
|
||||
- GKI 2.0 (5.10+) เคอร์เนลสามารถรันไฟล์อิมเมจสำเร็จรูป และ LKM/KMI ได้
|
||||
- GKI 1.0 (4.19 - 5.4) เคอร์เนลจะต้องรีบิ้วร่วมกับไดร์เวอร์ของ KernelSU
|
||||
- EOL (<4.14) เคอร์เนลก็ต้องรีบิ้วร่วมกับไดร์เวอร์ของ KernelSU เช่นกัน (3.18+ ยังเป็นเวอร์ชั่นทดลอง และยังต้องเขียนฟังก์ชั่นหลังบ้านเพิ่มเติม)
|
||||
|
||||
ในขณะนี้, มีแค่สถาปัตยกรรม `arm64-v8a`, `armeabi-v7a` & `x86_64` ที่รองรับเท่านั้น
|
||||
|
||||
## การใช้งาน
|
||||
|
||||
- [คำแนะนำในการติดตั้ง](https://ksunext.org/pages/installation.html)
|
||||
|
||||
## ความปลอดภัย
|
||||
|
||||
สำหรับข้อมูลการรายงานช่องโหว่ด้านความปลอดภัยของ KernelSU โปรดดูที่ [SECURITY.md](/SECURITY.md).
|
||||
|
||||
## สัญญาอนุญาต
|
||||
|
||||
- ไฟล์ภายใต้โฟลเดอร์ `kernel` ถือว่าเป็นสัญญาอนุญาต [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||
- ไฟล์ที่นอกเหนือจากโฟลเดอร์ `kernel` ถือว่าเป็นสัญญาอนุญาต [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
|
||||
## การบริจาก
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT BEP20 ]
|
||||
|
||||
- TYUVMWGTcnR5svnDoX85DWHyqUAeyQcdjh [ USDT TRC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT ERC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ ETH ERC20 ]
|
||||
|
||||
- Ld238uYBuRQdZB5YwdbkuU6ektBAAUByoL [ LTC ]
|
||||
|
||||
- 19QgifcjMjSr1wB2DJcea5cxitvWVcXMT6 [ BTC ]
|
||||
|
||||
## เครดิต
|
||||
|
||||
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): ที่เป็นคนริเริ่มไอเดีย KernelSU
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): เครื่องมือรูทที่ทรงพลัง
|
||||
- [genuine](https://github.com/brevent/genuine/): การตรวจสอบลายเซ็น APK v2
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): ความรู้เกี่ยวกับ rootkit
|
||||
- [KernelSU](https://github.com/tiann/KernelSU): ต้องขอบคุณ tiann ไม่งั้นจะไม่มี KernelSU ขึ้นมา
|
||||
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): 💜 5ec1cff ที่ช่วย KernelSU เอาไว้!
|
||||
@@ -1,63 +0,0 @@
|
||||
[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | **Türkçe** | [Português (Brasil)](README_PT-BR.md) | [한국어](README_KO.md) | [Français](README_FR.md) | [Bahasa Indonesia](README_ID.md) | [Русский](README_RU.md) | [Український](README_UA.md) | [ภาษาไทย](README_TH.md) | [Tiếng Việt](README_VI.md) | [Italiano](README_IT.md) | [Polski](README_PL.md) | [Български](README_BG.md) | [日本語](README_JA.md)
|
||||
|
||||
# KernelSU Next
|
||||
|
||||
<img src="/assets/kernelsu_next.png" style="width: 96px;" alt="logo">
|
||||
|
||||
Android cihazlar için çekirdek tabanlı root çözümü.
|
||||
|
||||
[](https://github.com/KernelSU-Next/KernelSU-Next/releases/latest)
|
||||
[](https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## Özellikler
|
||||
|
||||
1. Çekirdek tabanlı `su` ve root erişimi yönetimi.
|
||||
2. Dinamik bağlama sistemi [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) tabanlı modül sistemi.
|
||||
3. [Uygulama Profili](https://kernelsu.org/guide/app-profile.html): Root yetkisini bir kafese kilitleyin.
|
||||
|
||||
## Uyumluluk Durumu
|
||||
|
||||
KernelSU Next, resmi olarak Android çekirdeklerinin çoğunu 4.4 sürümünden 6.6 sürümüne kadar destekler.
|
||||
- GKI 2.0 (5.10+) çekirdekleri, hazır imajları ve LKM/KMI desteğini çalıştırabilir.
|
||||
- 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`, `armeabi-v7a` & `x86_64` mimarisi desteklenmektedir.
|
||||
|
||||
## Kullanım
|
||||
|
||||
- [Kurulum Talimatları](https://ksunext.org/pages/installation.html)
|
||||
|
||||
## Güvenlik
|
||||
|
||||
KernelSU'daki güvenlik açıklarını bildirme hakkında bilgi için bkz: [SECURITY.md](/SECURITY.md)
|
||||
|
||||
## Lisans
|
||||
|
||||
- `kernel` dizinindeki dosyalar [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) lisanslıdır.
|
||||
- `kernel` dizini dışındaki tüm diğer bölümler [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html) lisansı altındadır.
|
||||
|
||||
## Bağışlar
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT BEP20 ]
|
||||
|
||||
- TYUVMWGTcnR5svnDoX85DWHyqUAeyQcdjh [ USDT TRC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT ERC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ ETH ERC20 ]
|
||||
|
||||
- Ld238uYBuRQdZB5YwdbkuU6ektBAAUByoL [ LTC ]
|
||||
|
||||
- 19QgifcjMjSr1wB2DJcea5cxitvWVcXMT6 [ BTC ]
|
||||
|
||||
## Katkıda Bulunanlar
|
||||
|
||||
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): KernelSU fikrinin temeli.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): Güçlü root aracı.
|
||||
- [genuine](https://github.com/brevent/genuine/): APK v2 imza doğrulama.
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): Bazı rootkit teknikleri.
|
||||
- [KernelSU](https://github.com/tiann/KernelSU): tiann'a teşekkürler, KernelSU Next onun sayesinde var.
|
||||
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): 💜 KernelSU'yu kurtardığı için 5ec1cff'e teşekkürler!
|
||||
@@ -1,50 +0,0 @@
|
||||
[English](README.md) | [简体中文](README_CN.md) | **繁體中文** | [Türkçe](README_TR.md) | [Português (Brasil)](README_PT-BR.md) | [한국어](README_KO.md) | [Français](README_FR.md) | [Bahasa Indonesia](README_ID.md) | [Русский](README_RU.md) | [Український](README_UA.md) | [ภาษาไทย](README_TH.md) | [Tiếng Việt](README_VI.md) | [Italiano](README_IT.md) | [Polski](README_PL.md) | [Български](README_BG.md) | [日本語](README_JA.md)
|
||||
|
||||
# KernelSU Next
|
||||
|
||||
<img src="/assets/kernelsu_next.png" style="width: 96px;" alt="logo">
|
||||
|
||||
基於內核的 Android 設備 Root 解決方案
|
||||
|
||||
[](https://github.com/KernelSU-Next/KernelSU-Next/releases/latest)
|
||||
[](https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## 特性
|
||||
|
||||
1. 基於內核的 `su` 和 Root 權限管理
|
||||
2. 基於動態掛載系統 [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) 的模塊系統。
|
||||
3. [App Profile](https://kernelsu.org/zh_CN/guide/app-profile.html):把 Root 權限關進籠子裡
|
||||
|
||||
## 兼容狀態
|
||||
|
||||
KernelSU Next 正式支持大多數從 4.4 到 6.6 的 Android 內核
|
||||
- GKI 2.0 (5.10+) 內核可以運行預構建的映像和 LKM/KMI
|
||||
- GKI 1.0 (4.19 - 5.4) 內核需要重新編譯 KernelSU 驅動程序
|
||||
- EOL (<4.14) 內核也需要重新編譯 KernelSU 驅動程序(3.18+ 是實驗性的,可能需要移植一些功能)
|
||||
|
||||
目前僅支持 `arm64-v8a`, `armeabi-v7a` & `x86_64`
|
||||
|
||||
## 用法
|
||||
|
||||
- [安裝說明](https://ksunext.org/pages/installation.html)
|
||||
|
||||
## 安全性
|
||||
|
||||
有關報告 KernelSU Next 漏洞的信息,請參閱 [SECURITY.md](/SECURITY.md).
|
||||
|
||||
## 許可證
|
||||
|
||||
- 目錄 `kernel` 下所有文件為 [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
- `kernel` 目錄以外的其他部分均為 [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
## 鳴謝
|
||||
|
||||
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): KernelSU 的靈感.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): 強大的 Root 工具.
|
||||
- [genuine](https://github.com/brevent/genuine/): APK v2 簽名驗證。
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): 一些 Rootkit 技巧。
|
||||
- [KernelSU](https://github.com/tiann/KernelSU): 感謝 tiann,否則 KernelSU Next 根本不會存在。
|
||||
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): 💜 5ec1cff 為了拯救 KernelSU!
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [Türkçe](README_TR.md) | [Português (Brasil)](README_PT-BR.md) | [한국어](README_KO.md) | [Français](README_FR.md) | [Bahasa Indonesia](README_ID.md) | [Русский](README_RU.md) | [ภาษาไทย](README_TH.md) | [Tiếng Việt](README_VI.md) | [Italiano](README_IT.md) | [Polski](README_PL.md) | [Български](README_BG.md) | [日本語](README_JA.md) | **Українська**
|
||||
|
||||
# KernelSU Next
|
||||
|
||||
<img src="/assets/kernelsu_next.png" style="width: 96px;" alt="logo">
|
||||
|
||||
Рут-рішення на основі ядра для пристроїв Android.
|
||||
|
||||
[](https://github.com/KernelSU-Next/KernelSU-Next/releases/latest)
|
||||
[](https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## Можливості
|
||||
|
||||
1. `su` на основі ядра та можливість контролювати дозволи руту.
|
||||
2. Module system based on dynamic mount system [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||
3. [Профілі додатків](https://kernelsu.org/guide/app-profile.html): Обмеж права руту для додатків.
|
||||
|
||||
## Compatibility state
|
||||
|
||||
KernelSU Next офіційно підтримує більшість Android ядер починаючи з 4.4 і до 6.6.
|
||||
- Користувачі GKI 2.0 (5.10+) ядра можуть використовувати готові образи та LKM/KMI.
|
||||
- Користувачі GKI 1.0 (4.19 - 5.4) ядра мають бути перезібрані з драйвером KernelSU.
|
||||
- Користувачі EOL (<4.14) ядра також мають бути перезібрані з драйвером KernelSU (Підтримка 3.18+ експерементальна і потребує бекпортів деяких функцій в ядрі).
|
||||
|
||||
На даний момент підтримується лише архітектура `arm64-v8a`, `armeabi-v7a` & `x86_64`.
|
||||
|
||||
## Спосіб використання
|
||||
|
||||
- [Інструкція для встановлення/інтеграції](https://ksunext.org/pages/installation.html)
|
||||
|
||||
## Безпека
|
||||
|
||||
Для інформації зв'язаною з безпекою дивіться [SECURITY.md](/SECURITY.md).
|
||||
|
||||
## Ліцензія
|
||||
|
||||
- Всі файли в директорії `kernel` мають ліцензію [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||
- Всі інші файли виключаючи директорію `kernel` мають ліцензію [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
|
||||
## Підтримка розробника
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT BEP20 ]
|
||||
|
||||
- TYUVMWGTcnR5svnDoX85DWHyqUAeyQcdjh [ USDT TRC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT ERC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ ETH ERC20 ]
|
||||
|
||||
- Ld238uYBuRQdZB5YwdbkuU6ektBAAUByoL [ LTC ]
|
||||
|
||||
- 19QgifcjMjSr1wB2DJcea5cxitvWVcXMT6 [ BTC ]
|
||||
|
||||
## Подяки
|
||||
|
||||
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): Ідея KernelSU.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): Потужний засіб руту.
|
||||
- [genuine](https://github.com/brevent/genuine/): Перевірка підпису APK v2.
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): Деякі руткіт скіли.
|
||||
- [KernelSU](https://github.com/tiann/KernelSU): Дякую tiann, інакше KernelSU Next ніколи б не існував.
|
||||
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): Дякую 💜 5ec1cff за збереження KernelSU!
|
||||
@@ -1,63 +0,0 @@
|
||||
[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [Türkçe](README_TR.md) | [Português (Brasil)](README_PT-BR.md) | [한국어](README_KO.md) | [Français](README_FR.md) | [Bahasa Indonesia](README_ID.md) | [Русский](README_RU.md) | [Український](README_UA.md) | [ภาษาไทย](README_TH.md) | **Tiếng Việt** | [Italiano](README_IT.md) | [Polski](README_PL.md) | [Български](README_BG.md) | [日本語](README_JA.md)
|
||||
|
||||
# KernelSU Next
|
||||
|
||||
<img src="/assets/kernelsu_next.png" style="width: 96px;" alt="logo">
|
||||
|
||||
Một giải pháp root từ nhân linux dành cho các thiết bị chạy Android
|
||||
|
||||
[](https://github.com/KernelSU-Next/KernelSU-Next/releases/latest)
|
||||
[](https://nightly.link/KernelSU-Next/KernelSU-Next/workflows/build-manager-ci/next/Manager)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](/LICENSE)
|
||||
|
||||
## Tính năng
|
||||
|
||||
1. Quản lý quyền truy cập SU dựa trên kernel android.
|
||||
2. Hệ thống mount module dựa trên 1 trong 2 cơ chế mount [Magic Mount](https://topjohnwu.github.io/Magisk/details.html#magic-mount) / [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||
3. [App Profile](https://kernelsu.org/guide/app-profile.html): Quản lý quyền truy cập root 1 cách chặt chẽ
|
||||
|
||||
## Danh sách tương thích
|
||||
|
||||
KernelSU Next hỗ trợ chính thức các kernel Android từ phiên bản 4.4 đến 6.6
|
||||
- GKI 2.0 (5.10+) kernels có thể cài đặt qua những .img/.zip đã được build sẵn và LKM/KMI hoặc tự vá qua manager (nếu được)
|
||||
- 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`, `armeabi-v7a` & `x86_64`
|
||||
|
||||
## Sử dụng
|
||||
|
||||
- [Hướng dẫn vá KernelSU Next vào Kernel của bạn (yêu cầu kernel source)](https://ksunext.org/pages/installation.html)
|
||||
|
||||
## Bảo mật
|
||||
|
||||
Để biết thêm thông tin về việc báo cáo lỗ hổng bảo mật trong KernelSU Next vui lòng đọc (Thông tin sẽ dược gửi về KernelSU)[SECURITY.md](/SECURITY.md).
|
||||
|
||||
## Gíây phép
|
||||
|
||||
- Những thư mục/tập tin trong `kernel` là giấy phép [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||
- Những thư mục/tập tin ngoài `kernel` là giấy phép [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||
|
||||
## Quyên góp/Hỗ trợ
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT BEP20 ]
|
||||
|
||||
- TYUVMWGTcnR5svnDoX85DWHyqUAeyQcdjh [ USDT TRC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ USDT ERC20 ]
|
||||
|
||||
- 0x12b5224b7aca0121c2f003240a901e1d064371c1 [ ETH ERC20 ]
|
||||
|
||||
- Ld238uYBuRQdZB5YwdbkuU6ektBAAUByoL [ LTC ]
|
||||
|
||||
- 19QgifcjMjSr1wB2DJcea5cxitvWVcXMT6 [ BTC ]
|
||||
|
||||
## Lời cảm ơn tới...
|
||||
|
||||
- [Kernel-Assisted Superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): Ý tưởng cho sự ra đời của KernelSU.
|
||||
- [Magisk](https://github.com/topjohnwu/Magisk): Công cụ root mạnh mẽ, quen thuộc và tương thích cao cho các thiết bị chạy Android.
|
||||
- [genuine](https://github.com/brevent/genuine/): Chữ kí apk v2.
|
||||
- [Diamorphine](https://github.com/m0nad/Diamorphine): Một vài kỹ năng rootkit.
|
||||
- [KernelSU](https://github.com/tiann/KernelSU): Nguồn gốc của KernelSU Next, thanks to tiann.
|
||||
- [Magic Mount Port](https://github.com/5ec1cff/KernelSU/blob/main/userspace/ksud/src/magic_mount.rs): 5ec1cff - người đã cứu lấy KernelSU💜 !
|
||||
14
justfile
14
justfile
@@ -1,14 +0,0 @@
|
||||
alias bk := build_ksud
|
||||
alias bm := build_manager
|
||||
|
||||
build_ksud:
|
||||
cross build --target aarch64-linux-android --release --manifest-path ./userspace/ksud/Cargo.toml
|
||||
|
||||
build_manager: build_ksud
|
||||
cp userspace/ksud/target/aarch64-linux-android/release/ksud manager/app/src/main/jniLibs/arm64-v8a/libksud.so
|
||||
cd manager && ./gradlew aDebug
|
||||
|
||||
clippy:
|
||||
cargo fmt --manifest-path ./userspace/ksud/Cargo.toml
|
||||
cross clippy --target x86_64-pc-windows-gnu --release --manifest-path ./userspace/ksud/Cargo.toml
|
||||
cross clippy --target aarch64-linux-android --release --manifest-path ./userspace/ksud/Cargo.toml
|
||||
135
kernel/Kconfig
135
kernel/Kconfig
@@ -40,4 +40,139 @@ config KSU_LSM_SECURITY_HOOKS
|
||||
Disabling this is mostly only useful for kernel 4.1 and older.
|
||||
Make sure to implement manual hooks on security/security.c.
|
||||
|
||||
menu "KernelSU - SUSFS"
|
||||
config KSU_SUSFS
|
||||
bool "KernelSU addon - SUSFS"
|
||||
depends on KSU
|
||||
depends on THREAD_INFO_IN_TASK
|
||||
default y
|
||||
help
|
||||
Patch and Enable SUSFS to kernel with KernelSU.
|
||||
|
||||
config KSU_SUSFS_HAS_MAGIC_MOUNT
|
||||
bool "Say yes if the current KernelSU repo has magic mount implemented (default y)"
|
||||
depends on KSU
|
||||
default y
|
||||
help
|
||||
- Enable to indicate that the current SUSFS kernel supports the auto hide features for 5ec1cff's Magic Mount KernelSU
|
||||
- Every mounts from /debug_ramdisk/workdir will be treated as magic mount and processed differently by susfs
|
||||
|
||||
config KSU_SUSFS_SUS_PATH
|
||||
bool "Enable to hide suspicious path (NOT recommended)"
|
||||
depends on KSU_SUSFS
|
||||
default y
|
||||
help
|
||||
- Allow hiding the user-defined path and all its sub-paths from various system calls.
|
||||
- Includes temp fix for the leaks of app path in /sdcard/Android/data directory.
|
||||
- Effective only on zygote spawned user app process.
|
||||
- Use with cautious as it may cause performance loss and will be vulnerable to side channel attacks,
|
||||
just disable this feature if it doesn't work for you or you don't need it at all.
|
||||
|
||||
config KSU_SUSFS_SUS_MOUNT
|
||||
bool "Enable to hide suspicious mounts"
|
||||
depends on KSU_SUSFS
|
||||
default y
|
||||
help
|
||||
- Allow hiding the user-defined mount paths from /proc/self/[mounts|mountinfo|mountstat].
|
||||
- Effective on all processes for hiding mount entries.
|
||||
- Mounts mounted by process with ksu domain will be forced to be assigned the dev name "KSU".
|
||||
- mnt_id and mnt_group_id of the sus mount will be assigned to a much bigger number to solve the issue of id not being contiguous.
|
||||
|
||||
config KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT
|
||||
bool "Enable to hide KSU's default mounts automatically (experimental)"
|
||||
depends on KSU_SUSFS_SUS_MOUNT
|
||||
default y
|
||||
help
|
||||
- Automatically add KSU's default mounts to sus_mount.
|
||||
- No susfs command is needed in userspace.
|
||||
- Only mount operation from process with ksu domain will be checked.
|
||||
|
||||
config KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT
|
||||
bool "Enable to hide suspicious bind mounts automatically (experimental)"
|
||||
depends on KSU_SUSFS_SUS_MOUNT
|
||||
default y
|
||||
help
|
||||
- Automatically add binded mounts to sus_mount.
|
||||
- No susfs command is needed in userspace.
|
||||
- Only mount operation from process with ksu domain will be checked.
|
||||
|
||||
config KSU_SUSFS_SUS_KSTAT
|
||||
bool "Enable to spoof suspicious kstat"
|
||||
depends on KSU_SUSFS
|
||||
default y
|
||||
help
|
||||
- Allow spoofing the kstat of user-defined file/directory.
|
||||
- Effective only on zygote spawned user app process.
|
||||
|
||||
config KSU_SUSFS_TRY_UMOUNT
|
||||
bool "Enable to use ksu's ksu_try_umount"
|
||||
depends on KSU_SUSFS
|
||||
default y
|
||||
help
|
||||
- Allow using ksu_try_umount to umount other user-defined mount paths prior to ksu's default umount paths.
|
||||
- Effective on all NO-root-access-granted processes.
|
||||
|
||||
config KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT
|
||||
bool "Enable to add bind mounts to ksu's ksu_try_umount automatically (experimental)"
|
||||
depends on KSU_SUSFS_TRY_UMOUNT
|
||||
default y
|
||||
help
|
||||
- Automatically add binded mounts to ksu's ksu_try_umount.
|
||||
- No susfs command is needed in userspace.
|
||||
- Only mount operation from process with ksu domain will be checked.
|
||||
|
||||
config KSU_SUSFS_SPOOF_UNAME
|
||||
bool "Enable to spoof uname"
|
||||
depends on KSU_SUSFS
|
||||
default y
|
||||
help
|
||||
- Allow spoofing the string returned by uname syscall to user-defined string.
|
||||
- Effective on all processes.
|
||||
|
||||
config KSU_SUSFS_ENABLE_LOG
|
||||
bool "Enable logging susfs log to kernel"
|
||||
depends on KSU_SUSFS
|
||||
default y
|
||||
help
|
||||
- Allow logging susfs log to kernel, uncheck it to completely disable all susfs log.
|
||||
|
||||
config KSU_SUSFS_HIDE_KSU_SUSFS_SYMBOLS
|
||||
bool "Enable to automatically hide ksu and susfs symbols from /proc/kallsyms"
|
||||
depends on KSU_SUSFS
|
||||
default y
|
||||
help
|
||||
- Automatically hide ksu and susfs symbols from '/proc/kallsyms'.
|
||||
- Effective on all processes.
|
||||
|
||||
config KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG
|
||||
bool "Enable to spoof /proc/bootconfig (gki) or /proc/cmdline (non-gki)"
|
||||
depends on KSU_SUSFS
|
||||
default y
|
||||
help
|
||||
- Spoof the output of /proc/bootconfig (gki) or /proc/cmdline (non-gki) with a user-defined file.
|
||||
- Effective on all processes.
|
||||
|
||||
config KSU_SUSFS_OPEN_REDIRECT
|
||||
bool "Enable to redirect a path to be opened with another path (experimental)"
|
||||
depends on KSU_SUSFS
|
||||
default y
|
||||
help
|
||||
- Allow redirecting a target path to be opened with another user-defined path.
|
||||
- Effective only on processes with uid < 2000.
|
||||
- Please be reminded that process with open access to the target and redirected path can be detected.
|
||||
|
||||
config KSU_SUSFS_SUS_SU
|
||||
bool "Enable SUS-SU in runtime temporarily"
|
||||
depends on KSU_SUSFS && KPROBES && HAVE_KPROBES && KPROBE_EVENTS && KSU_KPROBES_HOOK
|
||||
default y
|
||||
help
|
||||
- Allow user to enable or disable core ksu kprobes hooks temporarily in runtime. There are 2 working modes for sus_su.
|
||||
- Mode 0 (default): Disable sus_su, and enable ksu kprobe hooks for su instead.
|
||||
- Mode 1 (deprecated):
|
||||
- Mode 2: Enable sus_su, and disable ksu kprobe hooks for su, which means the kernel inline hooks are enabled,
|
||||
the same as the su implementaion of non-gki kernel without kprobe supported.
|
||||
- Only apps with root access granted by ksu manager are allowed to get root.
|
||||
|
||||
endmenu
|
||||
|
||||
endmenu
|
||||
|
||||
152
kernel/Makefile
152
kernel/Makefile
@@ -16,30 +16,7 @@ ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-
|
||||
|
||||
obj-$(CONFIG_KSU) += kernelsu.o
|
||||
|
||||
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
|
||||
|
||||
$(eval KSU_VERSION=12803)
|
||||
$(info -- KernelSU-Next version: $(KSU_VERSION))
|
||||
ccflags-y += -DKSU_VERSION=$(KSU_VERSION)
|
||||
|
||||
@@ -63,12 +40,12 @@ ifeq ($(shell grep "ssize_t kernel_write" $(srctree)/fs/read_write.c | grep -q "
|
||||
ccflags-y += -DKSU_KERNEL_WRITE
|
||||
endif
|
||||
|
||||
ifndef KSU_NEXT_EXPECTED_SIZE
|
||||
KSU_NEXT_EXPECTED_SIZE := 0x3e6
|
||||
ifndef KSU_NEXT_MANAGER_SIZE
|
||||
KSU_NEXT_MANAGER_SIZE := 0x3e6
|
||||
endif
|
||||
|
||||
ifndef KSU_NEXT_EXPECTED_HASH
|
||||
KSU_NEXT_EXPECTED_HASH := 79e590113c4c4c0c222978e413a5faa801666957b1212a328e46c00c69821bf7
|
||||
ifndef KSU_NEXT_MANAGER_HASH
|
||||
KSU_NEXT_MANAGER_HASH := 79e590113c4c4c0c222978e413a5faa801666957b1212a328e46c00c69821bf7
|
||||
endif
|
||||
|
||||
ifdef KSU_MANAGER_PACKAGE
|
||||
@@ -76,48 +53,14 @@ ccflags-y += -DKSU_MANAGER_PACKAGE=\"$(KSU_MANAGER_PACKAGE)\"
|
||||
$(info -- KernelSU-Next Manager package name: $(KSU_MANAGER_PACKAGE))
|
||||
endif
|
||||
|
||||
$(info -- KernelSU-Next Manager signature size: $(KSU_NEXT_EXPECTED_SIZE))
|
||||
$(info -- KernelSU-Next Manager signature hash: $(KSU_NEXT_EXPECTED_HASH))
|
||||
$(info -- KernelSU-Next Manager signature size: $(KSU_NEXT_MANAGER_SIZE))
|
||||
$(info -- KernelSU-Next Manager signature hash: $(KSU_NEXT_MANAGER_HASH))
|
||||
|
||||
ccflags-y += -DEXPECTED_NEXT_SIZE=$(KSU_NEXT_EXPECTED_SIZE)
|
||||
ccflags-y += -DEXPECTED_NEXT_HASH=\"$(KSU_NEXT_EXPECTED_HASH)\"
|
||||
|
||||
ccflags-y += -DKSU_COMPAT_GET_CRED_RCU
|
||||
ccflags-y += -DEXPECTED_MANAGER_SIZE=$(KSU_NEXT_MANAGER_SIZE)
|
||||
ccflags-y += -DEXPECTED_MANAGER_HASH=\"$(KSU_NEXT_MANAGER_HASH)\"
|
||||
|
||||
ccflags-y += -DKSU_UMOUNT
|
||||
|
||||
# Determine the appropriate atomic function and apply patch accordingly
|
||||
ifeq ($(shell grep -q "atomic_inc_not_zero" $(srctree)/kernel/cred.c; echo $$?),0)
|
||||
ATOMIC_INC_FUNC = atomic_inc_not_zero
|
||||
else ifeq ($(shell grep -q "atomic_long_inc_not_zero" $(srctree)/kernel/cred.c; echo $$?),0)
|
||||
ATOMIC_INC_FUNC = atomic_long_inc_not_zero
|
||||
else
|
||||
$(info -- KSU_NEXT: Neither atomic_inc_not_zero nor atomic_long_inc_not_zero found in kernel/cred.c)
|
||||
endif
|
||||
|
||||
# Inform which function is being patched
|
||||
$(info -- KSU_NEXT: Using $(ATOMIC_INC_FUNC) in get_cred_rcu patch.)
|
||||
|
||||
# Add the get_cred_rcu function to cred.h if not already present
|
||||
ifneq ($(shell grep -Eq "^static inline const struct cred \*get_cred_rcu" $(srctree)/include/linux/cred.h; echo $$?),0)
|
||||
$(info -- KSU_NEXT: adding function 'static inline const struct cred *get_cred_rcu(const struct cred *cred);' to $(srctree)/include/linux/cred.h)
|
||||
GET_CRED_RCU = static inline const struct cred *get_cred_rcu(const struct cred *cred)\n\
|
||||
{\n\t\
|
||||
struct cred *nonconst_cred = (struct cred *) cred;\n\t\
|
||||
if (!cred)\n\t\t\
|
||||
return NULL;\n\t\
|
||||
if (!$(ATOMIC_INC_FUNC)(&nonconst_cred->usage))\n\t\t\
|
||||
return NULL;\n\t\
|
||||
validate_creds(cred);\n\t\
|
||||
return cred;\n\
|
||||
}\n
|
||||
$(shell grep -qF "$(GET_CRED_RCU)" $(srctree)/include/linux/cred.h || sed -i '/^static inline void put_cred/i $(GET_CRED_RCU)' $(srctree)/include/linux/cred.h)
|
||||
|
||||
# Modify get_task_cred in cred.c
|
||||
$(info -- KSU_NEXT: modifying 'get_task_cred' function in $(srctree)/kernel/cred.c)
|
||||
$(shell sed -i "s/!$(ATOMIC_INC_FUNC)(&((struct cred \*)cred)->usage)/!get_cred_rcu(cred)/g" $(srctree)/kernel/cred.c)
|
||||
endif
|
||||
|
||||
ifneq ($(shell grep -Eq "^static int can_umount" $(srctree)/fs/namespace.c; echo $$?),0)
|
||||
$(info -- KSU_NEXT: adding function 'static int can_umount(const struct path *path, int flags);' to $(srctree)/fs/namespace.c)
|
||||
CAN_UMOUNT = static int can_umount(const struct path *path, int flags)\n\
|
||||
@@ -164,4 +107,81 @@ endif
|
||||
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
|
||||
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function
|
||||
|
||||
## For non-gki compatiblity ##
|
||||
ifeq ($(shell grep -q " current_sid(void)" $(srctree)/security/selinux/include/objsec.h; echo $$?),0)
|
||||
ccflags-y += -DKSU_COMPAT_HAS_CURRENT_SID
|
||||
endif
|
||||
|
||||
ifeq ($(shell grep -q "struct selinux_state " $(srctree)/security/selinux/include/security.h; echo $$?),0)
|
||||
ccflags-y += -DKSU_COMPAT_HAS_SELINUX_STATE
|
||||
endif
|
||||
|
||||
ccflags-y += -DKSU_UMOUNT
|
||||
ifneq ($(shell grep -Eq "get_cred_rcu" $(srctree)/include/linux/cred.h; echo $$?),0)
|
||||
$(info -- KSU_SUSFS: adding function 'static inline const struct cred *get_cred_rcu();' to $(srctree)/include/linux/cred.h)
|
||||
GET_CRED_RCU = static inline const struct cred *get_cred_rcu(const struct cred *cred)\n\
|
||||
{\n\t\
|
||||
struct cred *nonconst_cred = (struct cred *) cred;\n\t\
|
||||
if (!cred)\n\t\t\
|
||||
return NULL;\n\t\
|
||||
if (!atomic_inc_not_zero(&nonconst_cred->usage))\n\t\t\
|
||||
return NULL;\n\t\
|
||||
validate_creds(cred);\n\t\
|
||||
return cred;\n\
|
||||
}\n
|
||||
$(shell sed -i '/^static inline void put_cred/i $(GET_CRED_RCU)' $(srctree)/include/linux/cred.h;)
|
||||
endif
|
||||
|
||||
ifneq ($(shell grep -Eq "^static int can_umount" $(srctree)/fs/namespace.c; echo $$?),0)
|
||||
$(info -- KSU_SUSFS: adding function 'static int can_umount(const struct path *path, int flags);' to $(srctree)/fs/namespace.c)
|
||||
CAN_UMOUNT = static int can_umount(const struct path *path, int flags)\n\
|
||||
{\n\t\
|
||||
struct mount *mnt = real_mount(path->mnt);\n\t\
|
||||
if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW))\n\t\t\
|
||||
return -EINVAL;\n\t\
|
||||
if (!may_mount())\n\t\t\
|
||||
return -EPERM;\n\t\
|
||||
if (path->dentry != path->mnt->mnt_root)\n\t\t\
|
||||
return -EINVAL;\n\t\
|
||||
if (!check_mnt(mnt))\n\t\t\
|
||||
return -EINVAL;\n\t\
|
||||
if (mnt->mnt.mnt_flags & MNT_LOCKED)\n\t\t\
|
||||
return -EINVAL;\n\t\
|
||||
if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN))\n\t\t\
|
||||
return -EPERM;\n\t\
|
||||
return 0;\n\
|
||||
}\n
|
||||
$(shell sed -i '/^static bool is_mnt_ns_file/i $(CAN_UMOUNT)' $(srctree)/fs/namespace.c;)
|
||||
endif
|
||||
|
||||
ifneq ($(shell grep -Eq "^int path_umount" $(srctree)/fs/namespace.c; echo $$?),0)
|
||||
$(info -- KSU_SUSFS: adding function 'int path_umount(struct path *path, int flags);' to $(srctree)/fs/namespace.c)
|
||||
PATH_UMOUNT = int path_umount(struct path *path, int flags)\n\
|
||||
{\n\t\
|
||||
struct mount *mnt = real_mount(path->mnt);\n\t\
|
||||
int ret;\n\t\
|
||||
ret = can_umount(path, flags);\n\t\
|
||||
if (!ret)\n\t\t\
|
||||
ret = do_umount(mnt, flags);\n\t\
|
||||
dput(path->dentry);\n\t\
|
||||
mntput_no_expire(mnt);\n\t\
|
||||
return ret;\n\
|
||||
}\n
|
||||
$(shell sed -i '/^static bool is_mnt_ns_file/i $(PATH_UMOUNT)' $(srctree)/fs/namespace.c;)
|
||||
endif
|
||||
|
||||
ifneq ($(shell grep -Eq "^int path_umount" $(srctree)/fs/internal.h; echo $$?),0)
|
||||
$(shell sed -i '/^extern void __init mnt_init/a int path_umount(struct path *path, int flags);' $(srctree)/fs/internal.h;)
|
||||
$(info -- KSU_SUSFS: adding 'int path_umount(struct path *path, int flags);' to $(srctree)/fs/internal.h)
|
||||
endif
|
||||
|
||||
## For susfs stuff ##
|
||||
ifeq ($(shell test -e $(srctree)/fs/susfs.c; echo $$?),0)
|
||||
$(eval SUSFS_VERSION=$(shell cat $(srctree)/include/linux/susfs.h | grep -E '^#define SUSFS_VERSION' | cut -d' ' -f3 | sed 's/"//g'))
|
||||
$(info )
|
||||
$(info -- SUSFS_VERSION: $(SUSFS_VERSION))
|
||||
else
|
||||
$(info -- You have not integrate susfs in your kernel.)
|
||||
$(info -- Read: https://gitlab.com/simonpunk/susfs4ksu)
|
||||
endif
|
||||
# Keep a new line here!! Because someone may append config
|
||||
|
||||
@@ -95,7 +95,7 @@ static uint8_t allow_list_bitmap[PAGE_SIZE] __read_mostly __aligned(PAGE_SIZE);
|
||||
static struct work_struct ksu_save_work;
|
||||
static struct work_struct ksu_load_work;
|
||||
|
||||
bool persistent_allow_list(void);
|
||||
static bool persistent_allow_list(void);
|
||||
|
||||
void ksu_show_allow_list(void)
|
||||
{
|
||||
@@ -266,7 +266,7 @@ bool __ksu_is_allow_uid(uid_t uid)
|
||||
|
||||
if (unlikely(uid == 0)) {
|
||||
// already root, but only allow our domain.
|
||||
return is_ksu_domain();
|
||||
return ksu_is_ksu_domain();
|
||||
}
|
||||
|
||||
if (forbid_system_uid(uid)) {
|
||||
@@ -351,7 +351,7 @@ bool ksu_get_allow_list(int *array, int *length, bool allow)
|
||||
return true;
|
||||
}
|
||||
|
||||
void do_save_allow_list(struct work_struct *work)
|
||||
static void do_save_allow_list(struct work_struct *work)
|
||||
{
|
||||
u32 magic = FILE_MAGIC;
|
||||
u32 version = FILE_FORMAT_VERSION;
|
||||
@@ -393,7 +393,7 @@ exit:
|
||||
filp_close(fp, 0);
|
||||
}
|
||||
|
||||
void do_load_allow_list(struct work_struct *work)
|
||||
static void do_load_allow_list(struct work_struct *work)
|
||||
{
|
||||
loff_t off = 0;
|
||||
ssize_t ret = 0;
|
||||
@@ -483,7 +483,7 @@ void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *), void *data
|
||||
}
|
||||
|
||||
// make sure allow list works cross boot
|
||||
bool persistent_allow_list(void)
|
||||
static bool persistent_allow_list(void)
|
||||
{
|
||||
return ksu_queue_work(&ksu_save_work);
|
||||
}
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/version.h>
|
||||
#ifdef CONFIG_KSU_DEBUG
|
||||
#include <linux/moduleparam.h>
|
||||
#endif
|
||||
#include <crypto/hash.h>
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
|
||||
#include <crypto/sha2.h>
|
||||
@@ -19,6 +18,8 @@
|
||||
#include "kernel_compat.h"
|
||||
#include "throne_tracker.h"
|
||||
|
||||
static unsigned int expected_manager_size = EXPECTED_MANAGER_SIZE;
|
||||
static char expected_manager_hash[SHA256_DIGEST_SIZE * 2 + 1] = EXPECTED_MANAGER_HASH;
|
||||
|
||||
struct sdesc {
|
||||
struct shash_desc shash;
|
||||
@@ -313,9 +314,56 @@ static struct kernel_param_ops expected_size_ops = {
|
||||
module_param_cb(ksu_debug_manager_uid, &expected_size_ops,
|
||||
&ksu_debug_manager_uid, S_IRUSR | S_IWUSR);
|
||||
|
||||
#else
|
||||
|
||||
static int set_expected_size(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
int rv = param_set_uint(val, kp);
|
||||
pr_info("expected_manager_size set to %u\n", expected_manager_size);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int get_expected_size(char *buf, const struct kernel_param *kp)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", expected_manager_size);
|
||||
}
|
||||
|
||||
static int set_expected_hash(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
if (strlen(val) != SHA256_DIGEST_SIZE * 2) {
|
||||
pr_err("Invalid hash length: %s\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
strncpy(expected_manager_hash, val, SHA256_DIGEST_SIZE * 2);
|
||||
expected_manager_hash[SHA256_DIGEST_SIZE * 2] = '\0';
|
||||
|
||||
pr_info("expected_manager_hash set to %s\n", expected_manager_hash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_expected_hash(char *buf, const struct kernel_param *kp)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", expected_manager_hash);
|
||||
}
|
||||
|
||||
static struct kernel_param_ops expected_size_ops = {
|
||||
.set = set_expected_size,
|
||||
.get = get_expected_size,
|
||||
};
|
||||
|
||||
static struct kernel_param_ops expected_hash_ops = {
|
||||
.set = set_expected_hash,
|
||||
.get = get_expected_hash,
|
||||
};
|
||||
|
||||
module_param_cb(expected_manager_size, &expected_size_ops, &expected_manager_size, 0644);
|
||||
|
||||
module_param_cb(expected_manager_hash, &expected_hash_ops, &expected_manager_hash, 0644);
|
||||
|
||||
#endif
|
||||
|
||||
bool is_manager_apk(char *path)
|
||||
bool ksu_is_manager_apk(char *path)
|
||||
{
|
||||
int tries = 0;
|
||||
|
||||
@@ -333,5 +381,13 @@ bool is_manager_apk(char *path)
|
||||
return false;
|
||||
}
|
||||
|
||||
return check_v2_signature(path, EXPECTED_NEXT_SIZE, EXPECTED_NEXT_HASH);
|
||||
// set debug info to print size and hash to kernel log
|
||||
pr_info("%s: expected size: %u, expected hash: %s\n",
|
||||
path, expected_manager_size, expected_manager_hash);
|
||||
|
||||
#ifdef CONFIG_KSU_DEBUG
|
||||
return check_v2_signature(path, EXPECTED_MANAGER_SIZE, EXPECTED_MANAGER_HASH);
|
||||
#else
|
||||
return check_v2_signature(path, expected_manager_size, expected_manager_hash);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
bool is_manager_apk(char *path);
|
||||
bool ksu_is_manager_apk(char *path);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -35,6 +35,10 @@
|
||||
#include <linux/vmalloc.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KSU_SUSFS
|
||||
#include <linux/susfs.h>
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS
|
||||
|
||||
#include "allowlist.h"
|
||||
#include "arch.h"
|
||||
#include "core_hook.h"
|
||||
@@ -44,24 +48,91 @@
|
||||
#include "manager.h"
|
||||
#include "selinux/selinux.h"
|
||||
#include "throne_tracker.h"
|
||||
#include "throne_tracker.h"
|
||||
#include "kernel_compat.h"
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) || defined(KSU_COMPAT_GET_CRED_RCU)
|
||||
#define KSU_GET_CRED_RCU
|
||||
#ifdef CONFIG_KSU_SUSFS
|
||||
bool susfs_is_allow_su(void)
|
||||
{
|
||||
if (ksu_is_manager()) {
|
||||
// we are manager, allow!
|
||||
return true;
|
||||
}
|
||||
return ksu_is_allow_uid(current_uid().val);
|
||||
}
|
||||
|
||||
extern u32 susfs_zygote_sid;
|
||||
extern bool susfs_is_mnt_devname_ksu(struct path *path);
|
||||
#ifdef CONFIG_KSU_SUSFS_ENABLE_LOG
|
||||
extern bool susfs_is_log_enabled __read_mostly;
|
||||
#endif
|
||||
#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT
|
||||
extern void susfs_run_try_umount_for_current_mnt_ns(void);
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||
static bool susfs_is_umount_for_zygote_system_process_enabled = false;
|
||||
static bool susfs_is_umount_for_zygote_iso_service_enabled = false;
|
||||
extern bool susfs_hide_sus_mnts_for_all_procs;
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||
#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT
|
||||
extern bool susfs_is_auto_add_sus_bind_mount_enabled;
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT
|
||||
#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT
|
||||
extern bool susfs_is_auto_add_sus_ksu_default_mount_enabled;
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT
|
||||
#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT
|
||||
extern bool susfs_is_auto_add_try_umount_for_bind_mount_enabled;
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
extern bool susfs_is_sus_su_ready;
|
||||
extern int susfs_sus_su_working_mode;
|
||||
extern bool susfs_is_sus_su_hooks_enabled __read_mostly;
|
||||
extern bool ksu_devpts_hook;
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
|
||||
static inline void susfs_on_post_fs_data(void) {
|
||||
struct path path;
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||
if (!kern_path(DATA_ADB_UMOUNT_FOR_ZYGOTE_SYSTEM_PROCESS, 0, &path)) {
|
||||
susfs_is_umount_for_zygote_system_process_enabled = true;
|
||||
path_put(&path);
|
||||
}
|
||||
pr_info("susfs_is_umount_for_zygote_system_process_enabled: %d\n", susfs_is_umount_for_zygote_system_process_enabled);
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||
#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT
|
||||
if (!kern_path(DATA_ADB_NO_AUTO_ADD_SUS_BIND_MOUNT, 0, &path)) {
|
||||
susfs_is_auto_add_sus_bind_mount_enabled = false;
|
||||
path_put(&path);
|
||||
}
|
||||
pr_info("susfs_is_auto_add_sus_bind_mount_enabled: %d\n", susfs_is_auto_add_sus_bind_mount_enabled);
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT
|
||||
#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT
|
||||
if (!kern_path(DATA_ADB_NO_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT, 0, &path)) {
|
||||
susfs_is_auto_add_sus_ksu_default_mount_enabled = false;
|
||||
path_put(&path);
|
||||
}
|
||||
pr_info("susfs_is_auto_add_sus_ksu_default_mount_enabled: %d\n", susfs_is_auto_add_sus_ksu_default_mount_enabled);
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT
|
||||
#ifdef CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT
|
||||
if (!kern_path(DATA_ADB_NO_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT, 0, &path)) {
|
||||
susfs_is_auto_add_try_umount_for_bind_mount_enabled = false;
|
||||
path_put(&path);
|
||||
}
|
||||
pr_info("susfs_is_auto_add_try_umount_for_bind_mount_enabled: %d\n", susfs_is_auto_add_try_umount_for_bind_mount_enabled);
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT
|
||||
}
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS
|
||||
|
||||
static bool ksu_module_mounted = false;
|
||||
|
||||
extern int handle_sepolicy(unsigned long arg3, void __user *arg4);
|
||||
extern int ksu_handle_sepolicy(unsigned long arg3, void __user *arg4);
|
||||
|
||||
static bool ksu_su_compat_enabled = true;
|
||||
bool ksu_su_compat_enabled = true;
|
||||
extern void ksu_sucompat_init();
|
||||
extern void ksu_sucompat_exit();
|
||||
|
||||
static inline bool is_allow_su()
|
||||
{
|
||||
if (is_manager()) {
|
||||
if (ksu_is_manager()) {
|
||||
// we are manager, allow!
|
||||
return true;
|
||||
}
|
||||
@@ -139,7 +210,7 @@ static void disable_seccomp(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
void escape_to_root(void)
|
||||
void ksu_escape_to_root(void)
|
||||
{
|
||||
struct cred *cred;
|
||||
|
||||
@@ -197,7 +268,7 @@ void escape_to_root(void)
|
||||
disable_seccomp();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
setup_selinux(profile->selinux_domain);
|
||||
ksu_setup_selinux(profile->selinux_domain);
|
||||
}
|
||||
|
||||
int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry)
|
||||
@@ -234,7 +305,7 @@ int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry)
|
||||
pr_info("renameat: %s -> %s, new path: %s\n", old_dentry->d_iname,
|
||||
new_dentry->d_iname, buf);
|
||||
|
||||
track_throne();
|
||||
ksu_track_throne();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -279,7 +350,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
}
|
||||
|
||||
bool from_root = 0 == current_uid().val;
|
||||
bool from_manager = is_manager();
|
||||
bool from_manager = ksu_is_manager();
|
||||
|
||||
if (!from_root && !from_manager) {
|
||||
// only root or manager can access this interface
|
||||
@@ -303,7 +374,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
if (arg2 == CMD_GRANT_ROOT) {
|
||||
if (is_allow_su()) {
|
||||
pr_info("allow root for: %d\n", current_uid().val);
|
||||
escape_to_root();
|
||||
ksu_escape_to_root();
|
||||
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
|
||||
pr_err("grant_root: prctl reply error\n");
|
||||
}
|
||||
@@ -328,6 +399,17 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg2 == CMD_GET_MANAGER_UID) {
|
||||
uid_t manager_uid = ksu_get_manager_uid();
|
||||
if (copy_to_user(arg3, &manager_uid, sizeof(manager_uid))) {
|
||||
pr_err("get manager uid failed\n");
|
||||
}
|
||||
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
|
||||
pr_err("prctl reply error, cmd: %lu\n", arg2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg2 == CMD_HOOK_MODE) {
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
const char *mode = "Kprobes";
|
||||
@@ -347,10 +429,13 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
switch (arg3) {
|
||||
case EVENT_POST_FS_DATA: {
|
||||
static bool post_fs_data_lock = false;
|
||||
#ifdef CONFIG_KSU_SUSFS
|
||||
susfs_on_post_fs_data();
|
||||
#endif
|
||||
if (!post_fs_data_lock) {
|
||||
post_fs_data_lock = true;
|
||||
pr_info("post-fs-data triggered\n");
|
||||
on_post_fs_data();
|
||||
ksu_on_post_fs_data();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -378,7 +463,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
if (!from_root) {
|
||||
return 0;
|
||||
}
|
||||
if (!handle_sepolicy(arg3, arg4)) {
|
||||
if (!ksu_handle_sepolicy(arg3, arg4)) {
|
||||
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
|
||||
pr_err("sepolicy: prctl reply error\n");
|
||||
}
|
||||
@@ -439,6 +524,352 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KSU_SUSFS
|
||||
if (current_uid_val == 0) {
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||
if (arg2 == CMD_SUSFS_ADD_SUS_PATH) {
|
||||
int error = 0;
|
||||
if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_sus_path))) {
|
||||
pr_err("susfs: CMD_SUSFS_ADD_SUS_PATH -> arg3 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_access_ok((void __user*)arg5, sizeof(error))) {
|
||||
pr_err("susfs: CMD_SUSFS_ADD_SUS_PATH -> arg5 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
error = susfs_add_sus_path((struct st_susfs_sus_path __user*)arg3);
|
||||
pr_info("susfs: CMD_SUSFS_ADD_SUS_PATH -> ret: %d\n", error);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
if (arg2 == CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH) {
|
||||
int error = 0;
|
||||
if (!ksu_access_ok((void __user*)arg3, SUSFS_MAX_LEN_PATHNAME)) {
|
||||
pr_err("susfs: CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH -> arg3 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_access_ok((void __user*)arg5, sizeof(error))) {
|
||||
pr_err("susfs: CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH -> arg5 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
error = susfs_set_i_state_on_external_dir((char __user*)arg3, CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH);
|
||||
pr_info("susfs: CMD_SUSFS_SET_ANDROID_DATA_ROOT_PATH -> ret: %d\n", error);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
if (arg2 == CMD_SUSFS_SET_SDCARD_ROOT_PATH) {
|
||||
int error = 0;
|
||||
if (!ksu_access_ok((void __user*)arg3, SUSFS_MAX_LEN_PATHNAME)) {
|
||||
pr_err("susfs: CMD_SUSFS_SET_SDCARD_ROOT_PATH -> arg3 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_access_ok((void __user*)arg5, sizeof(error))) {
|
||||
pr_err("susfs: CMD_SUSFS_SET_SDCARD_ROOT_PATH -> arg5 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
error = susfs_set_i_state_on_external_dir((char __user*)arg3, CMD_SUSFS_SET_SDCARD_ROOT_PATH);
|
||||
pr_info("susfs: CMD_SUSFS_SET_SDCARD_ROOT_PATH -> ret: %d\n", error);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
#endif //#ifdef CONFIG_KSU_SUSFS_SUS_PATH
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||
if (arg2 == CMD_SUSFS_ADD_SUS_MOUNT) {
|
||||
int error = 0;
|
||||
if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_sus_mount))) {
|
||||
pr_err("susfs: CMD_SUSFS_ADD_SUS_MOUNT -> arg3 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_access_ok((void __user*)arg5, sizeof(error))) {
|
||||
pr_err("susfs: CMD_SUSFS_ADD_SUS_MOUNT -> arg5 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
error = susfs_add_sus_mount((struct st_susfs_sus_mount __user*)arg3);
|
||||
pr_info("susfs: CMD_SUSFS_ADD_SUS_MOUNT -> ret: %d\n", error);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
if (arg2 == CMD_SUSFS_HIDE_SUS_MNTS_FOR_ALL_PROCS) {
|
||||
int error = 0;
|
||||
if (arg3 != 0 && arg3 != 1) {
|
||||
pr_err("susfs: CMD_SUSFS_HIDE_SUS_MNTS_FOR_ALL_PROCS -> arg3 can only be 0 or 1\n");
|
||||
return 0;
|
||||
}
|
||||
susfs_hide_sus_mnts_for_all_procs = arg3;
|
||||
pr_info("susfs: CMD_SUSFS_HIDE_SUS_MNTS_FOR_ALL_PROCS -> susfs_hide_sus_mnts_for_all_procs: %lu\n", arg3);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
if (arg2 == CMD_SUSFS_UMOUNT_FOR_ZYGOTE_ISO_SERVICE) {
|
||||
int error = 0;
|
||||
if (arg3 != 0 && arg3 != 1) {
|
||||
pr_err("susfs: CMD_SUSFS_UMOUNT_FOR_ZYGOTE_ISO_SERVICE -> arg3 can only be 0 or 1\n");
|
||||
return 0;
|
||||
}
|
||||
susfs_is_umount_for_zygote_iso_service_enabled = arg3;
|
||||
pr_info("susfs: CMD_SUSFS_UMOUNT_FOR_ZYGOTE_ISO_SERVICE -> susfs_is_umount_for_zygote_iso_service_enabled: %lu\n", arg3);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
#endif //#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT
|
||||
if (arg2 == CMD_SUSFS_ADD_SUS_KSTAT) {
|
||||
int error = 0;
|
||||
if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_sus_kstat))) {
|
||||
pr_err("susfs: CMD_SUSFS_ADD_SUS_KSTAT -> arg3 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_access_ok((void __user*)arg5, sizeof(error))) {
|
||||
pr_err("susfs: CMD_SUSFS_ADD_SUS_KSTAT -> arg5 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
error = susfs_add_sus_kstat((struct st_susfs_sus_kstat __user*)arg3);
|
||||
pr_info("susfs: CMD_SUSFS_ADD_SUS_KSTAT -> ret: %d\n", error);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
if (arg2 == CMD_SUSFS_UPDATE_SUS_KSTAT) {
|
||||
int error = 0;
|
||||
if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_sus_kstat))) {
|
||||
pr_err("susfs: CMD_SUSFS_UPDATE_SUS_KSTAT -> arg3 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_access_ok((void __user*)arg5, sizeof(error))) {
|
||||
pr_err("susfs: CMD_SUSFS_UPDATE_SUS_KSTAT -> arg5 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
error = susfs_update_sus_kstat((struct st_susfs_sus_kstat __user*)arg3);
|
||||
pr_info("susfs: CMD_SUSFS_UPDATE_SUS_KSTAT -> ret: %d\n", error);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
if (arg2 == CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY) {
|
||||
int error = 0;
|
||||
if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_sus_kstat))) {
|
||||
pr_err("susfs: CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY -> arg3 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_access_ok((void __user*)arg5, sizeof(error))) {
|
||||
pr_err("susfs: CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY -> arg5 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
error = susfs_add_sus_kstat((struct st_susfs_sus_kstat __user*)arg3);
|
||||
pr_info("susfs: CMD_SUSFS_ADD_SUS_KSTAT_STATICALLY -> ret: %d\n", error);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
#endif //#ifdef CONFIG_KSU_SUSFS_SUS_KSTAT
|
||||
#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT
|
||||
if (arg2 == CMD_SUSFS_ADD_TRY_UMOUNT) {
|
||||
int error = 0;
|
||||
if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_try_umount))) {
|
||||
pr_err("susfs: CMD_SUSFS_ADD_TRY_UMOUNT -> arg3 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_access_ok((void __user*)arg5, sizeof(error))) {
|
||||
pr_err("susfs: CMD_SUSFS_ADD_TRY_UMOUNT -> arg5 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
error = susfs_add_try_umount((struct st_susfs_try_umount __user*)arg3);
|
||||
pr_info("susfs: CMD_SUSFS_ADD_TRY_UMOUNT -> ret: %d\n", error);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
if (arg2 == CMD_SUSFS_RUN_UMOUNT_FOR_CURRENT_MNT_NS) {
|
||||
int error = 0;
|
||||
susfs_run_try_umount_for_current_mnt_ns();
|
||||
pr_info("susfs: CMD_SUSFS_RUN_UMOUNT_FOR_CURRENT_MNT_NS -> ret: %d\n", error);
|
||||
}
|
||||
#endif //#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT
|
||||
#ifdef CONFIG_KSU_SUSFS_SPOOF_UNAME
|
||||
if (arg2 == CMD_SUSFS_SET_UNAME) {
|
||||
int error = 0;
|
||||
if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_uname))) {
|
||||
pr_err("susfs: CMD_SUSFS_SET_UNAME -> arg3 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_access_ok((void __user*)arg5, sizeof(error))) {
|
||||
pr_err("susfs: CMD_SUSFS_SET_UNAME -> arg5 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
error = susfs_set_uname((struct st_susfs_uname __user*)arg3);
|
||||
pr_info("susfs: CMD_SUSFS_SET_UNAME -> ret: %d\n", error);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
#endif //#ifdef CONFIG_KSU_SUSFS_SPOOF_UNAME
|
||||
#ifdef CONFIG_KSU_SUSFS_ENABLE_LOG
|
||||
if (arg2 == CMD_SUSFS_ENABLE_LOG) {
|
||||
int error = 0;
|
||||
if (arg3 != 0 && arg3 != 1) {
|
||||
pr_err("susfs: CMD_SUSFS_ENABLE_LOG -> arg3 can only be 0 or 1\n");
|
||||
return 0;
|
||||
}
|
||||
susfs_set_log(arg3);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
#endif //#ifdef CONFIG_KSU_SUSFS_ENABLE_LOG
|
||||
#ifdef CONFIG_KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG
|
||||
if (arg2 == CMD_SUSFS_SET_CMDLINE_OR_BOOTCONFIG) {
|
||||
int error = 0;
|
||||
if (!ksu_access_ok((void __user*)arg3, SUSFS_FAKE_CMDLINE_OR_BOOTCONFIG_SIZE)) {
|
||||
pr_err("susfs: CMD_SUSFS_SET_CMDLINE_OR_BOOTCONFIG -> arg3 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_access_ok((void __user*)arg5, sizeof(error))) {
|
||||
pr_err("susfs: CMD_SUSFS_SET_CMDLINE_OR_BOOTCONFIG -> arg5 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
error = susfs_set_cmdline_or_bootconfig((char __user*)arg3);
|
||||
pr_info("susfs: CMD_SUSFS_SET_CMDLINE_OR_BOOTCONFIG -> ret: %d\n", error);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
#endif //#ifdef CONFIG_KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG
|
||||
#ifdef CONFIG_KSU_SUSFS_OPEN_REDIRECT
|
||||
if (arg2 == CMD_SUSFS_ADD_OPEN_REDIRECT) {
|
||||
int error = 0;
|
||||
if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_susfs_open_redirect))) {
|
||||
pr_err("susfs: CMD_SUSFS_ADD_OPEN_REDIRECT -> arg3 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_access_ok((void __user*)arg5, sizeof(error))) {
|
||||
pr_err("susfs: CMD_SUSFS_ADD_OPEN_REDIRECT -> arg5 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
error = susfs_add_open_redirect((struct st_susfs_open_redirect __user*)arg3);
|
||||
pr_info("susfs: CMD_SUSFS_ADD_OPEN_REDIRECT -> ret: %d\n", error);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
#endif //#ifdef CONFIG_KSU_SUSFS_OPEN_REDIRECT
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
if (arg2 == CMD_SUSFS_SUS_SU) {
|
||||
int error = 0;
|
||||
if (!ksu_access_ok((void __user*)arg3, sizeof(struct st_sus_su))) {
|
||||
pr_err("susfs: CMD_SUSFS_SUS_SU -> arg3 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_access_ok((void __user*)arg5, sizeof(error))) {
|
||||
pr_err("susfs: CMD_SUSFS_SUS_SU -> arg5 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
error = susfs_sus_su((struct st_sus_su __user*)arg3);
|
||||
pr_info("susfs: CMD_SUSFS_SUS_SU -> ret: %d\n", error);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
#endif //#ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
if (arg2 == CMD_SUSFS_SHOW_VERSION) {
|
||||
int error = 0;
|
||||
int len_of_susfs_version = strlen(SUSFS_VERSION);
|
||||
char *susfs_version = SUSFS_VERSION;
|
||||
if (!ksu_access_ok((void __user*)arg3, len_of_susfs_version+1)) {
|
||||
pr_err("susfs: CMD_SUSFS_SHOW_VERSION -> arg3 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_access_ok((void __user*)arg5, sizeof(error))) {
|
||||
pr_err("susfs: CMD_SUSFS_SHOW_VERSION -> arg5 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
error = copy_to_user((void __user*)arg3, (void*)susfs_version, len_of_susfs_version+1);
|
||||
pr_info("susfs: CMD_SUSFS_SHOW_VERSION -> ret: %d\n", error);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
if (arg2 == CMD_SUSFS_SHOW_ENABLED_FEATURES) {
|
||||
int error = 0;
|
||||
if (arg4 <= 0) {
|
||||
pr_err("susfs: CMD_SUSFS_SHOW_ENABLED_FEATURES -> arg4 cannot be <= 0\n");
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_access_ok((void __user*)arg3, arg4)) {
|
||||
pr_err("susfs: CMD_SUSFS_SHOW_ENABLED_FEATURES -> arg3 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_access_ok((void __user*)arg5, sizeof(error))) {
|
||||
pr_err("susfs: CMD_SUSFS_SHOW_ENABLED_FEATURES -> arg5 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
error = susfs_get_enabled_features((char __user*)arg3, arg4);
|
||||
pr_info("susfs: CMD_SUSFS_SHOW_ENABLED_FEATURES -> ret: %d\n", error);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
if (arg2 == CMD_SUSFS_SHOW_VARIANT) {
|
||||
int error = 0;
|
||||
int len_of_variant = strlen(SUSFS_VARIANT);
|
||||
char *susfs_variant = SUSFS_VARIANT;
|
||||
if (!ksu_access_ok((void __user*)arg3, len_of_variant+1)) {
|
||||
pr_err("susfs: CMD_SUSFS_SHOW_VARIANT -> arg3 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_access_ok((void __user*)arg5, sizeof(error))) {
|
||||
pr_err("susfs: CMD_SUSFS_SHOW_VARIANT -> arg5 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
error = copy_to_user((void __user*)arg3, (void*)susfs_variant, len_of_variant+1);
|
||||
pr_info("susfs: CMD_SUSFS_SHOW_VARIANT -> ret: %d\n", error);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
if (arg2 == CMD_SUSFS_IS_SUS_SU_READY) {
|
||||
int error = 0;
|
||||
if (!ksu_access_ok((void __user*)arg3, sizeof(susfs_is_sus_su_ready))) {
|
||||
pr_err("susfs: CMD_SUSFS_IS_SUS_SU_READY -> arg3 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_access_ok((void __user*)arg5, sizeof(error))) {
|
||||
pr_err("susfs: CMD_SUSFS_IS_SUS_SU_READY -> arg5 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
error = copy_to_user((void __user*)arg3, (void*)&susfs_is_sus_su_ready, sizeof(susfs_is_sus_su_ready));
|
||||
pr_info("susfs: CMD_SUSFS_IS_SUS_SU_READY -> ret: %d\n", error);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
if (arg2 == CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE) {
|
||||
int error = 0;
|
||||
int working_mode = susfs_get_sus_su_working_mode();
|
||||
if (!ksu_access_ok((void __user*)arg3, sizeof(working_mode))) {
|
||||
pr_err("susfs: CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE -> arg3 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_access_ok((void __user*)arg5, sizeof(error))) {
|
||||
pr_err("susfs: CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE -> arg5 is not accessible\n");
|
||||
return 0;
|
||||
}
|
||||
error = copy_to_user((void __user*)arg3, (void*)&working_mode, sizeof(working_mode));
|
||||
pr_info("susfs: CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE -> ret: %d\n", error);
|
||||
if (copy_to_user((void __user*)arg5, &error, sizeof(error)))
|
||||
pr_info("susfs: copy_to_user() failed\n");
|
||||
return 0;
|
||||
}
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
}
|
||||
#endif //#ifdef CONFIG_KSU_SUSFS
|
||||
|
||||
// all other cmds are for 'root manager'
|
||||
if (!from_manager) {
|
||||
return 0;
|
||||
@@ -504,6 +935,12 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
// We disable all sus_su hook whenever user toggle on su_kps
|
||||
susfs_is_sus_su_hooks_enabled = false;
|
||||
ksu_devpts_hook = false;
|
||||
susfs_sus_su_working_mode = SUS_SU_DISABLED;
|
||||
#endif
|
||||
ksu_sucompat_init();
|
||||
} else {
|
||||
ksu_sucompat_exit();
|
||||
@@ -542,11 +979,15 @@ static bool should_umount(struct path *path)
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KSU_SUSFS
|
||||
return susfs_is_mnt_devname_ksu(path);
|
||||
#else
|
||||
if (path->mnt && path->mnt->mnt_sb && path->mnt->mnt_sb->s_type) {
|
||||
const char *fstype = path->mnt->mnt_sb->s_type->name;
|
||||
return strcmp(fstype, "overlay") == 0;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int ksu_umount_mnt(struct path *path, int flags)
|
||||
@@ -559,7 +1000,11 @@ static int ksu_umount_mnt(struct path *path, int flags)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void try_umount(const char *mnt, bool check_mnt, int flags)
|
||||
#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT
|
||||
void ksu_try_umount(const char *mnt, bool check_mnt, int flags, uid_t uid)
|
||||
#else
|
||||
static void ksu_try_umount(const char *mnt, bool check_mnt, int flags)
|
||||
#endif
|
||||
{
|
||||
struct path path;
|
||||
int err = kern_path(mnt, 0, &path);
|
||||
@@ -579,12 +1024,46 @@ static void try_umount(const char *mnt, bool check_mnt, int flags)
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_KSU_SUSFS_TRY_UMOUNT) && defined(CONFIG_KSU_SUSFS_ENABLE_LOG)
|
||||
if (susfs_is_log_enabled) {
|
||||
pr_info("susfs: umounting '%s' for uid: %d\n", mnt, uid);
|
||||
}
|
||||
#endif
|
||||
|
||||
err = ksu_umount_mnt(&path, flags);
|
||||
if (err) {
|
||||
pr_warn("umount %s failed: %d\n", mnt, err);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT
|
||||
void susfs_try_umount_all(uid_t uid) {
|
||||
susfs_try_umount(uid);
|
||||
/* For Legacy KSU only */
|
||||
ksu_try_umount("/system", true, 0, uid);
|
||||
ksu_try_umount("/system_ext", true, 0, uid);
|
||||
ksu_try_umount("/vendor", true, 0, uid);
|
||||
ksu_try_umount("/product", true, 0, uid);
|
||||
ksu_try_umount("/odm", true, 0, uid);
|
||||
// - For '/data/adb/modules' we pass 'false' here because it is a loop device that we can't determine whether
|
||||
// its dev_name is KSU or not, and it is safe to just umount it if it is really a mountpoint
|
||||
ksu_try_umount("/data/adb/modules", false, MNT_DETACH, uid);
|
||||
/* For both Legacy KSU and Magic Mount KSU */
|
||||
ksu_try_umount("/debug_ramdisk", true, MNT_DETACH, uid);
|
||||
|
||||
// try umount ksu temp path
|
||||
ksu_try_umount("/sbin", false, MNT_DETACH, uid);
|
||||
|
||||
// try umount hosts file
|
||||
ksu_try_umount("/system/etc/hosts", false, MNT_DETACH, uid);
|
||||
|
||||
// try umount lsposed dex2oat bins
|
||||
ksu_try_umount("/apex/com.android.art/bin/dex2oat64", false, MNT_DETACH, uid);
|
||||
ksu_try_umount("/apex/com.android.art/bin/dex2oat32", false, MNT_DETACH, uid);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int ksu_handle_setuid(struct cred *new, const struct cred *old)
|
||||
{
|
||||
// this hook is used for umounting overlayfs for some uid, if there isn't any module mounted, just ignore it!
|
||||
@@ -604,6 +1083,52 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KSU_SUSFS
|
||||
// check if current process is zygote
|
||||
bool is_zygote_child = susfs_is_sid_equal(old->security, susfs_zygote_sid);
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS
|
||||
if (likely(is_zygote_child)) {
|
||||
// if spawned process is non user app process
|
||||
if (unlikely(new_uid.val < 10000 && new_uid.val >= 1000)) {
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
// set flag if zygote spawned system process is allowed for root access
|
||||
if (!ksu_is_allow_uid(new_uid.val)) {
|
||||
task_lock(current);
|
||||
susfs_set_current_proc_su_not_allowed();
|
||||
task_unlock(current);
|
||||
}
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||
// umount for the system process if path DATA_ADB_UMOUNT_FOR_ZYGOTE_SYSTEM_PROCESS exists
|
||||
if (susfs_is_umount_for_zygote_system_process_enabled) {
|
||||
goto out_ksu_try_umount;
|
||||
}
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||
}
|
||||
#ifdef CONFIG_KSU_SUSFS
|
||||
// - here we check if uid is a isolated service spawned by zygote directly
|
||||
// - Apps that do not use "useAppZyogte" to start a isolated service will be directly
|
||||
// spawned by zygote which KSU will ignore it by default, the only fix for now is to
|
||||
// force a umount for those uid
|
||||
// - Therefore make sure your root app doesn't use isolated service for root access
|
||||
// - Kudos to ThePedroo, the author and maintainer of Rezygisk for finding and reporting
|
||||
// the detection, really big helps here!
|
||||
else if (new_uid.val >= 90000 && new_uid.val < 1000000) {
|
||||
task_lock(current);
|
||||
susfs_set_current_non_root_user_app_proc();
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
susfs_set_current_proc_su_not_allowed();
|
||||
#endif
|
||||
task_unlock(current);
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||
if (susfs_is_umount_for_zygote_iso_service_enabled) {
|
||||
goto out_susfs_try_umount_all;
|
||||
}
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||
}
|
||||
}
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS
|
||||
|
||||
if (!is_appuid(new_uid) || is_unsupported_uid(new_uid.val)) {
|
||||
// pr_info("handle setuid ignore non application or isolated uid: %d\n", new_uid.val);
|
||||
return 0;
|
||||
@@ -613,7 +1138,20 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
|
||||
// pr_info("handle setuid ignore allowed application: %d\n", new_uid.val);
|
||||
return 0;
|
||||
}
|
||||
#ifdef CONFIG_KSU_SUSFS
|
||||
else {
|
||||
task_lock(current);
|
||||
susfs_set_current_non_root_user_app_proc();
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
susfs_set_current_proc_su_not_allowed();
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
task_unlock(current);
|
||||
}
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS
|
||||
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||
out_ksu_try_umount:
|
||||
#endif
|
||||
if (!ksu_uid_should_umount(new_uid.val)) {
|
||||
return 0;
|
||||
} else {
|
||||
@@ -622,10 +1160,12 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef CONFIG_KSU_SUSFS
|
||||
// check old process's selinux context, if it is not zygote, ignore it!
|
||||
// because some su apps may setuid to untrusted_app but they are in global mount namespace
|
||||
// when we umount for such process, that is a disaster!
|
||||
bool is_zygote_child = is_zygote(old->security);
|
||||
bool is_zygote_child = ksu_is_zygote(old->security);
|
||||
#endif
|
||||
if (!is_zygote_child) {
|
||||
pr_info("handle umount ignore non zygote child: %d\n",
|
||||
current->pid);
|
||||
@@ -637,25 +1177,31 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
|
||||
current->pid);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KSU_SUSFS_TRY_UMOUNT
|
||||
out_susfs_try_umount_all:
|
||||
// susfs come first, and lastly umount by ksu, make sure umount in reversed order
|
||||
susfs_try_umount_all(new_uid.val);
|
||||
#else
|
||||
// fixme: use `collect_mounts` and `iterate_mount` to iterate all mountpoint and
|
||||
// filter the mountpoint whose target is `/data/adb`
|
||||
try_umount("/odm", true, 0);
|
||||
try_umount("/system", true, 0);
|
||||
try_umount("/system_ext", true, 0);
|
||||
try_umount("/vendor", true, 0);
|
||||
try_umount("/product", true, 0);
|
||||
try_umount("/data/adb/modules", false, MNT_DETACH);
|
||||
ksu_try_umount("/odm", true, 0);
|
||||
ksu_try_umount("/system", true, 0);
|
||||
ksu_try_umount("/system_ext", true, 0);
|
||||
ksu_try_umount("/vendor", true, 0);
|
||||
ksu_try_umount("/product", true, 0);
|
||||
ksu_try_umount("/data/adb/modules", false, MNT_DETACH);
|
||||
|
||||
// try umount ksu temp path
|
||||
try_umount("/debug_ramdisk", false, MNT_DETACH);
|
||||
try_umount("/sbin", false, MNT_DETACH);
|
||||
ksu_try_umount("/debug_ramdisk", false, MNT_DETACH);
|
||||
ksu_try_umount("/sbin", false, MNT_DETACH);
|
||||
|
||||
// try umount hosts file
|
||||
try_umount("/system/etc/hosts", false, MNT_DETACH);
|
||||
ksu_try_umount("/system/etc/hosts", false, MNT_DETACH);
|
||||
|
||||
// try umount lsposed dex2oat bins
|
||||
try_umount("/apex/com.android.art/bin/dex2oat64", false, MNT_DETACH);
|
||||
try_umount("/apex/com.android.art/bin/dex2oat32", false, MNT_DETACH);
|
||||
ksu_try_umount("/apex/com.android.art/bin/dex2oat64", false, MNT_DETACH);
|
||||
ksu_try_umount("/apex/com.android.art/bin/dex2oat32", false, MNT_DETACH);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -76,6 +76,16 @@ void ksu_android_ns_fs_check()
|
||||
task_unlock(current);
|
||||
}
|
||||
|
||||
int ksu_access_ok(const void *addr, unsigned long size) {
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)
|
||||
/* For kernels before 5.0.0, pass the type argument to access_ok. */
|
||||
return access_ok(VERIFY_READ, addr, size);
|
||||
#else
|
||||
/* For kernels 5.0.0 and later, ignore the type argument. */
|
||||
return access_ok(addr, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode)
|
||||
{
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND)
|
||||
@@ -173,3 +183,17 @@ long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
long ksu_strncpy_from_user_retry(char *dst, const void __user *unsafe_addr,
|
||||
long count)
|
||||
{
|
||||
long ret = ksu_strncpy_from_user_nofault(dst, unsafe_addr, count);
|
||||
if (likely(ret >= 0))
|
||||
return ret;
|
||||
|
||||
// we faulted! fallback to slow path
|
||||
if (unlikely(!ksu_access_ok(unsafe_addr, count)))
|
||||
return -EFAULT;
|
||||
|
||||
return strncpy_from_user(dst, unsafe_addr, count);
|
||||
}
|
||||
|
||||
@@ -23,12 +23,16 @@
|
||||
extern long ksu_strncpy_from_user_nofault(char *dst,
|
||||
const void __user *unsafe_addr,
|
||||
long count);
|
||||
extern long ksu_strncpy_from_user_retry(char *dst,
|
||||
const void __user *unsafe_addr,
|
||||
long count);
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND)
|
||||
extern struct key *init_session_keyring;
|
||||
#endif
|
||||
|
||||
extern void ksu_android_ns_fs_check();
|
||||
extern int ksu_access_ok(const void *addr, unsigned long size);
|
||||
extern struct file *ksu_filp_open_compat(const char *filename, int flags,
|
||||
umode_t mode);
|
||||
extern ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count,
|
||||
|
||||
16
kernel/ksu.c
16
kernel/ksu.c
@@ -11,6 +11,10 @@
|
||||
#include "ksu.h"
|
||||
#include "throne_tracker.h"
|
||||
|
||||
#ifdef CONFIG_KSU_SUSFS
|
||||
#include <linux/susfs.h>
|
||||
#endif
|
||||
|
||||
static struct workqueue_struct *ksu_workqueue;
|
||||
|
||||
bool ksu_queue_work(struct work_struct *work)
|
||||
@@ -37,7 +41,7 @@ extern void ksu_sucompat_exit();
|
||||
extern void ksu_ksud_init();
|
||||
extern void ksu_ksud_exit();
|
||||
|
||||
int __init kernelsu_init(void)
|
||||
int __init ksu_kernelsu_init(void)
|
||||
{
|
||||
#ifdef CONFIG_KSU_DEBUG
|
||||
pr_alert("*************************************************************");
|
||||
@@ -49,6 +53,10 @@ int __init kernelsu_init(void)
|
||||
pr_alert("*************************************************************");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KSU_SUSFS
|
||||
susfs_init();
|
||||
#endif
|
||||
|
||||
ksu_core_init();
|
||||
|
||||
ksu_workqueue = alloc_ordered_workqueue("kernelsu_work_queue", 0);
|
||||
@@ -72,7 +80,7 @@ int __init kernelsu_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kernelsu_exit(void)
|
||||
void ksu_kernelsu_exit(void)
|
||||
{
|
||||
ksu_allowlist_exit();
|
||||
|
||||
@@ -88,8 +96,8 @@ void kernelsu_exit(void)
|
||||
ksu_core_exit();
|
||||
}
|
||||
|
||||
module_init(kernelsu_init);
|
||||
module_exit(kernelsu_exit);
|
||||
module_init(ksu_kernelsu_init);
|
||||
module_exit(ksu_kernelsu_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("weishu");
|
||||
|
||||
@@ -23,7 +23,9 @@
|
||||
#define CMD_UID_SHOULD_UMOUNT 13
|
||||
#define CMD_IS_SU_ENABLED 14
|
||||
#define CMD_ENABLE_SU 15
|
||||
#define CMD_HOOK_MODE 16
|
||||
#define CMD_GET_MANAGER_UID 16
|
||||
|
||||
#define CMD_HOOK_MODE 0xC0DEAD1A
|
||||
|
||||
#define EVENT_POST_FS_DATA 1
|
||||
#define EVENT_BOOT_COMPLETED 2
|
||||
|
||||
@@ -58,12 +58,15 @@ static void stop_input_hook();
|
||||
static struct work_struct stop_vfs_read_work;
|
||||
static struct work_struct stop_execve_hook_work;
|
||||
static struct work_struct stop_input_hook_work;
|
||||
#endif
|
||||
|
||||
#else
|
||||
bool ksu_vfs_read_hook __read_mostly = true;
|
||||
bool ksu_execveat_hook __read_mostly = true;
|
||||
bool ksu_input_hook __read_mostly = true;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
bool susfs_is_sus_su_ready = false;
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
|
||||
u32 ksu_devpts_sid;
|
||||
|
||||
@@ -71,15 +74,15 @@ u32 ksu_devpts_sid;
|
||||
bool ksu_is_compat __read_mostly = false;
|
||||
#endif
|
||||
|
||||
void on_post_fs_data(void)
|
||||
void ksu_on_post_fs_data(void)
|
||||
{
|
||||
static bool done = false;
|
||||
if (done) {
|
||||
pr_info("on_post_fs_data already done\n");
|
||||
pr_info("ksu_on_post_fs_data already done\n");
|
||||
return;
|
||||
}
|
||||
done = true;
|
||||
pr_info("on_post_fs_data!\n");
|
||||
pr_info("ksu_on_post_fs_data!\n");
|
||||
ksu_load_allow_list();
|
||||
// sanity check, this may influence the performance
|
||||
stop_input_hook();
|
||||
@@ -197,13 +200,13 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
|
||||
const char __user *p = get_user_arg_ptr(*argv, 1);
|
||||
if (p && !IS_ERR(p)) {
|
||||
char first_arg[16];
|
||||
ksu_strncpy_from_user_nofault(
|
||||
ksu_strncpy_from_user_retry(
|
||||
first_arg, p, sizeof(first_arg));
|
||||
pr_info("/system/bin/init first arg: %s\n",
|
||||
first_arg);
|
||||
if (!strcmp(first_arg, "second_stage")) {
|
||||
pr_info("/system/bin/init second_stage executed\n");
|
||||
apply_kernelsu_rules();
|
||||
ksu_apply_kernelsu_rules();
|
||||
init_second_stage_executed = true;
|
||||
ksu_android_ns_fs_check();
|
||||
}
|
||||
@@ -222,12 +225,12 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
|
||||
const char __user *p = get_user_arg_ptr(*argv, 1);
|
||||
if (p && !IS_ERR(p)) {
|
||||
char first_arg[16];
|
||||
ksu_strncpy_from_user_nofault(
|
||||
ksu_strncpy_from_user_retry(
|
||||
first_arg, p, sizeof(first_arg));
|
||||
pr_info("/init first arg: %s\n", first_arg);
|
||||
if (!strcmp(first_arg, "--second-stage")) {
|
||||
pr_info("/init second_stage executed\n");
|
||||
apply_kernelsu_rules();
|
||||
ksu_apply_kernelsu_rules();
|
||||
init_second_stage_executed = true;
|
||||
ksu_android_ns_fs_check();
|
||||
}
|
||||
@@ -247,7 +250,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
|
||||
}
|
||||
char env[256];
|
||||
// Reading environment variable strings from user space
|
||||
if (ksu_strncpy_from_user_nofault(
|
||||
if (ksu_strncpy_from_user_retry(
|
||||
env, p, sizeof(env)) < 0)
|
||||
continue;
|
||||
// Parsing environment variable names and values
|
||||
@@ -264,7 +267,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
|
||||
(!strcmp(env_value, "1") ||
|
||||
!strcmp(env_value, "true"))) {
|
||||
pr_info("/init second_stage executed\n");
|
||||
apply_kernelsu_rules();
|
||||
ksu_apply_kernelsu_rules();
|
||||
init_second_stage_executed =
|
||||
true;
|
||||
ksu_android_ns_fs_check();
|
||||
@@ -279,7 +282,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
|
||||
first_app_process = false;
|
||||
pr_info("exec app_process, /data prepared, second_stage: %d\n",
|
||||
init_second_stage_executed);
|
||||
on_post_fs_data(); // we keep this for old ksud
|
||||
ksu_on_post_fs_data(); // we keep this for old ksud
|
||||
stop_execve_hook();
|
||||
}
|
||||
|
||||
@@ -488,10 +491,12 @@ __maybe_unused int ksu_handle_execve_ksud(const char __user *filename_user,
|
||||
struct filename filename_in, *filename_p;
|
||||
char path[32];
|
||||
|
||||
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||
// return early if disabled.
|
||||
if (!ksu_execveat_hook) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!filename_user)
|
||||
return 0;
|
||||
@@ -677,6 +682,10 @@ static void stop_execve_hook()
|
||||
ksu_execveat_hook = false;
|
||||
pr_info("stop execve_hook\n");
|
||||
#endif
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
susfs_is_sus_su_ready = true;
|
||||
pr_info("susfs: sus_su is ready\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void stop_input_hook()
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#define KSUD_PATH "/data/adb/ksud"
|
||||
|
||||
void on_post_fs_data(void);
|
||||
void ksu_on_post_fs_data(void);
|
||||
|
||||
bool ksu_is_safe_mode(void);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ static inline bool ksu_is_manager_uid_valid()
|
||||
return ksu_manager_uid != KSU_INVALID_UID;
|
||||
}
|
||||
|
||||
static inline bool is_manager()
|
||||
static inline bool ksu_is_manager()
|
||||
{
|
||||
return unlikely(ksu_manager_uid == current_uid().val);
|
||||
}
|
||||
|
||||
@@ -36,14 +36,19 @@ static struct policydb *get_policydb(void)
|
||||
return db;
|
||||
}
|
||||
|
||||
void apply_kernelsu_rules()
|
||||
static DEFINE_MUTEX(ksu_rules);
|
||||
|
||||
void ksu_apply_kernelsu_rules()
|
||||
{
|
||||
if (!getenforce()) {
|
||||
struct policydb *db;
|
||||
|
||||
if (!ksu_getenforce()) {
|
||||
pr_info("SELinux permissive or disabled, apply rules!\n");
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
struct policydb *db = get_policydb();
|
||||
mutex_lock(&ksu_rules);
|
||||
|
||||
db = get_policydb();
|
||||
|
||||
ksu_permissive(db, KERNEL_SU_DOMAIN);
|
||||
ksu_typeattribute(db, KERNEL_SU_DOMAIN, "mlstrustedsubject");
|
||||
@@ -130,11 +135,19 @@ void apply_kernelsu_rules()
|
||||
// Allow all binder transactions
|
||||
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "binder", ALL);
|
||||
|
||||
// Allow system server kill su process
|
||||
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "getpgid");
|
||||
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "sigkill");
|
||||
// Allow system server kill su process
|
||||
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "getpgid");
|
||||
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "sigkill");
|
||||
|
||||
rcu_read_unlock();
|
||||
#ifdef CONFIG_KSU_SUSFS
|
||||
// Allow umount in zygote process without installing zygisk
|
||||
ksu_allow(db, "zygote", "labeledfs", "filesystem", "unmount");
|
||||
susfs_set_init_sid();
|
||||
susfs_set_ksu_sid();
|
||||
susfs_set_zygote_sid();
|
||||
#endif
|
||||
|
||||
mutex_unlock(&ksu_rules);
|
||||
}
|
||||
|
||||
#define MAX_SEPOL_LEN 128
|
||||
@@ -223,13 +236,13 @@ static void reset_avc_cache()
|
||||
selinux_xfrm_notify_policyload();
|
||||
}
|
||||
|
||||
int handle_sepolicy(unsigned long arg3, void __user *arg4)
|
||||
int ksu_handle_sepolicy(unsigned long arg3, void __user *arg4)
|
||||
{
|
||||
if (!arg4) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!getenforce()) {
|
||||
if (!ksu_getenforce()) {
|
||||
pr_info("SELinux permissive or disabled when handle policy!\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,14 @@
|
||||
|
||||
#define KERNEL_SU_DOMAIN "u:r:su:s0"
|
||||
|
||||
#ifdef CONFIG_KSU_SUSFS
|
||||
#define KERNEL_INIT_DOMAIN "u:r:init:s0"
|
||||
#define KERNEL_ZYGOTE_DOMAIN "u:r:zygote:s0"
|
||||
u32 susfs_ksu_sid = 0;
|
||||
u32 susfs_init_sid = 0;
|
||||
u32 susfs_zygote_sid = 0;
|
||||
#endif
|
||||
|
||||
static int transive_to_domain(const char *domain)
|
||||
{
|
||||
struct cred *cred;
|
||||
@@ -37,7 +45,7 @@ static int transive_to_domain(const char *domain)
|
||||
return error;
|
||||
}
|
||||
|
||||
void setup_selinux(const char *domain)
|
||||
void ksu_setup_selinux(const char *domain)
|
||||
{
|
||||
if (transive_to_domain(domain)) {
|
||||
pr_err("transive domain failed.\n");
|
||||
@@ -52,7 +60,7 @@ if (!is_domain_permissive) {
|
||||
}*/
|
||||
}
|
||||
|
||||
void setenforce(bool enforce)
|
||||
void ksu_setenforce(bool enforce)
|
||||
{
|
||||
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
|
||||
#ifdef KSU_COMPAT_USE_SELINUX_STATE
|
||||
@@ -63,7 +71,7 @@ void setenforce(bool enforce)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool getenforce()
|
||||
bool ksu_getenforce()
|
||||
{
|
||||
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
|
||||
#ifdef KSU_COMPAT_USE_SELINUX_STATE
|
||||
@@ -99,7 +107,7 @@ static inline u32 current_sid(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
bool is_ksu_domain()
|
||||
bool ksu_is_ksu_domain()
|
||||
{
|
||||
char *domain;
|
||||
u32 seclen;
|
||||
@@ -113,7 +121,7 @@ bool is_ksu_domain()
|
||||
return result;
|
||||
}
|
||||
|
||||
bool is_zygote(void *sec)
|
||||
bool ksu_is_zygote(void *sec)
|
||||
{
|
||||
struct task_security_struct *tsec = (struct task_security_struct *)sec;
|
||||
if (!tsec) {
|
||||
@@ -131,6 +139,83 @@ bool is_zygote(void *sec)
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KSU_SUSFS
|
||||
static inline void susfs_set_sid(const char *secctx_name, u32 *out_sid)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!secctx_name || !out_sid) {
|
||||
pr_err("secctx_name || out_sid is NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
err = security_secctx_to_secid(secctx_name, strlen(secctx_name),
|
||||
out_sid);
|
||||
if (err) {
|
||||
pr_err("failed setting sid for '%s', err: %d\n", secctx_name, err);
|
||||
return;
|
||||
}
|
||||
pr_info("sid '%u' is set for secctx_name '%s'\n", *out_sid, secctx_name);
|
||||
}
|
||||
|
||||
bool susfs_is_sid_equal(void *sec, u32 sid2) {
|
||||
struct task_security_struct *tsec = (struct task_security_struct *)sec;
|
||||
if (!tsec) {
|
||||
return false;
|
||||
}
|
||||
return tsec->sid == sid2;
|
||||
}
|
||||
|
||||
u32 susfs_get_sid_from_name(const char *secctx_name)
|
||||
{
|
||||
u32 out_sid = 0;
|
||||
int err;
|
||||
|
||||
if (!secctx_name) {
|
||||
pr_err("secctx_name is NULL\n");
|
||||
return 0;
|
||||
}
|
||||
err = security_secctx_to_secid(secctx_name, strlen(secctx_name),
|
||||
&out_sid);
|
||||
if (err) {
|
||||
pr_err("failed getting sid from secctx_name: %s, err: %d\n", secctx_name, err);
|
||||
return 0;
|
||||
}
|
||||
return out_sid;
|
||||
}
|
||||
|
||||
u32 susfs_get_current_sid(void) {
|
||||
return current_sid();
|
||||
}
|
||||
|
||||
void susfs_set_zygote_sid(void)
|
||||
{
|
||||
susfs_set_sid(KERNEL_ZYGOTE_DOMAIN, &susfs_zygote_sid);
|
||||
}
|
||||
|
||||
bool susfs_is_current_zygote_domain(void) {
|
||||
return unlikely(current_sid() == susfs_zygote_sid);
|
||||
}
|
||||
|
||||
void susfs_set_ksu_sid(void)
|
||||
{
|
||||
susfs_set_sid(KERNEL_SU_DOMAIN, &susfs_ksu_sid);
|
||||
}
|
||||
|
||||
bool susfs_is_current_ksu_domain(void) {
|
||||
return unlikely(current_sid() == susfs_ksu_sid);
|
||||
}
|
||||
|
||||
void susfs_set_init_sid(void)
|
||||
{
|
||||
susfs_set_sid(KERNEL_INIT_DOMAIN, &susfs_init_sid);
|
||||
}
|
||||
|
||||
bool susfs_is_current_init_domain(void) {
|
||||
return unlikely(current_sid() == susfs_init_sid);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define DEVPTS_DOMAIN "u:object_r:ksu_file:s0"
|
||||
|
||||
u32 ksu_get_devpts_sid()
|
||||
|
||||
@@ -8,17 +8,29 @@
|
||||
#define KSU_COMPAT_USE_SELINUX_STATE
|
||||
#endif
|
||||
|
||||
void setup_selinux(const char *);
|
||||
void ksu_setup_selinux(const char *);
|
||||
|
||||
void setenforce(bool);
|
||||
void ksu_setenforce(bool);
|
||||
|
||||
bool getenforce();
|
||||
bool ksu_getenforce();
|
||||
|
||||
bool is_ksu_domain();
|
||||
bool ksu_is_ksu_domain();
|
||||
|
||||
bool is_zygote(void *cred);
|
||||
bool ksu_is_zygote(void *cred);
|
||||
|
||||
void apply_kernelsu_rules();
|
||||
void ksu_apply_kernelsu_rules();
|
||||
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_MOUNT
|
||||
bool susfs_is_sid_equal(void *sec, u32 sid2);
|
||||
u32 susfs_get_sid_from_name(const char *secctx_name);
|
||||
u32 susfs_get_current_sid(void);
|
||||
void susfs_set_zygote_sid(void);
|
||||
bool susfs_is_current_zygote_domain(void);
|
||||
void susfs_set_ksu_sid(void);
|
||||
bool susfs_is_current_ksu_domain(void);
|
||||
void susfs_set_init_sid(void);
|
||||
bool susfs_is_current_init_domain(void);
|
||||
#endif
|
||||
|
||||
u32 ksu_get_devpts_sid();
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ setup_kernelsu() {
|
||||
cd "$GKI_ROOT/KernelSU-Next"
|
||||
git stash && echo "[-] Stashed current changes."
|
||||
if [ "$(git status | grep -Po 'v\d+(\.\d+)*' | head -n1)" ]; then
|
||||
git checkout next && echo "[-] Switched to next branch."
|
||||
git checkout next-susfs-a13-5.15-dev && echo "[-] Switched to next-susfs-a13-5.15-dev branch."
|
||||
fi
|
||||
git pull && echo "[+] Repository updated."
|
||||
if [ -z "${1-}" ]; then
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
#else
|
||||
#include <linux/sched.h>
|
||||
#endif
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
#include <linux/susfs_def.h>
|
||||
#endif
|
||||
|
||||
#include "objsec.h"
|
||||
#include "allowlist.h"
|
||||
@@ -28,9 +31,13 @@
|
||||
static bool ksu_sucompat_non_kp __read_mostly = true;
|
||||
#endif
|
||||
|
||||
extern void escape_to_root();
|
||||
extern void ksu_escape_to_root();
|
||||
|
||||
static void __user *userspace_stack_buffer(const void *d, size_t len)
|
||||
static const char sh_path[] = "/system/bin/sh";
|
||||
static const char ksud_path[] = KSUD_PATH;
|
||||
static const char su[] = SU_PATH;
|
||||
|
||||
static inline void __user *userspace_stack_buffer(const void *d, size_t len)
|
||||
{
|
||||
/* To avoid having to mmap a page in userspace, just write below the stack
|
||||
* pointer. */
|
||||
@@ -39,37 +46,37 @@ static void __user *userspace_stack_buffer(const void *d, size_t len)
|
||||
return copy_to_user(p, d, len) ? NULL : p;
|
||||
}
|
||||
|
||||
static char __user *sh_user_path(void)
|
||||
static inline char __user *sh_user_path(void)
|
||||
{
|
||||
static const char sh_path[] = "/system/bin/sh";
|
||||
|
||||
return userspace_stack_buffer(sh_path, sizeof(sh_path));
|
||||
}
|
||||
|
||||
static char __user *ksud_user_path(void)
|
||||
static inline char __user *ksud_user_path(void)
|
||||
{
|
||||
static const char ksud_path[] = KSUD_PATH;
|
||||
|
||||
return userspace_stack_buffer(ksud_path, sizeof(ksud_path));
|
||||
}
|
||||
|
||||
int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
|
||||
int *__unused_flags)
|
||||
{
|
||||
const char su[] = SU_PATH;
|
||||
|
||||
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||
if (!ksu_sucompat_non_kp) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ksu_is_allow_uid(current_uid().val)) {
|
||||
return 0;
|
||||
}
|
||||
#ifndef CONFIG_KSU_SUSFS_SUS_SU
|
||||
if (!ksu_is_allow_uid(current_uid().val)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
char path[sizeof(su)] = {0};
|
||||
#else
|
||||
char path[sizeof(su) + 1];
|
||||
memset(path, 0, sizeof(path));
|
||||
#endif
|
||||
ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path));
|
||||
|
||||
if (unlikely(!memcmp(path, su, sizeof(su)))) {
|
||||
@@ -80,27 +87,49 @@ int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) && defined(CONFIG_KSU_SUSFS_SUS_SU)
|
||||
struct filename* susfs_ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags) {
|
||||
struct filename *name = getname_flags(*filename_user, getname_statx_lookup_flags(*flags), NULL);
|
||||
|
||||
if (unlikely(IS_ERR(name) || name->name == NULL)) {
|
||||
return name;
|
||||
}
|
||||
|
||||
if (likely(memcmp(name->name, su, sizeof(su)))) {
|
||||
return name;
|
||||
}
|
||||
|
||||
const char sh[] = SH_PATH;
|
||||
pr_info("vfs_fstatat su->sh!\n");
|
||||
memcpy((void *)name->name, sh, sizeof(sh));
|
||||
return name;
|
||||
}
|
||||
#endif
|
||||
|
||||
int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags)
|
||||
{
|
||||
// const char sh[] = SH_PATH;
|
||||
const char su[] = SU_PATH;
|
||||
|
||||
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||
if (!ksu_sucompat_non_kp){
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_KSU_SUSFS_SUS_SU
|
||||
if (!ksu_is_allow_uid(current_uid().val)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (unlikely(!filename_user)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
char path[sizeof(su)] = {0};
|
||||
#else
|
||||
char path[sizeof(su) + 1];
|
||||
memset(path, 0, sizeof(path));
|
||||
#endif
|
||||
// Remove this later!! we use syscall hook, so this will never happen!!!!!
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) && 0
|
||||
// it becomes a `struct filename *` after 5.18
|
||||
@@ -132,8 +161,6 @@ int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
|
||||
int *__never_use_flags)
|
||||
{
|
||||
struct filename *filename;
|
||||
const char sh[] = KSUD_PATH;
|
||||
const char su[] = SU_PATH;
|
||||
|
||||
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||
if (!ksu_sucompat_non_kp) {
|
||||
@@ -152,13 +179,15 @@ int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
|
||||
if (likely(memcmp(filename->name, su, sizeof(su))))
|
||||
return 0;
|
||||
|
||||
#ifndef CONFIG_KSU_SUSFS_SUS_SU
|
||||
if (!ksu_is_allow_uid(current_uid().val))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
pr_info("do_execveat_common su found\n");
|
||||
memcpy((void *)filename->name, sh, sizeof(sh));
|
||||
memcpy((void *)filename->name, ksud_path, sizeof(ksud_path));
|
||||
|
||||
escape_to_root();
|
||||
ksu_escape_to_root();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -167,8 +196,11 @@ int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user,
|
||||
void *__never_use_argv, void *__never_use_envp,
|
||||
int *__never_use_flags)
|
||||
{
|
||||
const char su[] = SU_PATH;
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
char path[sizeof(su)] = {0};
|
||||
#else
|
||||
char path[sizeof(su) + 1];
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||
if (!ksu_sucompat_non_kp) {
|
||||
@@ -179,23 +211,8 @@ int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user,
|
||||
if (unlikely(!filename_user))
|
||||
return 0;
|
||||
|
||||
// nofault variant fails probably due to pagefault_disable
|
||||
// some cpus dont really have that good speculative execution
|
||||
// substitute set_fs, check if pointer is valid
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)
|
||||
if (!access_ok(VERIFY_READ, *filename_user, sizeof(path)))
|
||||
return 0;
|
||||
#else
|
||||
if (!access_ok(*filename_user, sizeof(path)))
|
||||
return 0;
|
||||
#endif
|
||||
// success = returns number of bytes and should be less than path
|
||||
long len = strncpy_from_user(path, *filename_user, sizeof(path));
|
||||
if (len <= 0 || len > sizeof(path))
|
||||
return 0;
|
||||
|
||||
// strncpy_from_user_nofault does this too
|
||||
path[sizeof(path) - 1] = '\0';
|
||||
memset(path, 0, sizeof(path));
|
||||
ksu_strncpy_from_user_retry(path, *filename_user, sizeof(path));
|
||||
|
||||
if (likely(memcmp(path, su, sizeof(su))))
|
||||
return 0;
|
||||
@@ -206,7 +223,7 @@ int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user,
|
||||
pr_info("sys_execve su found\n");
|
||||
*filename_user = ksud_user_path();
|
||||
|
||||
escape_to_root();
|
||||
ksu_escape_to_root();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -352,3 +369,41 @@ void ksu_sucompat_exit()
|
||||
pr_info("ksu_sucompat_exit: hooks disabled: execve/execveat_su, faccessat, stat, devpts\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
extern bool ksu_su_compat_enabled;
|
||||
bool ksu_devpts_hook = false;
|
||||
bool susfs_is_sus_su_hooks_enabled __read_mostly = false;
|
||||
int susfs_sus_su_working_mode = 0;
|
||||
|
||||
static bool ksu_is_su_kps_enabled(void) {
|
||||
for (int i = 0; i < ARRAY_SIZE(su_kps); i++) {
|
||||
if (su_kps[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ksu_susfs_disable_sus_su(void) {
|
||||
susfs_is_sus_su_hooks_enabled = false;
|
||||
ksu_devpts_hook = false;
|
||||
susfs_sus_su_working_mode = SUS_SU_DISABLED;
|
||||
// Re-enable the su_kps for user, users need to toggle off the kprobe hooks again in ksu manager if they want it disabled.
|
||||
if (!ksu_is_su_kps_enabled()) {
|
||||
ksu_sucompat_init();
|
||||
ksu_su_compat_enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ksu_susfs_enable_sus_su(void) {
|
||||
if (ksu_is_su_kps_enabled()) {
|
||||
ksu_sucompat_exit();
|
||||
ksu_su_compat_enabled = false;
|
||||
}
|
||||
susfs_is_sus_su_hooks_enabled = true;
|
||||
ksu_devpts_hook = true;
|
||||
susfs_sus_su_working_mode = SUS_SU_WITH_HOOKS;
|
||||
}
|
||||
#endif // #ifdef CONFIG_KSU_SUSFS_SUS_SU
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name,
|
||||
}
|
||||
}
|
||||
|
||||
bool is_manager = is_manager_apk(dirpath);
|
||||
bool is_manager = ksu_is_manager_apk(dirpath);
|
||||
pr_info("Found new base.apk at path: %s, is_manager: %d\n",
|
||||
dirpath, is_manager);
|
||||
if (is_manager) {
|
||||
@@ -351,7 +351,7 @@ static bool is_uid_exist(uid_t uid, char *package, void *data)
|
||||
return exist;
|
||||
}
|
||||
|
||||
void track_throne()
|
||||
void ksu_track_throne()
|
||||
{
|
||||
struct file *fp;
|
||||
int tries = 0;
|
||||
|
||||
@@ -5,7 +5,7 @@ void ksu_throne_tracker_init();
|
||||
|
||||
void ksu_throne_tracker_exit();
|
||||
|
||||
void track_throne();
|
||||
void ksu_track_throne();
|
||||
|
||||
bool is_lock_held(const char *path);
|
||||
|
||||
|
||||
11
manager/.gitignore
vendored
11
manager/.gitignore
vendored
@@ -1,11 +0,0 @@
|
||||
*.iml
|
||||
.gradle
|
||||
.idea
|
||||
.kotlin
|
||||
.DS_Store
|
||||
build
|
||||
captures
|
||||
.cxx
|
||||
local.properties
|
||||
key.jks
|
||||
setup.sh
|
||||
2
manager/app/.gitignore
vendored
2
manager/app/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
/build
|
||||
/release/
|
||||
@@ -1,140 +0,0 @@
|
||||
@file:Suppress("UnstableApiUsage")
|
||||
|
||||
import com.android.build.gradle.internal.api.BaseVariantOutputImpl
|
||||
import com.android.build.gradle.tasks.PackageAndroidArtifact
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.agp.app)
|
||||
alias(libs.plugins.kotlin)
|
||||
alias(libs.plugins.compose.compiler)
|
||||
alias(libs.plugins.ksp)
|
||||
alias(libs.plugins.lsplugin.apksign)
|
||||
id("kotlin-parcelize")
|
||||
}
|
||||
|
||||
val managerVersionCode: Int by rootProject.extra
|
||||
val managerVersionName: String by rootProject.extra
|
||||
|
||||
apksign {
|
||||
storeFileProperty = "KEYSTORE_FILE"
|
||||
storePasswordProperty = "KEYSTORE_PASSWORD"
|
||||
keyAliasProperty = "KEY_ALIAS"
|
||||
keyPasswordProperty = "KEY_PASSWORD"
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.rifsxd.ksunext"
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = true
|
||||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
compose = true
|
||||
prefab = true
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = "21"
|
||||
}
|
||||
|
||||
packaging {
|
||||
jniLibs {
|
||||
useLegacyPackaging = true
|
||||
}
|
||||
resources {
|
||||
// https://stackoverflow.com/a/58956288
|
||||
// It will break Layout Inspector, but it's unused for release build.
|
||||
excludes += "META-INF/*.version"
|
||||
// https://github.com/Kotlin/kotlinx.coroutines?tab=readme-ov-file#avoiding-including-the-debug-infrastructure-in-the-resulting-apk
|
||||
excludes += "DebugProbesKt.bin"
|
||||
// https://issueantenna.com/repo/kotlin/kotlinx.coroutines/issues/3158
|
||||
excludes += "kotlin-tooling-metadata.json"
|
||||
}
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path("src/main/cpp/CMakeLists.txt")
|
||||
}
|
||||
}
|
||||
|
||||
applicationVariants.all {
|
||||
outputs.forEach {
|
||||
val output = it as BaseVariantOutputImpl
|
||||
output.outputFileName = "KernelSU_Next_${managerVersionName}_${managerVersionCode}-$name.apk"
|
||||
}
|
||||
kotlin.sourceSets {
|
||||
getByName(name) {
|
||||
kotlin.srcDir("build/generated/ksp/$name/kotlin")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/77745844
|
||||
tasks.withType<PackageAndroidArtifact> {
|
||||
doFirst { appMetadata.asFile.orNull?.writeText("") }
|
||||
}
|
||||
|
||||
dependenciesInfo {
|
||||
includeInApk = false
|
||||
includeInBundle = false
|
||||
}
|
||||
|
||||
androidResources {
|
||||
generateLocaleConfig = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.androidx.navigation.compose)
|
||||
|
||||
implementation(platform(libs.androidx.compose.bom))
|
||||
implementation(libs.androidx.compose.material.icons.extended)
|
||||
implementation(libs.androidx.compose.material)
|
||||
implementation(libs.androidx.compose.material3)
|
||||
implementation(libs.androidx.compose.ui)
|
||||
implementation(libs.androidx.compose.ui.tooling.preview)
|
||||
|
||||
debugImplementation(libs.androidx.compose.ui.test.manifest)
|
||||
debugImplementation(libs.androidx.compose.ui.tooling)
|
||||
|
||||
implementation(libs.androidx.lifecycle.runtime.compose)
|
||||
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||
implementation(libs.androidx.lifecycle.viewmodel.compose)
|
||||
|
||||
implementation(libs.compose.destinations.core)
|
||||
ksp(libs.compose.destinations.ksp)
|
||||
|
||||
implementation(libs.com.github.topjohnwu.libsu.core)
|
||||
implementation(libs.com.github.topjohnwu.libsu.service)
|
||||
implementation(libs.com.github.topjohnwu.libsu.io)
|
||||
|
||||
implementation(libs.dev.rikka.rikkax.parcelablelist)
|
||||
|
||||
implementation(libs.io.coil.kt.coil.compose)
|
||||
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
|
||||
implementation(libs.me.zhanghai.android.appiconloader.coil)
|
||||
|
||||
implementation(libs.sheet.compose.dialogs.core)
|
||||
implementation(libs.sheet.compose.dialogs.list)
|
||||
implementation(libs.sheet.compose.dialogs.input)
|
||||
|
||||
implementation(libs.markdown)
|
||||
implementation(libs.androidx.webkit)
|
||||
|
||||
implementation(libs.lsposed.cxx)
|
||||
|
||||
implementation(libs.mmrl.platform)
|
||||
compileOnly(libs.mmrl.hidden.api)
|
||||
implementation(libs.mmrl.ui)
|
||||
implementation(libs.mmrl.webui)
|
||||
}
|
||||
47
manager/app/proguard-rules.pro
vendored
47
manager/app/proguard-rules.pro
vendored
@@ -1,47 +0,0 @@
|
||||
-verbose
|
||||
-optimizationpasses 5
|
||||
|
||||
-dontwarn org.conscrypt.**
|
||||
-dontwarn kotlinx.serialization.**
|
||||
|
||||
# Please add these rules to your existing keep rules in order to suppress warnings.
|
||||
# This is generated automatically by the Android Gradle plugin.
|
||||
-dontwarn com.google.auto.service.AutoService
|
||||
-dontwarn com.google.j2objc.annotations.RetainedWith
|
||||
-dontwarn javax.lang.model.SourceVersion
|
||||
-dontwarn javax.lang.model.element.AnnotationMirror
|
||||
-dontwarn javax.lang.model.element.AnnotationValue
|
||||
-dontwarn javax.lang.model.element.Element
|
||||
-dontwarn javax.lang.model.element.ElementKind
|
||||
-dontwarn javax.lang.model.element.ElementVisitor
|
||||
-dontwarn javax.lang.model.element.ExecutableElement
|
||||
-dontwarn javax.lang.model.element.Modifier
|
||||
-dontwarn javax.lang.model.element.Name
|
||||
-dontwarn javax.lang.model.element.PackageElement
|
||||
-dontwarn javax.lang.model.element.TypeElement
|
||||
-dontwarn javax.lang.model.element.TypeParameterElement
|
||||
-dontwarn javax.lang.model.element.VariableElement
|
||||
-dontwarn javax.lang.model.type.ArrayType
|
||||
-dontwarn javax.lang.model.type.DeclaredType
|
||||
-dontwarn javax.lang.model.type.ExecutableType
|
||||
-dontwarn javax.lang.model.type.TypeKind
|
||||
-dontwarn javax.lang.model.type.TypeMirror
|
||||
-dontwarn javax.lang.model.type.TypeVariable
|
||||
-dontwarn javax.lang.model.type.TypeVisitor
|
||||
-dontwarn javax.lang.model.util.AbstractAnnotationValueVisitor8
|
||||
-dontwarn javax.lang.model.util.AbstractTypeVisitor8
|
||||
-dontwarn javax.lang.model.util.ElementFilter
|
||||
-dontwarn javax.lang.model.util.Elements
|
||||
-dontwarn javax.lang.model.util.SimpleElementVisitor8
|
||||
-dontwarn javax.lang.model.util.SimpleTypeVisitor7
|
||||
-dontwarn javax.lang.model.util.SimpleTypeVisitor8
|
||||
-dontwarn javax.lang.model.util.Types
|
||||
-dontwarn javax.tools.Diagnostic$Kind
|
||||
|
||||
|
||||
# MMRL:webui reflection
|
||||
-keep class com.dergoogler.mmrl.webui.model.ModId { *; }
|
||||
-keep class com.dergoogler.mmrl.webui.interfaces.** { *; }
|
||||
-keep class com.rifsxd.ksunext.ui.webui.WebViewInterface { *; }
|
||||
|
||||
-keep,allowobfuscation class * extends com.dergoogler.mmrl.platform.content.IService { *; }
|
||||
@@ -1,63 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:name=".KernelSUApplication"
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.KernelSU"
|
||||
tools:targetApi="34">
|
||||
<activity
|
||||
android:name=".ui.MainActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.KernelSU">
|
||||
<intent-filter>
|
||||
<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
|
||||
android:name=".ui.webui.WebUIActivity"
|
||||
android:autoRemoveFromRecents="true"
|
||||
android:documentLaunchMode="intoExisting"
|
||||
android:exported="false"
|
||||
android:theme="@style/Theme.KernelSU.WebUI" />
|
||||
|
||||
<activity
|
||||
android:name=".ui.webui.WebUIXActivity"
|
||||
android:autoRemoveFromRecents="true"
|
||||
android:documentLaunchMode="intoExisting"
|
||||
android:exported="false"
|
||||
android:theme="@style/Theme.KernelSU.WebUI" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/filepaths" />
|
||||
</provider>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -1,21 +0,0 @@
|
||||
|
||||
# For more information about using CMake with Android Studio, read the
|
||||
# documentation: https://d.android.com/studio/projects/add-native-code.html
|
||||
|
||||
# Sets the minimum version of CMake required to build the native library.
|
||||
cmake_minimum_required(VERSION 3.18.1)
|
||||
|
||||
project("kernelsu")
|
||||
|
||||
find_package(cxx REQUIRED CONFIG)
|
||||
link_libraries(cxx::cxx)
|
||||
|
||||
add_library(kernelsu
|
||||
SHARED
|
||||
jni.cc
|
||||
ksu.cc
|
||||
)
|
||||
|
||||
find_library(log-lib log)
|
||||
|
||||
target_link_libraries(kernelsu ${log-lib})
|
||||
@@ -1,315 +0,0 @@
|
||||
#include <jni.h>
|
||||
|
||||
#include <sys/prctl.h>
|
||||
|
||||
#include <android/log.h>
|
||||
#include <cstring>
|
||||
|
||||
#include "ksu.h"
|
||||
|
||||
#define LOG_TAG "KernelSU-Next"
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_rifsxd_ksunext_Natives_becomeManager(JNIEnv *env, jobject, jstring pkg) {
|
||||
auto cpkg = env->GetStringUTFChars(pkg, nullptr);
|
||||
auto result = become_manager(cpkg);
|
||||
env->ReleaseStringUTFChars(pkg, cpkg);
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_rifsxd_ksunext_Natives_getVersion(JNIEnv *env, jobject) {
|
||||
return get_version();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_rifsxd_ksunext_Natives_getHookMode(JNIEnv *env, jobject) {
|
||||
const char* mode = get_hook_mode();
|
||||
return env->NewStringUTF(mode);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jintArray JNICALL
|
||||
Java_com_rifsxd_ksunext_Natives_getAllowList(JNIEnv *env, jobject) {
|
||||
int uids[1024];
|
||||
int size = 0;
|
||||
bool result = get_allow_list(uids, &size);
|
||||
LOGD("getAllowList: %d, size: %d", result, size);
|
||||
if (result) {
|
||||
auto array = env->NewIntArray(size);
|
||||
env->SetIntArrayRegion(array, 0, size, uids);
|
||||
return array;
|
||||
}
|
||||
return env->NewIntArray(0);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_rifsxd_ksunext_Natives_isSafeMode(JNIEnv *env, jclass clazz) {
|
||||
return is_safe_mode();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_rifsxd_ksunext_Natives_isLkmMode(JNIEnv *env, jclass clazz) {
|
||||
return is_lkm_mode();
|
||||
}
|
||||
|
||||
static void fillIntArray(JNIEnv *env, jobject list, int *data, int count) {
|
||||
auto cls = env->GetObjectClass(list);
|
||||
auto add = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z");
|
||||
auto integerCls = env->FindClass("java/lang/Integer");
|
||||
auto constructor = env->GetMethodID(integerCls, "<init>", "(I)V");
|
||||
for (int i = 0; i < count; ++i) {
|
||||
auto integer = env->NewObject(integerCls, constructor, data[i]);
|
||||
env->CallBooleanMethod(list, add, integer);
|
||||
}
|
||||
}
|
||||
|
||||
static void addIntToList(JNIEnv *env, jobject list, int ele) {
|
||||
auto cls = env->GetObjectClass(list);
|
||||
auto add = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z");
|
||||
auto integerCls = env->FindClass("java/lang/Integer");
|
||||
auto constructor = env->GetMethodID(integerCls, "<init>", "(I)V");
|
||||
auto integer = env->NewObject(integerCls, constructor, ele);
|
||||
env->CallBooleanMethod(list, add, integer);
|
||||
}
|
||||
|
||||
static uint64_t capListToBits(JNIEnv *env, jobject list) {
|
||||
auto cls = env->GetObjectClass(list);
|
||||
auto get = env->GetMethodID(cls, "get", "(I)Ljava/lang/Object;");
|
||||
auto size = env->GetMethodID(cls, "size", "()I");
|
||||
auto listSize = env->CallIntMethod(list, size);
|
||||
auto integerCls = env->FindClass("java/lang/Integer");
|
||||
auto intValue = env->GetMethodID(integerCls, "intValue", "()I");
|
||||
uint64_t result = 0;
|
||||
for (int i = 0; i < listSize; ++i) {
|
||||
auto integer = env->CallObjectMethod(list, get, i);
|
||||
int data = env->CallIntMethod(integer, intValue);
|
||||
|
||||
if (cap_valid(data)) {
|
||||
result |= (1ULL << data);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int getListSize(JNIEnv *env, jobject list) {
|
||||
auto cls = env->GetObjectClass(list);
|
||||
auto size = env->GetMethodID(cls, "size", "()I");
|
||||
return env->CallIntMethod(list, size);
|
||||
}
|
||||
|
||||
static void fillArrayWithList(JNIEnv *env, jobject list, int *data, int count) {
|
||||
auto cls = env->GetObjectClass(list);
|
||||
auto get = env->GetMethodID(cls, "get", "(I)Ljava/lang/Object;");
|
||||
auto integerCls = env->FindClass("java/lang/Integer");
|
||||
auto intValue = env->GetMethodID(integerCls, "intValue", "()I");
|
||||
for (int i = 0; i < count; ++i) {
|
||||
auto integer = env->CallObjectMethod(list, get, i);
|
||||
data[i] = env->CallIntMethod(integer, intValue);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_com_rifsxd_ksunext_Natives_getAppProfile(JNIEnv *env, jobject, jstring pkg, jint uid) {
|
||||
if (env->GetStringLength(pkg) > KSU_MAX_PACKAGE_NAME) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
p_key_t key = {};
|
||||
auto cpkg = env->GetStringUTFChars(pkg, nullptr);
|
||||
strcpy(key, cpkg);
|
||||
env->ReleaseStringUTFChars(pkg, cpkg);
|
||||
|
||||
app_profile profile = {};
|
||||
profile.version = KSU_APP_PROFILE_VER;
|
||||
|
||||
strcpy(profile.key, key);
|
||||
profile.current_uid = uid;
|
||||
|
||||
bool useDefaultProfile = !get_app_profile(key, &profile);
|
||||
|
||||
auto cls = env->FindClass("com/rifsxd/ksunext/Natives$Profile");
|
||||
auto constructor = env->GetMethodID(cls, "<init>", "()V");
|
||||
auto obj = env->NewObject(cls, constructor);
|
||||
auto keyField = env->GetFieldID(cls, "name", "Ljava/lang/String;");
|
||||
auto currentUidField = env->GetFieldID(cls, "currentUid", "I");
|
||||
auto allowSuField = env->GetFieldID(cls, "allowSu", "Z");
|
||||
|
||||
auto rootUseDefaultField = env->GetFieldID(cls, "rootUseDefault", "Z");
|
||||
auto rootTemplateField = env->GetFieldID(cls, "rootTemplate", "Ljava/lang/String;");
|
||||
|
||||
auto uidField = env->GetFieldID(cls, "uid", "I");
|
||||
auto gidField = env->GetFieldID(cls, "gid", "I");
|
||||
auto groupsField = env->GetFieldID(cls, "groups", "Ljava/util/List;");
|
||||
auto capabilitiesField = env->GetFieldID(cls, "capabilities", "Ljava/util/List;");
|
||||
auto domainField = env->GetFieldID(cls, "context", "Ljava/lang/String;");
|
||||
auto namespacesField = env->GetFieldID(cls, "namespace", "I");
|
||||
|
||||
auto nonRootUseDefaultField = env->GetFieldID(cls, "nonRootUseDefault", "Z");
|
||||
auto umountModulesField = env->GetFieldID(cls, "umountModules", "Z");
|
||||
|
||||
env->SetObjectField(obj, keyField, env->NewStringUTF(profile.key));
|
||||
env->SetIntField(obj, currentUidField, profile.current_uid);
|
||||
|
||||
if (useDefaultProfile) {
|
||||
// no profile found, so just use default profile:
|
||||
// don't allow root and use default profile!
|
||||
LOGD("use default profile for: %s, %d", key, uid);
|
||||
|
||||
// allow_su = false
|
||||
// non root use default = true
|
||||
env->SetBooleanField(obj, allowSuField, false);
|
||||
env->SetBooleanField(obj, nonRootUseDefaultField, true);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
auto allowSu = profile.allow_su;
|
||||
|
||||
if (allowSu) {
|
||||
env->SetBooleanField(obj, rootUseDefaultField, (jboolean) profile.rp_config.use_default);
|
||||
if (strlen(profile.rp_config.template_name) > 0) {
|
||||
env->SetObjectField(obj, rootTemplateField,
|
||||
env->NewStringUTF(profile.rp_config.template_name));
|
||||
}
|
||||
|
||||
env->SetIntField(obj, uidField, profile.rp_config.profile.uid);
|
||||
env->SetIntField(obj, gidField, profile.rp_config.profile.gid);
|
||||
|
||||
jobject groupList = env->GetObjectField(obj, groupsField);
|
||||
int groupCount = profile.rp_config.profile.groups_count;
|
||||
if (groupCount > KSU_MAX_GROUPS) {
|
||||
LOGD("kernel group count too large: %d???", groupCount);
|
||||
groupCount = KSU_MAX_GROUPS;
|
||||
}
|
||||
fillIntArray(env, groupList, profile.rp_config.profile.groups, groupCount);
|
||||
|
||||
jobject capList = env->GetObjectField(obj, capabilitiesField);
|
||||
for (int i = 0; i <= CAP_LAST_CAP; i++) {
|
||||
if (profile.rp_config.profile.capabilities.effective & (1ULL << i)) {
|
||||
addIntToList(env, capList, i);
|
||||
}
|
||||
}
|
||||
|
||||
env->SetObjectField(obj, domainField,
|
||||
env->NewStringUTF(profile.rp_config.profile.selinux_domain));
|
||||
env->SetIntField(obj, namespacesField, profile.rp_config.profile.namespaces);
|
||||
env->SetBooleanField(obj, allowSuField, profile.allow_su);
|
||||
} else {
|
||||
env->SetBooleanField(obj, nonRootUseDefaultField,
|
||||
(jboolean) profile.nrp_config.use_default);
|
||||
env->SetBooleanField(obj, umountModulesField, profile.nrp_config.profile.umount_modules);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_rifsxd_ksunext_Natives_setAppProfile(JNIEnv *env, jobject clazz, jobject profile) {
|
||||
auto cls = env->FindClass("com/rifsxd/ksunext/Natives$Profile");
|
||||
|
||||
auto keyField = env->GetFieldID(cls, "name", "Ljava/lang/String;");
|
||||
auto currentUidField = env->GetFieldID(cls, "currentUid", "I");
|
||||
auto allowSuField = env->GetFieldID(cls, "allowSu", "Z");
|
||||
|
||||
auto rootUseDefaultField = env->GetFieldID(cls, "rootUseDefault", "Z");
|
||||
auto rootTemplateField = env->GetFieldID(cls, "rootTemplate", "Ljava/lang/String;");
|
||||
|
||||
auto uidField = env->GetFieldID(cls, "uid", "I");
|
||||
auto gidField = env->GetFieldID(cls, "gid", "I");
|
||||
auto groupsField = env->GetFieldID(cls, "groups", "Ljava/util/List;");
|
||||
auto capabilitiesField = env->GetFieldID(cls, "capabilities", "Ljava/util/List;");
|
||||
auto domainField = env->GetFieldID(cls, "context", "Ljava/lang/String;");
|
||||
auto namespacesField = env->GetFieldID(cls, "namespace", "I");
|
||||
|
||||
auto nonRootUseDefaultField = env->GetFieldID(cls, "nonRootUseDefault", "Z");
|
||||
auto umountModulesField = env->GetFieldID(cls, "umountModules", "Z");
|
||||
|
||||
auto key = env->GetObjectField(profile, keyField);
|
||||
if (!key) {
|
||||
return false;
|
||||
}
|
||||
if (env->GetStringLength((jstring) key) > KSU_MAX_PACKAGE_NAME) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto cpkg = env->GetStringUTFChars((jstring) key, nullptr);
|
||||
p_key_t p_key = {};
|
||||
strcpy(p_key, cpkg);
|
||||
env->ReleaseStringUTFChars((jstring) key, cpkg);
|
||||
|
||||
auto currentUid = env->GetIntField(profile, currentUidField);
|
||||
|
||||
auto uid = env->GetIntField(profile, uidField);
|
||||
auto gid = env->GetIntField(profile, gidField);
|
||||
auto groups = env->GetObjectField(profile, groupsField);
|
||||
auto capabilities = env->GetObjectField(profile, capabilitiesField);
|
||||
auto domain = env->GetObjectField(profile, domainField);
|
||||
auto allowSu = env->GetBooleanField(profile, allowSuField);
|
||||
auto umountModules = env->GetBooleanField(profile, umountModulesField);
|
||||
|
||||
app_profile p = {};
|
||||
p.version = KSU_APP_PROFILE_VER;
|
||||
|
||||
strcpy(p.key, p_key);
|
||||
p.allow_su = allowSu;
|
||||
p.current_uid = currentUid;
|
||||
|
||||
if (allowSu) {
|
||||
p.rp_config.use_default = env->GetBooleanField(profile, rootUseDefaultField);
|
||||
auto templateName = env->GetObjectField(profile, rootTemplateField);
|
||||
if (templateName) {
|
||||
auto ctemplateName = env->GetStringUTFChars((jstring) templateName, nullptr);
|
||||
strcpy(p.rp_config.template_name, ctemplateName);
|
||||
env->ReleaseStringUTFChars((jstring) templateName, ctemplateName);
|
||||
}
|
||||
|
||||
p.rp_config.profile.uid = uid;
|
||||
p.rp_config.profile.gid = gid;
|
||||
|
||||
int groups_count = getListSize(env, groups);
|
||||
if (groups_count > KSU_MAX_GROUPS) {
|
||||
LOGD("groups count too large: %d", groups_count);
|
||||
return false;
|
||||
}
|
||||
p.rp_config.profile.groups_count = groups_count;
|
||||
fillArrayWithList(env, groups, p.rp_config.profile.groups, groups_count);
|
||||
|
||||
p.rp_config.profile.capabilities.effective = capListToBits(env, capabilities);
|
||||
|
||||
auto cdomain = env->GetStringUTFChars((jstring) domain, nullptr);
|
||||
strcpy(p.rp_config.profile.selinux_domain, cdomain);
|
||||
env->ReleaseStringUTFChars((jstring) domain, cdomain);
|
||||
|
||||
p.rp_config.profile.namespaces = env->GetIntField(profile, namespacesField);
|
||||
} else {
|
||||
p.nrp_config.use_default = env->GetBooleanField(profile, nonRootUseDefaultField);
|
||||
p.nrp_config.profile.umount_modules = umountModules;
|
||||
}
|
||||
|
||||
return set_app_profile(&p);
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_rifsxd_ksunext_Natives_uidShouldUmount(JNIEnv *env, jobject thiz, jint uid) {
|
||||
return uid_should_umount(uid);
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_rifsxd_ksunext_Natives_isSuEnabled(JNIEnv *env, jobject thiz) {
|
||||
return is_su_enabled();
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_rifsxd_ksunext_Natives_setSuEnabled(JNIEnv *env, jobject thiz, jboolean enabled) {
|
||||
return set_su_enabled(enabled);
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
//
|
||||
// Created by weishu on 2022/12/9.
|
||||
//
|
||||
|
||||
#include <sys/prctl.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "ksu.h"
|
||||
|
||||
#define KERNEL_SU_OPTION 0xDEADBEEF
|
||||
|
||||
#define CMD_GRANT_ROOT 0
|
||||
|
||||
#define CMD_BECOME_MANAGER 1
|
||||
#define CMD_GET_VERSION 2
|
||||
#define CMD_ALLOW_SU 3
|
||||
#define CMD_DENY_SU 4
|
||||
#define CMD_GET_SU_LIST 5
|
||||
#define CMD_GET_DENY_LIST 6
|
||||
#define CMD_CHECK_SAFEMODE 9
|
||||
|
||||
#define CMD_GET_APP_PROFILE 10
|
||||
#define CMD_SET_APP_PROFILE 11
|
||||
|
||||
#define CMD_IS_UID_GRANTED_ROOT 12
|
||||
#define CMD_IS_UID_SHOULD_UMOUNT 13
|
||||
#define CMD_IS_SU_ENABLED 14
|
||||
#define CMD_ENABLE_SU 15
|
||||
#define CMD_HOOK_MODE 16
|
||||
|
||||
static bool ksuctl(int cmd, void* arg1, void* arg2) {
|
||||
int32_t result = 0;
|
||||
prctl(KERNEL_SU_OPTION, cmd, arg1, arg2, &result);
|
||||
return result == KERNEL_SU_OPTION;
|
||||
}
|
||||
|
||||
bool become_manager(const char* pkg) {
|
||||
char param[128];
|
||||
uid_t uid = getuid();
|
||||
uint32_t userId = uid / 100000;
|
||||
if (userId == 0) {
|
||||
sprintf(param, "/data/data/%s", pkg);
|
||||
} else {
|
||||
snprintf(param, sizeof(param), "/data/user/%d/%s", userId, pkg);
|
||||
}
|
||||
|
||||
return ksuctl(CMD_BECOME_MANAGER, param, nullptr);
|
||||
}
|
||||
|
||||
// cache the result to avoid unnecessary syscall
|
||||
static bool is_lkm;
|
||||
int get_version() {
|
||||
int32_t version = -1;
|
||||
int32_t lkm = 0;
|
||||
ksuctl(CMD_GET_VERSION, &version, &lkm);
|
||||
if (!is_lkm && lkm != 0) {
|
||||
is_lkm = true;
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
const char* get_hook_mode() {
|
||||
static char mode[16];
|
||||
ksuctl(CMD_HOOK_MODE, mode, nullptr);
|
||||
return mode;
|
||||
}
|
||||
|
||||
bool get_allow_list(int *uids, int *size) {
|
||||
return ksuctl(CMD_GET_SU_LIST, uids, size);
|
||||
}
|
||||
|
||||
bool is_safe_mode() {
|
||||
return ksuctl(CMD_CHECK_SAFEMODE, nullptr, nullptr);
|
||||
}
|
||||
|
||||
bool is_lkm_mode() {
|
||||
// you should call get_version first!
|
||||
return is_lkm;
|
||||
}
|
||||
|
||||
bool uid_should_umount(int uid) {
|
||||
bool should;
|
||||
return ksuctl(CMD_IS_UID_SHOULD_UMOUNT, reinterpret_cast<void*>(uid), &should) && should;
|
||||
}
|
||||
|
||||
bool set_app_profile(const app_profile *profile) {
|
||||
return ksuctl(CMD_SET_APP_PROFILE, (void*) profile, nullptr);
|
||||
}
|
||||
|
||||
bool get_app_profile(p_key_t key, app_profile *profile) {
|
||||
return ksuctl(CMD_GET_APP_PROFILE, (void*) profile, nullptr);
|
||||
}
|
||||
|
||||
bool set_su_enabled(bool enabled) {
|
||||
return ksuctl(CMD_ENABLE_SU, (void*) enabled, nullptr);
|
||||
}
|
||||
|
||||
bool is_su_enabled() {
|
||||
bool enabled = true;
|
||||
// if ksuctl failed, we assume su is enabled, and it cannot be disabled.
|
||||
ksuctl(CMD_IS_SU_ENABLED, &enabled, nullptr);
|
||||
return enabled;
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
//
|
||||
// Created by weishu on 2022/12/9.
|
||||
//
|
||||
|
||||
#ifndef KERNELSU_KSU_H
|
||||
#define KERNELSU_KSU_H
|
||||
|
||||
#include <linux/capability.h>
|
||||
|
||||
bool become_manager(const char *);
|
||||
|
||||
int get_version();
|
||||
|
||||
const char* get_hook_mode();
|
||||
|
||||
bool get_allow_list(int *uids, int *size);
|
||||
|
||||
bool uid_should_umount(int uid);
|
||||
|
||||
bool is_safe_mode();
|
||||
|
||||
bool is_lkm_mode();
|
||||
|
||||
#define KSU_APP_PROFILE_VER 2
|
||||
#define KSU_MAX_PACKAGE_NAME 256
|
||||
// NGROUPS_MAX for Linux is 65535 generally, but we only supports 32 groups.
|
||||
#define KSU_MAX_GROUPS 32
|
||||
#define KSU_SELINUX_DOMAIN 64
|
||||
|
||||
using p_key_t = char[KSU_MAX_PACKAGE_NAME];
|
||||
|
||||
struct root_profile {
|
||||
int32_t uid;
|
||||
int32_t gid;
|
||||
|
||||
int32_t groups_count;
|
||||
int32_t groups[KSU_MAX_GROUPS];
|
||||
|
||||
// kernel_cap_t is u32[2] for capabilities v3
|
||||
struct {
|
||||
uint64_t effective;
|
||||
uint64_t permitted;
|
||||
uint64_t inheritable;
|
||||
} capabilities;
|
||||
|
||||
char selinux_domain[KSU_SELINUX_DOMAIN];
|
||||
|
||||
int32_t namespaces;
|
||||
};
|
||||
|
||||
struct non_root_profile {
|
||||
bool umount_modules;
|
||||
};
|
||||
|
||||
struct app_profile {
|
||||
// It may be utilized for backward compatibility, although we have never explicitly made any promises regarding this.
|
||||
uint32_t version;
|
||||
|
||||
// this is usually the package of the app, but can be other value for special apps
|
||||
char key[KSU_MAX_PACKAGE_NAME];
|
||||
int32_t current_uid;
|
||||
bool allow_su;
|
||||
|
||||
union {
|
||||
struct {
|
||||
bool use_default;
|
||||
char template_name[KSU_MAX_PACKAGE_NAME];
|
||||
|
||||
struct root_profile profile;
|
||||
} rp_config;
|
||||
|
||||
struct {
|
||||
bool use_default;
|
||||
|
||||
struct non_root_profile profile;
|
||||
} nrp_config;
|
||||
};
|
||||
};
|
||||
|
||||
bool set_app_profile(const app_profile *profile);
|
||||
|
||||
bool get_app_profile(p_key_t key, app_profile *profile);
|
||||
|
||||
bool set_su_enabled(bool enabled);
|
||||
|
||||
bool is_su_enabled();
|
||||
|
||||
#endif //KERNELSU_KSU_H
|
||||
@@ -1,71 +0,0 @@
|
||||
package com.rifsxd.ksunext
|
||||
|
||||
import android.app.Application
|
||||
import android.system.Os
|
||||
import coil.Coil
|
||||
import coil.ImageLoader
|
||||
import com.dergoogler.mmrl.platform.Platform
|
||||
import me.zhanghai.android.appiconloader.coil.AppIconFetcher
|
||||
import me.zhanghai.android.appiconloader.coil.AppIconKeyer
|
||||
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
|
||||
|
||||
class KernelSUApplication : Application() {
|
||||
|
||||
lateinit var okhttpClient: OkHttpClient
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
ksuApp = this
|
||||
|
||||
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(
|
||||
ImageLoader.Builder(context)
|
||||
.components {
|
||||
add(AppIconKeyer())
|
||||
add(AppIconFetcher.Factory(iconSize, false, context))
|
||||
}
|
||||
.build()
|
||||
)
|
||||
|
||||
val webroot = File(dataDir, "webroot")
|
||||
if (!webroot.exists()) {
|
||||
webroot.mkdir()
|
||||
}
|
||||
|
||||
// Provide working env for rust's temp_dir()
|
||||
Os.setenv("TMPDIR", cacheDir.absolutePath, true)
|
||||
|
||||
okhttpClient =
|
||||
OkHttpClient.Builder().cache(Cache(File(cacheDir, "okhttp"), 10 * 1024 * 1024))
|
||||
.addInterceptor { block ->
|
||||
block.proceed(
|
||||
block.request().newBuilder()
|
||||
.header("User-Agent", "KernelSU/${BuildConfig.VERSION_CODE}")
|
||||
.header("Accept-Language", Locale.getDefault().toLanguageTag()).build()
|
||||
)
|
||||
}.build()
|
||||
}
|
||||
|
||||
private fun launchPlatformInit() {
|
||||
// Use a coroutine to avoid blocking the main thread
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
initPlatform()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package com.rifsxd.ksunext
|
||||
|
||||
import android.system.Os
|
||||
|
||||
/**
|
||||
* @author weishu
|
||||
* @date 2022/12/10.
|
||||
*/
|
||||
|
||||
data class KernelVersion(val major: Int, val patchLevel: Int, val subLevel: Int) {
|
||||
override fun toString(): String {
|
||||
return "$major.$patchLevel.$subLevel"
|
||||
}
|
||||
|
||||
fun isGKI(): Boolean {
|
||||
|
||||
// kernel 6.x
|
||||
if (major > 5) {
|
||||
return true
|
||||
}
|
||||
|
||||
// kernel 5.10.x
|
||||
if (major == 5) {
|
||||
return patchLevel >= 10
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun isULegacy(): Boolean {
|
||||
return major == 3
|
||||
}
|
||||
|
||||
fun isLegacy(): Boolean {
|
||||
return major == 4 && patchLevel in 1..18
|
||||
}
|
||||
|
||||
fun isGKI1(): Boolean {
|
||||
return (major == 4 && patchLevel >= 19) || (major == 5 && patchLevel < 10)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun parseKernelVersion(version: String): KernelVersion {
|
||||
val find = "(\\d+)\\.(\\d+)\\.(\\d+)".toRegex().find(version)
|
||||
return if (find != null) {
|
||||
KernelVersion(find.groupValues[1].toInt(), find.groupValues[2].toInt(), find.groupValues[3].toInt())
|
||||
} else {
|
||||
KernelVersion(-1, -1, -1)
|
||||
}
|
||||
}
|
||||
|
||||
fun getKernelVersion(): KernelVersion {
|
||||
Os.uname().release.let {
|
||||
return parseKernelVersion(it)
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
package com.rifsxd.ksunext
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.annotation.Keep
|
||||
import androidx.compose.runtime.Immutable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
/**
|
||||
* @author weishu
|
||||
* @date 2022/12/8.
|
||||
*/
|
||||
object Natives {
|
||||
// minimal supported kernel version
|
||||
// 10915: allowlist breaking change, add app profile
|
||||
// 10931: app profile struct add 'version' field
|
||||
// 10946: add capabilities
|
||||
// 10977: change groups_count and groups to avoid overflow write
|
||||
// 11071: Fix the issue of failing to set a custom SELinux type.
|
||||
const val MINIMAL_SUPPORTED_KERNEL = 11071
|
||||
|
||||
// 11640: Support query working mode, LKM or GKI
|
||||
// when MINIMAL_SUPPORTED_KERNEL > 11640, we can remove this constant.
|
||||
const val MINIMAL_SUPPORTED_KERNEL_LKM = 11648
|
||||
|
||||
// 12404: Support disable sucompat mode
|
||||
const val MINIMAL_SUPPORTED_SU_COMPAT = 12404
|
||||
|
||||
// 12569: support get hook mode
|
||||
const val MINIMAL_SUPPORTED_HOOK_MODE = 12569
|
||||
|
||||
const val KERNEL_SU_DOMAIN = "u:r:su:s0"
|
||||
|
||||
const val ROOT_UID = 0
|
||||
const val ROOT_GID = 0
|
||||
|
||||
init {
|
||||
System.loadLibrary("kernelsu")
|
||||
}
|
||||
|
||||
// become root manager, return true if success.
|
||||
external fun becomeManager(pkg: String?): Boolean
|
||||
val version: Int
|
||||
external get
|
||||
|
||||
// get the uid list of allowed su processes.
|
||||
val allowList: IntArray
|
||||
external get
|
||||
|
||||
val isSafeMode: Boolean
|
||||
external get
|
||||
|
||||
val isLkmMode: Boolean
|
||||
external get
|
||||
|
||||
external fun uidShouldUmount(uid: Int): Boolean
|
||||
|
||||
/**
|
||||
* Get a string indicating the SU hook mode enabled in kernel.
|
||||
* The return values are:
|
||||
* - "Manual": Manual hooks was enabled.
|
||||
* - "Kprobes": Kprobes hooks was enabled (CONFIG_KSU_KPROBES_HOOK).
|
||||
*
|
||||
* @return return hook mode, or null if unavailable.
|
||||
*/
|
||||
external fun getHookMode(): String?
|
||||
|
||||
/**
|
||||
* Get the profile of the given package.
|
||||
* @param key usually the package name
|
||||
* @return return null if failed.
|
||||
*/
|
||||
external fun getAppProfile(key: String?, uid: Int): Profile
|
||||
external fun setAppProfile(profile: Profile?): Boolean
|
||||
|
||||
/**
|
||||
* `su` compat mode can be disabled temporarily.
|
||||
* 0: disabled
|
||||
* 1: enabled
|
||||
* negative : error
|
||||
*/
|
||||
external fun isSuEnabled(): Boolean
|
||||
external fun setSuEnabled(enabled: Boolean): Boolean
|
||||
|
||||
private const val NON_ROOT_DEFAULT_PROFILE_KEY = "$"
|
||||
private const val NOBODY_UID = 9999
|
||||
|
||||
fun setDefaultUmountModules(umountModules: Boolean): Boolean {
|
||||
Profile(
|
||||
NON_ROOT_DEFAULT_PROFILE_KEY,
|
||||
NOBODY_UID,
|
||||
false,
|
||||
umountModules = umountModules
|
||||
).let {
|
||||
return setAppProfile(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun isDefaultUmountModules(): Boolean {
|
||||
getAppProfile(NON_ROOT_DEFAULT_PROFILE_KEY, NOBODY_UID).let {
|
||||
return it.umountModules
|
||||
}
|
||||
}
|
||||
|
||||
fun requireNewKernel(): Boolean {
|
||||
return version < MINIMAL_SUPPORTED_KERNEL
|
||||
}
|
||||
|
||||
@Immutable
|
||||
@Parcelize
|
||||
@Keep
|
||||
data class Profile(
|
||||
// and there is a default profile for root and non-root
|
||||
val name: String,
|
||||
// current uid for the package, this is convivent for kernel to check
|
||||
// if the package name doesn't match uid, then it should be invalidated.
|
||||
val currentUid: Int = 0,
|
||||
|
||||
// if this is true, kernel will grant root permission to this package
|
||||
val allowSu: Boolean = false,
|
||||
|
||||
// these are used for root profile
|
||||
val rootUseDefault: Boolean = true,
|
||||
val rootTemplate: String? = null,
|
||||
val uid: Int = ROOT_UID,
|
||||
val gid: Int = ROOT_GID,
|
||||
val groups: List<Int> = mutableListOf(),
|
||||
val capabilities: List<Int> = mutableListOf(),
|
||||
val context: String = KERNEL_SU_DOMAIN,
|
||||
val namespace: Int = Namespace.INHERITED.ordinal,
|
||||
|
||||
val nonRootUseDefault: Boolean = true,
|
||||
val umountModules: Boolean = true,
|
||||
var rules: String = "", // this field is save in ksud!!
|
||||
) : Parcelable {
|
||||
enum class Namespace {
|
||||
INHERITED,
|
||||
GLOBAL,
|
||||
INDIVIDUAL,
|
||||
}
|
||||
|
||||
constructor() : this("")
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package com.rifsxd.ksunext.profile
|
||||
|
||||
/**
|
||||
* @author weishu
|
||||
* @date 2023/6/3.
|
||||
*/
|
||||
enum class Capabilities(val cap: Int, val display: String, val desc: String) {
|
||||
CAP_CHOWN(0, "CHOWN", "Make arbitrary changes to file UIDs and GIDs (see chown(2))"),
|
||||
CAP_DAC_OVERRIDE(1, "DAC_OVERRIDE", "Bypass file read, write, and execute permission checks"),
|
||||
CAP_DAC_READ_SEARCH(2, "DAC_READ_SEARCH", "Bypass file read permission checks and directory read and execute permission checks"),
|
||||
CAP_FOWNER(3, "FOWNER", "Bypass permission checks on operations that normally require the filesystem UID of the process to match the UID of the file (e.g., chmod(2), utime(2)), excluding those operations covered by CAP_DAC_OVERRIDE and CAP_DAC_READ_SEARCH"),
|
||||
CAP_FSETID(4, "FSETID", "Don’t clear set-user-ID and set-group-ID permission bits when a file is modified; set the set-group-ID bit for a file whose GID does not match the filesystem or any of the supplementary GIDs of the calling process"),
|
||||
CAP_KILL(5, "KILL", "Bypass permission checks for sending signals (see kill(2))."),
|
||||
CAP_SETGID(6, "SETGID", "Make arbitrary manipulations of process GIDs and supplementary GID list; allow setgid(2) manipulation of the caller’s effective and real group IDs"),
|
||||
CAP_SETUID(7, "SETUID", "Make arbitrary manipulations of process UIDs (setuid(2), setreuid(2), setresuid(2), setfsuid(2)); allow changing the current process user IDs; allow changing of the current process group ID to any value in the system’s range of legal group IDs"),
|
||||
CAP_SETPCAP(8, "SETPCAP", "If file capabilities are supported: grant or remove any capability in the caller’s permitted capability set to or from any other process. (This property supersedes the obsolete notion of giving a process all capabilities by granting all capabilities in its permitted set, and of removing all capabilities from a process by granting no capabilities in its permitted set. It does not permit any actions that were not permitted before.)"),
|
||||
CAP_LINUX_IMMUTABLE(9, "LINUX_IMMUTABLE", "Set the FS_APPEND_FL and FS_IMMUTABLE_FL inode flags (see chattr(1))."),
|
||||
CAP_NET_BIND_SERVICE(10, "NET_BIND_SERVICE", "Bind a socket to Internet domain"),
|
||||
CAP_NET_BROADCAST(11, "NET_BROADCAST", "Make socket broadcasts, and listen to multicasts"),
|
||||
CAP_NET_ADMIN(12, "NET_ADMIN", "Perform various network-related operations: interface configuration, administration of IP firewall, masquerading, and accounting, modify routing tables, bind to any address for transparent proxying, set type-of-service (TOS), clear driver statistics, set promiscuous mode, enabling multicasting, use setsockopt(2) to set the following socket options: SO_DEBUG, SO_MARK, SO_PRIORITY (for a priority outside the range 0 to 6), SO_RCVBUFFORCE, and SO_SNDBUFFORCE"),
|
||||
CAP_NET_RAW(13, "NET_RAW", "Use RAW and PACKET sockets"),
|
||||
CAP_IPC_LOCK(14, "IPC_LOCK", "Lock memory (mlock(2), mlockall(2), mmap(2), shmctl(2))"),
|
||||
CAP_IPC_OWNER(15, "IPC_OWNER", "Bypass permission checks for operations on System V IPC objects"),
|
||||
CAP_SYS_MODULE(16, "SYS_MODULE", "Load and unload kernel modules (see init_module(2) and delete_module(2)); in kernels before 2.6.25, this also granted rights for various other operations related to kernel modules"),
|
||||
CAP_SYS_RAWIO(17, "SYS_RAWIO", "Perform I/O port operations (iopl(2) and ioperm(2)); access /proc/kcore"),
|
||||
CAP_SYS_CHROOT(18, "SYS_CHROOT", "Use chroot(2)"),
|
||||
CAP_SYS_PTRACE(19, "SYS_PTRACE", "Trace arbitrary processes using ptrace(2)"),
|
||||
CAP_SYS_PACCT(20, "SYS_PACCT", "Use acct(2)"),
|
||||
CAP_SYS_ADMIN(21, "SYS_ADMIN", "Perform a range of system administration operations including: quotactl(2), mount(2), umount(2), swapon(2), swapoff(2), sethostname(2), and setdomainname(2); set and modify process resource limits (setrlimit(2)); perform various network-related operations (e.g., setting privileged socket options, enabling multicasting, interface configuration); perform various IPC operations (e.g., SysV semaphores, POSIX message queues, System V shared memory); allow reboot and kexec_load(2); override /proc/sys kernel tunables; perform ptrace(2) PTRACE_SECCOMP_GET_FILTER operation; perform some tracing and debugging operations (see ptrace(2)); administer the lifetime of kernel tracepoints (tracefs(5)); perform the KEYCTL_CHOWN and KEYCTL_SETPERM keyctl(2) operations; perform the following keyctl(2) operations: KEYCTL_CAPABILITIES, KEYCTL_CAPSQUASH, and KEYCTL_PKEY_ OPERATIONS; set state for the Extensible Authentication Protocol (EAP) kernel module; and override the RLIMIT_NPROC resource limit; allow ioperm/iopl access to I/O ports"),
|
||||
CAP_SYS_BOOT(22, "SYS_BOOT", "Use reboot(2) and kexec_load(2), reboot and load a new kernel for later execution"),
|
||||
CAP_SYS_NICE(23, "SYS_NICE", "Raise process nice value (nice(2), setpriority(2)) and change the nice value for arbitrary processes; set real-time scheduling policies for calling process, and set scheduling policies and priorities for arbitrary processes (sched_setscheduler(2), sched_setparam(2)"),
|
||||
CAP_SYS_RESOURCE(24, "SYS_RESOURCE", "Override resource Limits. Set resource limits (setrlimit(2), prlimit(2)), override quota limits (quota(2), quotactl(2)), override reserved space on ext2 filesystem (ext2_ioctl(2)), override size restrictions on IPC message queues (msg(2)) and system V shared memory segments (shmget(2)), and override the /proc/sys/fs/pipe-size-max limit"),
|
||||
CAP_SYS_TIME(25, "SYS_TIME", "Set system clock (settimeofday(2), stime(2), adjtimex(2)); set real-time (hardware) clock"),
|
||||
CAP_SYS_TTY_CONFIG(26, "SYS_TTY_CONFIG", "Use vhangup(2); employ various privileged ioctl(2) operations on virtual terminals"),
|
||||
CAP_MKNOD(27, "MKNOD", "Create special files using mknod(2)"),
|
||||
CAP_LEASE(28, "LEASE", "Establish leases on arbitrary files (see fcntl(2))"),
|
||||
CAP_AUDIT_WRITE(29, "AUDIT_WRITE", "Write records to kernel auditing log"),
|
||||
CAP_AUDIT_CONTROL(30, "AUDIT_CONTROL", "Enable and disable kernel auditing; change auditing filter rules; retrieve auditing status and filtering rules"),
|
||||
CAP_SETFCAP(31, "SETFCAP", "If file capabilities are supported: grant or remove any capability in any capability set to any file"),
|
||||
CAP_MAC_OVERRIDE(32, "MAC_OVERRIDE", "Override Mandatory Access Control (MAC). Implemented for the Smack Linux Security Module (LSM)"),
|
||||
CAP_MAC_ADMIN(33, "MAC_ADMIN", "Allow MAC configuration or state changes. Implemented for the Smack LSM"),
|
||||
CAP_SYSLOG(34, "SYSLOG", "Perform privileged syslog(2) operations. See syslog(2) for information on which operations require privilege"),
|
||||
CAP_WAKE_ALARM(35, "WAKE_ALARM", "Trigger something that will wake up the system"),
|
||||
CAP_BLOCK_SUSPEND(36, "BLOCK_SUSPEND", "Employ features that can block system suspend"),
|
||||
CAP_AUDIT_READ(37, "AUDIT_READ", "Allow reading the audit log via a multicast netlink socket"),
|
||||
CAP_PERFMON(38, "PERFMON", "Allow performance monitoring via perf_event_open(2)"),
|
||||
CAP_BPF(39, "BPF", "Allow BPF operations via bpf(2)"),
|
||||
CAP_CHECKPOINT_RESTORE(40, "CHECKPOINT_RESTORE", "Allow processes to be checkpointed via checkpoint/restore in user namespace(2)"),
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
package com.rifsxd.ksunext.profile
|
||||
|
||||
/**
|
||||
* https://cs.android.com/android/platform/superproject/main/+/main:system/core/libcutils/include/private/android_filesystem_config.h
|
||||
* @author weishu
|
||||
* @date 2023/6/3.
|
||||
*/
|
||||
enum class Groups(val gid: Int, val display: String, val desc: String) {
|
||||
ROOT(0, "root", "traditional unix root user"),
|
||||
DAEMON(1, "daemon", "Traditional unix daemon owner."),
|
||||
BIN(2, "bin", "Traditional unix binaries owner."),
|
||||
SYS(3, "sys", "A group with the same gid on Linux/macOS/Android."),
|
||||
SYSTEM(1000, "system", "system server"),
|
||||
RADIO(1001, "radio", "telephony subsystem, RIL"),
|
||||
BLUETOOTH(1002, "bluetooth", "bluetooth subsystem"),
|
||||
GRAPHICS(1003, "graphics", "graphics devices"),
|
||||
INPUT(1004, "input", "input devices"),
|
||||
AUDIO(1005, "audio", "audio devices"),
|
||||
CAMERA(1006, "camera", "camera devices"),
|
||||
LOG(1007, "log", "log devices"),
|
||||
COMPASS(1008, "compass", "compass device"),
|
||||
MOUNT(1009, "mount", "mountd socket"),
|
||||
WIFI(1010, "wifi", "wifi subsystem"),
|
||||
ADB(1011, "adb", "android debug bridge (adbd)"),
|
||||
INSTALL(1012, "install", "group for installing packages"),
|
||||
MEDIA(1013, "media", "mediaserver process"),
|
||||
DHCP(1014, "dhcp", "dhcp client"),
|
||||
SDCARD_RW(1015, "sdcard_rw", "external storage write access"),
|
||||
VPN(1016, "vpn", "vpn system"),
|
||||
KEYSTORE(1017, "keystore", "keystore subsystem"),
|
||||
USB(1018, "usb", "USB devices"),
|
||||
DRM(1019, "drm", "DRM server"),
|
||||
MDNSR(1020, "mdnsr", "MulticastDNSResponder (service discovery)"),
|
||||
GPS(1021, "gps", "GPS daemon"),
|
||||
UNUSED1(1022, "unused1", "deprecated, DO NOT USE"),
|
||||
MEDIA_RW(1023, "media_rw", "internal media storage write access"),
|
||||
MTP(1024, "mtp", "MTP USB driver access"),
|
||||
UNUSED2(1025, "unused2", "deprecated, DO NOT USE"),
|
||||
DRMRPC(1026, "drmrpc", "group for drm rpc"),
|
||||
NFC(1027, "nfc", "nfc subsystem"),
|
||||
SDCARD_R(1028, "sdcard_r", "external storage read access"),
|
||||
CLAT(1029, "clat", "clat part of nat464"),
|
||||
LOOP_RADIO(1030, "loop_radio", "loop radio devices"),
|
||||
MEDIA_DRM(1031, "media_drm", "MediaDrm plugins"),
|
||||
PACKAGE_INFO(1032, "package_info", "access to installed package details"),
|
||||
SDCARD_PICS(1033, "sdcard_pics", "external storage photos access"),
|
||||
SDCARD_AV(1034, "sdcard_av", "external storage audio/video access"),
|
||||
SDCARD_ALL(1035, "sdcard_all", "access all users external storage"),
|
||||
LOGD(1036, "logd", "log daemon"),
|
||||
SHARED_RELRO(1037, "shared_relro", "creator of shared GNU RELRO files"),
|
||||
DBUS(1038, "dbus", "dbus-daemon IPC broker process"),
|
||||
TLSDATE(1039, "tlsdate", "tlsdate unprivileged user"),
|
||||
MEDIA_EX(1040, "media_ex", "mediaextractor process"),
|
||||
AUDIOSERVER(1041, "audioserver", "audioserver process"),
|
||||
METRICS_COLL(1042, "metrics_coll", "metrics_collector process"),
|
||||
METRICSD(1043, "metricsd", "metricsd process"),
|
||||
WEBSERV(1044, "webserv", "webservd process"),
|
||||
DEBUGGERD(1045, "debuggerd", "debuggerd unprivileged user"),
|
||||
MEDIA_CODEC(1046, "media_codec", "media_codec process"),
|
||||
CAMERASERVER(1047, "cameraserver", "cameraserver process"),
|
||||
FIREWALL(1048, "firewall", "firewall process"),
|
||||
TRUNKS(1049, "trunks", "trunksd process"),
|
||||
NVRAM(1050, "nvram", "nvram daemon"),
|
||||
DNS(1051, "dns", "DNS resolution daemon (system: netd)"),
|
||||
DNS_TETHER(1052, "dns_tether", "DNS resolution daemon (tether: dnsmasq)"),
|
||||
WEBVIEW_ZYGOTE(1053, "webview_zygote", "WebView zygote process"),
|
||||
VEHICLE_NETWORK(1054, "vehicle_network", "Vehicle network service"),
|
||||
MEDIA_AUDIO(1055, "media_audio", "GID for audio files on internal media storage"),
|
||||
MEDIA_VIDEO(1056, "media_video", "GID for video files on internal media storage"),
|
||||
MEDIA_IMAGE(1057, "media_image", "GID for image files on internal media storage"),
|
||||
TOMBSTONED(1058, "tombstoned", "tombstoned user"),
|
||||
MEDIA_OBB(1059, "media_obb", "GID for OBB files on internal media storage"),
|
||||
ESE(1060, "ese", "embedded secure element (eSE) subsystem"),
|
||||
OTA_UPDATE(1061, "ota_update", "resource tracking UID for OTA updates"),
|
||||
AUTOMOTIVE_EVS(1062, "automotive_evs", "Automotive rear and surround view system"),
|
||||
LOWPAN(1063, "lowpan", "LoWPAN subsystem"),
|
||||
HSM(1064, "lowpan", "hardware security module subsystem"),
|
||||
RESERVED_DISK(1065, "reserved_disk", "GID that has access to reserved disk space"),
|
||||
STATSD(1066, "statsd", "statsd daemon"),
|
||||
INCIDENTD(1067, "incidentd", "incidentd daemon"),
|
||||
SECURE_ELEMENT(1068, "secure_element", "secure element subsystem"),
|
||||
LMKD(1069, "lmkd", "low memory killer daemon"),
|
||||
LLKD(1070, "llkd", "live lock daemon"),
|
||||
IORAPD(1071, "iorapd", "input/output readahead and pin daemon"),
|
||||
GPU_SERVICE(1072, "gpu_service", "GPU service daemon"),
|
||||
NETWORK_STACK(1073, "network_stack", "network stack service"),
|
||||
GSID(1074, "GSID", "GSI service daemon"),
|
||||
FSVERITY_CERT(1075, "fsverity_cert", "fs-verity key ownership in keystore"),
|
||||
CREDSTORE(1076, "credstore", "identity credential manager service"),
|
||||
EXTERNAL_STORAGE(1077, "external_storage", "Full external storage access including USB OTG volumes"),
|
||||
EXT_DATA_RW(1078, "ext_data_rw", "GID for app-private data directories on external storage"),
|
||||
EXT_OBB_RW(1079, "ext_obb_rw", "GID for OBB directories on external storage"),
|
||||
CONTEXT_HUB(1080, "context_hub", "GID for access to the Context Hub"),
|
||||
VIRTUALIZATIONSERVICE(1081, "virtualizationservice", "VirtualizationService daemon"),
|
||||
ARTD(1082, "artd", "ART Service daemon"),
|
||||
UWB(1083, "uwb", "UWB subsystem"),
|
||||
THREAD_NETWORK(1084, "thread_network", "Thread Network subsystem"),
|
||||
DICED(1085, "diced", "Android's DICE daemon"),
|
||||
DMESGD(1086, "dmesgd", "dmesg parsing daemon for kernel report collection"),
|
||||
JC_WEAVER(1087, "jc_weaver", "Javacard Weaver HAL - to manage omapi ARA rules"),
|
||||
JC_STRONGBOX(1088, "jc_strongbox", "Javacard Strongbox HAL - to manage omapi ARA rules"),
|
||||
JC_IDENTITYCRED(1089, "jc_identitycred", "Javacard Identity Cred HAL - to manage omapi ARA rules"),
|
||||
SDK_SANDBOX(1090, "sdk_sandbox", "SDK sandbox virtual UID"),
|
||||
SECURITY_LOG_WRITER(1091, "security_log_writer", "write to security log"),
|
||||
PRNG_SEEDER(1092, "prng_seeder", "PRNG seeder daemon"),
|
||||
|
||||
SHELL(2000, "shell", "adb and debug shell user"),
|
||||
CACHE(2001, "cache", "cache access"),
|
||||
DIAG(2002, "diag", "access to diagnostic resources"),
|
||||
|
||||
/* The 3000 series are intended for use as supplemental group id's only.
|
||||
* They indicate special Android capabilities that the kernel is aware of. */
|
||||
NET_BT_ADMIN(3001, "net_bt_admin", "bluetooth: create any socket"),
|
||||
NET_BT(3002, "net_bt", "bluetooth: create sco, rfcomm or l2cap sockets"),
|
||||
INET(3003, "inet", "can create AF_INET and AF_INET6 sockets"),
|
||||
NET_RAW(3004, "net_raw", "can create raw INET sockets"),
|
||||
NET_ADMIN(3005, "net_admin", "can configure interfaces and routing tables."),
|
||||
NET_BW_STATS(3006, "net_bw_stats", "read bandwidth statistics"),
|
||||
NET_BW_ACCT(3007, "net_bw_acct", "change bandwidth statistics accounting"),
|
||||
NET_BT_STACK(3008, "net_bt_stack", "access to various bluetooth management functions"),
|
||||
READPROC(3009, "readproc", "Allow /proc read access"),
|
||||
WAKELOCK(3010, "wakelock", "Allow system wakelock read/write access"),
|
||||
UHID(3011, "uhid", "Allow read/write to /dev/uhid node"),
|
||||
READTRACEFS(3012, "readtracefs", "Allow tracefs read"),
|
||||
|
||||
EVERYBODY(9997, "everybody", "Shared external storage read/write"),
|
||||
MISC(9998, "misc", "Access to misc storage"),
|
||||
NOBODY(9999, "nobody", "Reserved"),
|
||||
APP(10000, "app", "Access to app data"),
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
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
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.animation.AnimatedContentTransitionScope
|
||||
import androidx.compose.animation.EnterTransition
|
||||
import androidx.compose.animation.ExitTransition
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.displayCutout
|
||||
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.Icon
|
||||
import androidx.compose.material3.NavigationBar
|
||||
import androidx.compose.material3.NavigationBarItem
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavBackStackEntry
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import com.ramcosta.composedestinations.DestinationsNavHost
|
||||
import com.ramcosta.composedestinations.animations.NavHostAnimatedDestinationStyle
|
||||
import com.ramcosta.composedestinations.generated.destinations.ExecuteModuleActionScreenDestination
|
||||
import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
|
||||
import com.ramcosta.composedestinations.generated.NavGraphs
|
||||
import com.ramcosta.composedestinations.utils.isRouteOnBackStackAsState
|
||||
import com.ramcosta.composedestinations.utils.rememberDestinationsNavigator
|
||||
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.LocalSnackbarHost
|
||||
import com.rifsxd.ksunext.ui.util.rootAvailable
|
||||
import com.rifsxd.ksunext.ui.util.install
|
||||
import com.rifsxd.ksunext.ui.util.isSuCompatDisabled
|
||||
import com.rifsxd.ksunext.ui.screen.FlashIt
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
||||
// Enable edge to edge
|
||||
enableEdgeToEdge()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
window.isNavigationBarContrastEnforced = false
|
||||
}
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val isManager = Natives.becomeManager(ksuApp.packageName)
|
||||
if (isManager) install()
|
||||
|
||||
val zipUri: Uri? = when (intent?.action) {
|
||||
Intent.ACTION_VIEW, Intent.ACTION_SEND -> {
|
||||
val uri = intent.data ?: intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
|
||||
uri?.let {
|
||||
val name = when (it.scheme) {
|
||||
"file" -> it.lastPathSegment ?: ""
|
||||
"content" -> {
|
||||
contentResolver.query(it, null, null, null, null)?.use { cursor ->
|
||||
val nameIndex = cursor.getColumnIndex(android.provider.OpenableColumns.DISPLAY_NAME)
|
||||
if (cursor.moveToFirst() && nameIndex != -1) {
|
||||
cursor.getString(nameIndex)
|
||||
} else {
|
||||
it.lastPathSegment ?: ""
|
||||
}
|
||||
} ?: (it.lastPathSegment ?: "")
|
||||
}
|
||||
else -> it.lastPathSegment ?: ""
|
||||
}
|
||||
if (name.lowercase().endsWith(".zip")) it else null
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
setContent {
|
||||
// Read AMOLED mode preference
|
||||
val prefs = getSharedPreferences("settings", Context.MODE_PRIVATE)
|
||||
val amoledMode = prefs.getBoolean("enable_amoled", false)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
bottomBar = {
|
||||
AnimatedVisibility(
|
||||
visible = showBottomBar,
|
||||
enter = slideInVertically(initialOffsetY = { it }) + fadeIn(),
|
||||
exit = slideOutVertically(targetOffsetY = { it }) + fadeOut()
|
||||
) {
|
||||
BottomBar(navController)
|
||||
}
|
||||
},
|
||||
contentWindowInsets = WindowInsets(0, 0, 0, 0)
|
||||
) { innerPadding ->
|
||||
CompositionLocalProvider(
|
||||
LocalSnackbarHost provides snackBarHostState,
|
||||
) {
|
||||
DestinationsNavHost(
|
||||
modifier = Modifier.padding(innerPadding),
|
||||
navGraph = NavGraphs.root,
|
||||
navController = navController,
|
||||
defaultTransitions = object : NavHostAnimatedDestinationStyle() {
|
||||
override val enterTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition
|
||||
get() = { fadeIn(animationSpec = tween(340)) }
|
||||
override val exitTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition
|
||||
get() = { fadeOut(animationSpec = tween(340)) }
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BottomBar(navController: NavHostController) {
|
||||
val navigator = navController.rememberDestinationsNavigator()
|
||||
val isManager = Natives.becomeManager(ksuApp.packageName)
|
||||
val fullFeatured = isManager && !Natives.requireNewKernel() && rootAvailable()
|
||||
val suCompatDisabled = isSuCompatDisabled()
|
||||
|
||||
NavigationBar(
|
||||
tonalElevation = 8.dp,
|
||||
windowInsets = WindowInsets.systemBars.union(WindowInsets.displayCutout).only(
|
||||
WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom
|
||||
)
|
||||
) {
|
||||
BottomBarDestination.entries
|
||||
.filter {
|
||||
// Hide SuperUser and Module when su compat is enabled
|
||||
if (suCompatDisabled) {
|
||||
it != BottomBarDestination.SuperUser && it != BottomBarDestination.Module
|
||||
} 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 = {
|
||||
if (isCurrentDestOnBackStack) {
|
||||
Icon(destination.iconSelected, stringResource(destination.label))
|
||||
} else {
|
||||
Icon(destination.iconNotSelected, stringResource(destination.label))
|
||||
}
|
||||
},
|
||||
label = { Text(stringResource(destination.label)) },
|
||||
alwaysShowLabel = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
package com.rifsxd.ksunext.ui.component
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.ElevatedCard
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.TextLinkStyles
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.fromHtml
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import com.rifsxd.ksunext.BuildConfig
|
||||
import com.rifsxd.ksunext.R
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun AboutCard() {
|
||||
ElevatedCard(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(8.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(24.dp)
|
||||
) {
|
||||
AboutCardContent()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AboutDialog(dismiss: () -> Unit) {
|
||||
Dialog(
|
||||
onDismissRequest = { dismiss() }
|
||||
) {
|
||||
AboutCard()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AboutCardContent() {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Row {
|
||||
Surface(
|
||||
modifier = Modifier.size(40.dp),
|
||||
color = colorResource(id = R.color.ic_launcher_background),
|
||||
shape = CircleShape
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.ic_launcher_foreground),
|
||||
contentDescription = "icon",
|
||||
modifier = Modifier.scale(1.5f)
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
|
||||
Column {
|
||||
|
||||
Text(
|
||||
stringResource(id = R.string.app_name),
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
fontSize = 18.sp
|
||||
)
|
||||
Text(
|
||||
BuildConfig.VERSION_NAME,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
fontSize = 14.sp
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
val annotatedString = AnnotatedString.Companion.fromHtml(
|
||||
htmlString = stringResource(
|
||||
id = R.string.about_source_code,
|
||||
"<b><a href=\"https://github.com/KernelSU-Next/KernelSU-Next\">GitHub</a></b>"
|
||||
),
|
||||
linkStyles = TextLinkStyles(
|
||||
style = SpanStyle(
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
textDecoration = TextDecoration.Underline
|
||||
),
|
||||
pressedStyle = SpanStyle(
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
background = MaterialTheme.colorScheme.secondaryContainer,
|
||||
textDecoration = TextDecoration.Underline
|
||||
)
|
||||
)
|
||||
)
|
||||
Text(
|
||||
text = annotatedString,
|
||||
style = TextStyle(
|
||||
fontSize = 14.sp
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,453 +0,0 @@
|
||||
package com.rifsxd.ksunext.ui.component
|
||||
|
||||
import android.graphics.text.LineBreaker
|
||||
import android.os.Build
|
||||
import android.os.Parcelable
|
||||
import android.text.Layout
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.util.Log
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.Saver
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.utils.NoCopySpannableFactory
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.ReceiveChannel
|
||||
import kotlinx.coroutines.flow.FlowCollector
|
||||
import kotlinx.coroutines.flow.consumeAsFlow
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
private const val TAG = "DialogComponent"
|
||||
|
||||
interface ConfirmDialogVisuals : Parcelable {
|
||||
val title: String
|
||||
val content: String
|
||||
val isMarkdown: Boolean
|
||||
val confirm: String?
|
||||
val dismiss: String?
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
private data class ConfirmDialogVisualsImpl(
|
||||
override val title: String,
|
||||
override val content: String,
|
||||
override val isMarkdown: Boolean,
|
||||
override val confirm: String?,
|
||||
override val dismiss: String?,
|
||||
) : ConfirmDialogVisuals {
|
||||
companion object {
|
||||
val Empty: ConfirmDialogVisuals = ConfirmDialogVisualsImpl("", "", false, null, null)
|
||||
}
|
||||
}
|
||||
|
||||
interface DialogHandle {
|
||||
val isShown: Boolean
|
||||
val dialogType: String
|
||||
fun show()
|
||||
fun hide()
|
||||
}
|
||||
|
||||
interface LoadingDialogHandle : DialogHandle {
|
||||
suspend fun <R> withLoading(block: suspend () -> R): R
|
||||
fun showLoading()
|
||||
}
|
||||
|
||||
sealed interface ConfirmResult {
|
||||
object Confirmed : ConfirmResult
|
||||
object Canceled : ConfirmResult
|
||||
}
|
||||
|
||||
interface ConfirmDialogHandle : DialogHandle {
|
||||
val visuals: ConfirmDialogVisuals
|
||||
|
||||
fun showConfirm(
|
||||
title: String,
|
||||
content: String,
|
||||
markdown: Boolean = false,
|
||||
confirm: String? = null,
|
||||
dismiss: String? = null
|
||||
)
|
||||
|
||||
suspend fun awaitConfirm(
|
||||
title: String,
|
||||
content: String,
|
||||
markdown: Boolean = false,
|
||||
confirm: String? = null,
|
||||
dismiss: String? = null
|
||||
): ConfirmResult
|
||||
}
|
||||
|
||||
private abstract class DialogHandleBase(
|
||||
val visible: MutableState<Boolean>,
|
||||
val coroutineScope: CoroutineScope
|
||||
) : DialogHandle {
|
||||
override val isShown: Boolean
|
||||
get() = visible.value
|
||||
|
||||
override fun show() {
|
||||
coroutineScope.launch {
|
||||
visible.value = true
|
||||
}
|
||||
}
|
||||
|
||||
final override fun hide() {
|
||||
coroutineScope.launch {
|
||||
visible.value = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return dialogType
|
||||
}
|
||||
}
|
||||
|
||||
private class LoadingDialogHandleImpl(
|
||||
visible: MutableState<Boolean>,
|
||||
coroutineScope: CoroutineScope
|
||||
) : LoadingDialogHandle, DialogHandleBase(visible, coroutineScope) {
|
||||
override suspend fun <R> withLoading(block: suspend () -> R): R {
|
||||
return coroutineScope.async {
|
||||
try {
|
||||
visible.value = true
|
||||
block()
|
||||
} finally {
|
||||
visible.value = false
|
||||
}
|
||||
}.await()
|
||||
}
|
||||
|
||||
override fun showLoading() {
|
||||
show()
|
||||
}
|
||||
|
||||
override val dialogType: String get() = "LoadingDialog"
|
||||
}
|
||||
|
||||
typealias NullableCallback = (() -> Unit)?
|
||||
|
||||
interface ConfirmCallback {
|
||||
|
||||
val onConfirm: NullableCallback
|
||||
|
||||
val onDismiss: NullableCallback
|
||||
|
||||
val isEmpty: Boolean get() = onConfirm == null && onDismiss == null
|
||||
|
||||
companion object {
|
||||
operator fun invoke(onConfirmProvider: () -> NullableCallback, onDismissProvider: () -> NullableCallback): ConfirmCallback {
|
||||
return object : ConfirmCallback {
|
||||
override val onConfirm: NullableCallback
|
||||
get() = onConfirmProvider()
|
||||
override val onDismiss: NullableCallback
|
||||
get() = onDismissProvider()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ConfirmDialogHandleImpl(
|
||||
visible: MutableState<Boolean>,
|
||||
coroutineScope: CoroutineScope,
|
||||
callback: ConfirmCallback,
|
||||
override var visuals: ConfirmDialogVisuals = ConfirmDialogVisualsImpl.Empty,
|
||||
private val resultFlow: ReceiveChannel<ConfirmResult>
|
||||
) : ConfirmDialogHandle, DialogHandleBase(visible, coroutineScope) {
|
||||
private class ResultCollector(
|
||||
private val callback: ConfirmCallback
|
||||
) : FlowCollector<ConfirmResult> {
|
||||
fun handleResult(result: ConfirmResult) {
|
||||
Log.d(TAG, "handleResult: ${result.javaClass.simpleName}")
|
||||
when (result) {
|
||||
ConfirmResult.Confirmed -> onConfirm()
|
||||
ConfirmResult.Canceled -> onDismiss()
|
||||
}
|
||||
}
|
||||
|
||||
fun onConfirm() {
|
||||
callback.onConfirm?.invoke()
|
||||
}
|
||||
|
||||
fun onDismiss() {
|
||||
callback.onDismiss?.invoke()
|
||||
}
|
||||
|
||||
override suspend fun emit(value: ConfirmResult) {
|
||||
handleResult(value)
|
||||
}
|
||||
}
|
||||
|
||||
private val resultCollector = ResultCollector(callback)
|
||||
|
||||
private var awaitContinuation: CancellableContinuation<ConfirmResult>? = null
|
||||
|
||||
private val isCallbackEmpty = callback.isEmpty
|
||||
|
||||
init {
|
||||
coroutineScope.launch {
|
||||
resultFlow
|
||||
.consumeAsFlow()
|
||||
.onEach { result ->
|
||||
awaitContinuation?.let {
|
||||
awaitContinuation = null
|
||||
if (it.isActive) {
|
||||
it.resume(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
.onEach { hide() }
|
||||
.collect(resultCollector)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun awaitResult(): ConfirmResult {
|
||||
return suspendCancellableCoroutine {
|
||||
awaitContinuation = it.apply {
|
||||
if (isCallbackEmpty) {
|
||||
invokeOnCancellation {
|
||||
visible.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateVisuals(visuals: ConfirmDialogVisuals) {
|
||||
this.visuals = visuals
|
||||
}
|
||||
|
||||
override fun show() {
|
||||
if (visuals !== ConfirmDialogVisualsImpl.Empty) {
|
||||
super.show()
|
||||
} else {
|
||||
throw UnsupportedOperationException("can't show confirm dialog with the Empty visuals")
|
||||
}
|
||||
}
|
||||
|
||||
override fun showConfirm(
|
||||
title: String,
|
||||
content: String,
|
||||
markdown: Boolean,
|
||||
confirm: String?,
|
||||
dismiss: String?
|
||||
) {
|
||||
coroutineScope.launch {
|
||||
updateVisuals(ConfirmDialogVisualsImpl(title, content, markdown, confirm, dismiss))
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun awaitConfirm(
|
||||
title: String,
|
||||
content: String,
|
||||
markdown: Boolean,
|
||||
confirm: String?,
|
||||
dismiss: String?
|
||||
): ConfirmResult {
|
||||
coroutineScope.launch {
|
||||
updateVisuals(ConfirmDialogVisualsImpl(title, content, markdown, confirm, dismiss))
|
||||
show()
|
||||
}
|
||||
return awaitResult()
|
||||
}
|
||||
|
||||
override val dialogType: String get() = "ConfirmDialog"
|
||||
|
||||
override fun toString(): String {
|
||||
return "${super.toString()}(visuals: $visuals)"
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun Saver(
|
||||
visible: MutableState<Boolean>,
|
||||
coroutineScope: CoroutineScope,
|
||||
callback: ConfirmCallback,
|
||||
resultChannel: ReceiveChannel<ConfirmResult>
|
||||
) = Saver<ConfirmDialogHandle, ConfirmDialogVisuals>(
|
||||
save = {
|
||||
it.visuals
|
||||
},
|
||||
restore = {
|
||||
Log.d(TAG, "ConfirmDialog restore, visuals: $it")
|
||||
ConfirmDialogHandleImpl(visible, coroutineScope, callback, it, resultChannel)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class CustomDialogHandleImpl(
|
||||
visible: MutableState<Boolean>,
|
||||
coroutineScope: CoroutineScope
|
||||
) : DialogHandleBase(visible, coroutineScope) {
|
||||
override val dialogType: String get() = "CustomDialog"
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun rememberLoadingDialog(): LoadingDialogHandle {
|
||||
val visible = remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
if (visible.value) {
|
||||
LoadingDialog()
|
||||
}
|
||||
|
||||
return remember {
|
||||
LoadingDialogHandleImpl(visible, coroutineScope)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun rememberConfirmDialog(visuals: ConfirmDialogVisuals, callback: ConfirmCallback): ConfirmDialogHandle {
|
||||
val visible = rememberSaveable {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val resultChannel = remember {
|
||||
Channel<ConfirmResult>()
|
||||
}
|
||||
|
||||
val handle = rememberSaveable(
|
||||
saver = ConfirmDialogHandleImpl.Saver(visible, coroutineScope, callback, resultChannel),
|
||||
init = {
|
||||
ConfirmDialogHandleImpl(visible, coroutineScope, callback, visuals, resultChannel)
|
||||
}
|
||||
)
|
||||
|
||||
if (visible.value) {
|
||||
ConfirmDialog(
|
||||
handle.visuals,
|
||||
confirm = { coroutineScope.launch { resultChannel.send(ConfirmResult.Confirmed) } },
|
||||
dismiss = { coroutineScope.launch { resultChannel.send(ConfirmResult.Canceled) } }
|
||||
)
|
||||
}
|
||||
|
||||
return handle
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun rememberConfirmCallback(onConfirm: NullableCallback, onDismiss: NullableCallback): ConfirmCallback {
|
||||
val currentOnConfirm by rememberUpdatedState(newValue = onConfirm)
|
||||
val currentOnDismiss by rememberUpdatedState(newValue = onDismiss)
|
||||
return remember {
|
||||
ConfirmCallback({ currentOnConfirm }, { currentOnDismiss })
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun rememberConfirmDialog(onConfirm: NullableCallback = null, onDismiss: NullableCallback = null): ConfirmDialogHandle {
|
||||
return rememberConfirmDialog(rememberConfirmCallback(onConfirm, onDismiss))
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun rememberConfirmDialog(callback: ConfirmCallback): ConfirmDialogHandle {
|
||||
return rememberConfirmDialog(ConfirmDialogVisualsImpl.Empty, callback)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun rememberCustomDialog(composable: @Composable (dismiss: () -> Unit) -> Unit): DialogHandle {
|
||||
val visible = rememberSaveable {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
if (visible.value) {
|
||||
composable { visible.value = false }
|
||||
}
|
||||
return remember {
|
||||
CustomDialogHandleImpl(visible, coroutineScope)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LoadingDialog() {
|
||||
Dialog(
|
||||
onDismissRequest = {},
|
||||
properties = DialogProperties(dismissOnClickOutside = false, dismissOnBackPress = false)
|
||||
) {
|
||||
Surface(
|
||||
modifier = Modifier.size(100.dp), shape = RoundedCornerShape(8.dp)
|
||||
) {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
CircularProgressIndicator()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ConfirmDialog(visuals: ConfirmDialogVisuals, confirm: () -> Unit, dismiss: () -> Unit) {
|
||||
AlertDialog(
|
||||
onDismissRequest = {
|
||||
dismiss()
|
||||
},
|
||||
title = {
|
||||
Text(text = visuals.title)
|
||||
},
|
||||
text = {
|
||||
if (visuals.isMarkdown) {
|
||||
MarkdownContent(content = visuals.content)
|
||||
} else {
|
||||
Text(text = visuals.content)
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(onClick = confirm) {
|
||||
Text(text = visuals.confirm ?: stringResource(id = android.R.string.ok))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = dismiss) {
|
||||
Text(text = visuals.dismiss ?: stringResource(id = android.R.string.cancel))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MarkdownContent(content: String) {
|
||||
val contentColor = LocalContentColor.current
|
||||
|
||||
AndroidView(
|
||||
factory = { context ->
|
||||
TextView(context).apply {
|
||||
movementMethod = LinkMovementMethod.getInstance()
|
||||
setSpannableFactory(NoCopySpannableFactory.getInstance())
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
breakStrategy = LineBreaker.BREAK_STRATEGY_SIMPLE
|
||||
}
|
||||
hyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE
|
||||
layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
update = {
|
||||
Markwon.create(it.context).setMarkdown(it, content)
|
||||
it.setTextColor(contentColor.toArgb())
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.rifsxd.ksunext.ui.component
|
||||
|
||||
import androidx.compose.foundation.focusable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.input.key.KeyEvent
|
||||
import androidx.compose.ui.input.key.onKeyEvent
|
||||
|
||||
@Composable
|
||||
fun KeyEventBlocker(predicate: (KeyEvent) -> Boolean) {
|
||||
val requester = remember { FocusRequester() }
|
||||
Box(
|
||||
Modifier
|
||||
.onKeyEvent {
|
||||
predicate(it)
|
||||
}
|
||||
.focusRequester(requester)
|
||||
.focusable()
|
||||
)
|
||||
LaunchedEffect(Unit) {
|
||||
requester.requestFocus()
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
package com.rifsxd.ksunext.ui.component
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.safeDrawing
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.focus.onFocusChanged
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
private const val TAG = "SearchBar"
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun SearchAppBar(
|
||||
title: @Composable () -> Unit,
|
||||
searchText: String,
|
||||
onSearchTextChange: (String) -> Unit,
|
||||
onClearClick: () -> Unit,
|
||||
onBackClick: (() -> Unit)? = null,
|
||||
onConfirm: (() -> Unit)? = null,
|
||||
dropdownContent: @Composable (() -> Unit)? = null,
|
||||
scrollBehavior: TopAppBarScrollBehavior? = null
|
||||
) {
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
var onSearch by remember { mutableStateOf(false) }
|
||||
|
||||
if (onSearch) {
|
||||
LaunchedEffect(Unit) { focusRequester.requestFocus() }
|
||||
}
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
keyboardController?.hide()
|
||||
}
|
||||
}
|
||||
|
||||
TopAppBar(
|
||||
title = {
|
||||
Box {
|
||||
AnimatedVisibility(
|
||||
modifier = Modifier.align(Alignment.CenterStart),
|
||||
visible = !onSearch,
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut(),
|
||||
content = { title() }
|
||||
)
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = onSearch,
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut()
|
||||
) {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 2.dp, bottom = 2.dp, end = if (onBackClick != null) 0.dp else 14.dp)
|
||||
.focusRequester(focusRequester)
|
||||
.onFocusChanged { focusState ->
|
||||
if (focusState.isFocused) onSearch = true
|
||||
Log.d(TAG, "onFocusChanged: $focusState")
|
||||
},
|
||||
value = searchText,
|
||||
onValueChange = onSearchTextChange,
|
||||
trailingIcon = {
|
||||
IconButton(
|
||||
onClick = {
|
||||
onSearch = false
|
||||
keyboardController?.hide()
|
||||
onClearClick()
|
||||
},
|
||||
content = { Icon(Icons.Filled.Close, null) }
|
||||
)
|
||||
},
|
||||
maxLines = 1,
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done),
|
||||
keyboardActions = KeyboardActions(onDone = {
|
||||
keyboardController?.hide()
|
||||
onConfirm?.invoke()
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
navigationIcon = {
|
||||
if (onBackClick != null) {
|
||||
IconButton(
|
||||
onClick = onBackClick,
|
||||
content = { Icon(Icons.AutoMirrored.Outlined.ArrowBack, null) }
|
||||
)
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
AnimatedVisibility(
|
||||
visible = !onSearch
|
||||
) {
|
||||
IconButton(
|
||||
onClick = { onSearch = true },
|
||||
content = { Icon(Icons.Filled.Search, null) }
|
||||
)
|
||||
}
|
||||
|
||||
if (dropdownContent != null) {
|
||||
dropdownContent()
|
||||
}
|
||||
|
||||
},
|
||||
windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
|
||||
scrollBehavior = scrollBehavior
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Preview
|
||||
@Composable
|
||||
private fun SearchAppBarPreview() {
|
||||
var searchText by remember { mutableStateOf("") }
|
||||
SearchAppBar(
|
||||
title = { Text("Search text") },
|
||||
searchText = searchText,
|
||||
onSearchTextChange = { searchText = it },
|
||||
onClearClick = { searchText = "" }
|
||||
)
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package com.rifsxd.ksunext.ui.component
|
||||
|
||||
import androidx.compose.foundation.LocalIndication
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.selection.toggleable
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.RadioButton
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import com.dergoogler.mmrl.ui.component.LabelItem
|
||||
import com.dergoogler.mmrl.ui.component.text.TextRow
|
||||
|
||||
@Composable
|
||||
fun SwitchItem(
|
||||
icon: ImageVector? = null,
|
||||
title: String,
|
||||
summary: String? = null,
|
||||
checked: Boolean,
|
||||
enabled: Boolean = true,
|
||||
beta: Boolean = false,
|
||||
onCheckedChange: (Boolean) -> Unit,
|
||||
) {
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
val stateAlpha = remember(checked, enabled) { Modifier.alpha(if (enabled) 1f else 0.5f) }
|
||||
|
||||
ListItem(
|
||||
modifier = Modifier
|
||||
.toggleable(
|
||||
value = checked,
|
||||
interactionSource = interactionSource,
|
||||
role = Role.Switch,
|
||||
enabled = enabled,
|
||||
indication = LocalIndication.current,
|
||||
onValueChange = onCheckedChange
|
||||
),
|
||||
headlineContent = {
|
||||
TextRow(
|
||||
leadingContent = if (beta) {
|
||||
{
|
||||
LabelItem(
|
||||
modifier = Modifier.then(stateAlpha),
|
||||
text = "Beta"
|
||||
)
|
||||
}
|
||||
} else null
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.then(stateAlpha),
|
||||
text = title,
|
||||
)
|
||||
}
|
||||
},
|
||||
leadingContent = icon?.let {
|
||||
{
|
||||
Icon(
|
||||
modifier = Modifier.then(stateAlpha),
|
||||
imageVector = icon,
|
||||
contentDescription = title
|
||||
)
|
||||
}
|
||||
},
|
||||
trailingContent = {
|
||||
Switch(
|
||||
checked = checked,
|
||||
enabled = enabled,
|
||||
onCheckedChange = onCheckedChange,
|
||||
interactionSource = interactionSource
|
||||
)
|
||||
},
|
||||
supportingContent = {
|
||||
if (summary != null) {
|
||||
Text(
|
||||
modifier = Modifier.then(stateAlpha),
|
||||
text = summary
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RadioItem(
|
||||
title: String,
|
||||
selected: Boolean,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(title)
|
||||
},
|
||||
leadingContent = {
|
||||
RadioButton(selected = selected, onClick = onClick)
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package com.rifsxd.ksunext.ui.component.profile
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.rifsxd.ksunext.Natives
|
||||
import com.rifsxd.ksunext.R
|
||||
import com.rifsxd.ksunext.ui.component.SwitchItem
|
||||
|
||||
@Composable
|
||||
fun AppProfileConfig(
|
||||
modifier: Modifier = Modifier,
|
||||
fixedName: Boolean,
|
||||
enabled: Boolean,
|
||||
profile: Natives.Profile,
|
||||
onProfileChange: (Natives.Profile) -> Unit,
|
||||
) {
|
||||
Column(modifier = modifier) {
|
||||
if (!fixedName) {
|
||||
OutlinedTextField(
|
||||
label = { Text(stringResource(R.string.profile_name)) },
|
||||
value = profile.name,
|
||||
onValueChange = { onProfileChange(profile.copy(name = it)) }
|
||||
)
|
||||
}
|
||||
|
||||
SwitchItem(
|
||||
title = stringResource(R.string.profile_umount_modules),
|
||||
summary = stringResource(R.string.profile_umount_modules_summary),
|
||||
checked = if (enabled) {
|
||||
profile.umountModules
|
||||
} else {
|
||||
Natives.isDefaultUmountModules()
|
||||
},
|
||||
enabled = enabled,
|
||||
onCheckedChange = {
|
||||
onProfileChange(
|
||||
profile.copy(
|
||||
umountModules = it,
|
||||
nonRootUseDefault = false
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun AppProfileConfigPreview() {
|
||||
var profile by remember { mutableStateOf(Natives.Profile("")) }
|
||||
AppProfileConfig(fixedName = true, enabled = false, profile = profile) {
|
||||
profile = it
|
||||
}
|
||||
}
|
||||
@@ -1,487 +0,0 @@
|
||||
package com.rifsxd.ksunext.ui.component.profile
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowDropDown
|
||||
import androidx.compose.material.icons.filled.ArrowDropUp
|
||||
import androidx.compose.material3.AssistChip
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.MenuAnchorType
|
||||
import androidx.compose.material3.OutlinedCard
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.OutlinedTextFieldDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.text.isDigitsOnly
|
||||
import com.maxkeppeker.sheets.core.models.base.Header
|
||||
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
|
||||
import com.maxkeppeler.sheets.input.InputDialog
|
||||
import com.maxkeppeler.sheets.input.models.InputHeader
|
||||
import com.maxkeppeler.sheets.input.models.InputSelection
|
||||
import com.maxkeppeler.sheets.input.models.InputTextField
|
||||
import com.maxkeppeler.sheets.input.models.InputTextFieldType
|
||||
import com.maxkeppeler.sheets.input.models.ValidationResult
|
||||
import com.maxkeppeler.sheets.list.ListDialog
|
||||
import com.maxkeppeler.sheets.list.models.ListOption
|
||||
import com.maxkeppeler.sheets.list.models.ListSelection
|
||||
import com.rifsxd.ksunext.Natives
|
||||
import com.rifsxd.ksunext.R
|
||||
import com.rifsxd.ksunext.profile.Capabilities
|
||||
import com.rifsxd.ksunext.profile.Groups
|
||||
import com.rifsxd.ksunext.ui.component.rememberCustomDialog
|
||||
import com.rifsxd.ksunext.ui.util.isSepolicyValid
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun RootProfileConfig(
|
||||
modifier: Modifier = Modifier,
|
||||
fixedName: Boolean,
|
||||
profile: Natives.Profile,
|
||||
onProfileChange: (Natives.Profile) -> Unit,
|
||||
) {
|
||||
Column(modifier = modifier) {
|
||||
if (!fixedName) {
|
||||
OutlinedTextField(
|
||||
label = { Text(stringResource(R.string.profile_name)) },
|
||||
value = profile.name,
|
||||
onValueChange = { onProfileChange(profile.copy(name = it)) }
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
val currentNamespace = when (profile.namespace) {
|
||||
Natives.Profile.Namespace.INHERITED.ordinal -> stringResource(R.string.profile_namespace_inherited)
|
||||
Natives.Profile.Namespace.GLOBAL.ordinal -> stringResource(R.string.profile_namespace_global)
|
||||
Natives.Profile.Namespace.INDIVIDUAL.ordinal -> stringResource(R.string.profile_namespace_individual)
|
||||
else -> stringResource(R.string.profile_namespace_inherited)
|
||||
}
|
||||
ListItem(headlineContent = {
|
||||
ExposedDropdownMenuBox(
|
||||
expanded = expanded,
|
||||
onExpandedChange = { expanded = !expanded }
|
||||
) {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier
|
||||
.menuAnchor(MenuAnchorType.PrimaryNotEditable)
|
||||
.fillMaxWidth(),
|
||||
readOnly = true,
|
||||
label = { Text(stringResource(R.string.profile_namespace)) },
|
||||
value = currentNamespace,
|
||||
onValueChange = {},
|
||||
trailingIcon = {
|
||||
if (expanded) Icon(Icons.Filled.ArrowDropUp, null)
|
||||
else Icon(Icons.Filled.ArrowDropDown, null)
|
||||
},
|
||||
)
|
||||
ExposedDropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false }
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.profile_namespace_inherited)) },
|
||||
onClick = {
|
||||
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.INHERITED.ordinal))
|
||||
expanded = false
|
||||
},
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.profile_namespace_global)) },
|
||||
onClick = {
|
||||
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.GLOBAL.ordinal))
|
||||
expanded = false
|
||||
},
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.profile_namespace_individual)) },
|
||||
onClick = {
|
||||
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.INDIVIDUAL.ordinal))
|
||||
expanded = false
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
*/
|
||||
|
||||
UidPanel(uid = profile.uid, label = "uid", onUidChange = {
|
||||
onProfileChange(
|
||||
profile.copy(
|
||||
uid = it,
|
||||
rootUseDefault = false
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
UidPanel(uid = profile.gid, label = "gid", onUidChange = {
|
||||
onProfileChange(
|
||||
profile.copy(
|
||||
gid = it,
|
||||
rootUseDefault = false
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
val selectedGroups = profile.groups.ifEmpty { listOf(0) }.let { e ->
|
||||
e.mapNotNull { g ->
|
||||
Groups.entries.find { it.gid == g }
|
||||
}
|
||||
}
|
||||
GroupsPanel(selectedGroups) {
|
||||
onProfileChange(
|
||||
profile.copy(
|
||||
groups = it.map { group -> group.gid }.ifEmpty { listOf(0) },
|
||||
rootUseDefault = false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val selectedCaps = profile.capabilities.mapNotNull { e ->
|
||||
Capabilities.entries.find { it.cap == e }
|
||||
}
|
||||
|
||||
CapsPanel(selectedCaps) {
|
||||
onProfileChange(
|
||||
profile.copy(
|
||||
capabilities = it.map { cap -> cap.cap },
|
||||
rootUseDefault = false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
SELinuxPanel(profile = profile, onSELinuxChange = { domain, rules ->
|
||||
onProfileChange(
|
||||
profile.copy(
|
||||
context = domain,
|
||||
rules = rules,
|
||||
rootUseDefault = false
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun GroupsPanel(selected: List<Groups>, closeSelection: (selection: Set<Groups>) -> Unit) {
|
||||
val selectGroupsDialog = rememberCustomDialog { dismiss: () -> Unit ->
|
||||
val groups = Groups.entries.toTypedArray().sortedWith(
|
||||
compareBy<Groups> { if (selected.contains(it)) 0 else 1 }
|
||||
.then(compareBy {
|
||||
when (it) {
|
||||
Groups.ROOT -> 0
|
||||
Groups.SYSTEM -> 1
|
||||
Groups.SHELL -> 2
|
||||
else -> Int.MAX_VALUE
|
||||
}
|
||||
})
|
||||
.then(compareBy { it.name })
|
||||
|
||||
)
|
||||
val options = groups.map { value ->
|
||||
ListOption(
|
||||
titleText = value.display,
|
||||
subtitleText = value.desc,
|
||||
selected = selected.contains(value),
|
||||
)
|
||||
}
|
||||
|
||||
val selection = HashSet(selected)
|
||||
ListDialog(
|
||||
state = rememberUseCaseState(visible = true, onFinishedRequest = {
|
||||
closeSelection(selection)
|
||||
}, onCloseRequest = {
|
||||
dismiss()
|
||||
}),
|
||||
header = Header.Default(
|
||||
title = stringResource(R.string.profile_groups),
|
||||
),
|
||||
selection = ListSelection.Multiple(
|
||||
showCheckBoxes = true,
|
||||
options = options,
|
||||
maxChoices = 32, // Kernel only supports 32 groups at most
|
||||
) { indecies, _ ->
|
||||
// Handle selection
|
||||
selection.clear()
|
||||
indecies.forEach { index ->
|
||||
val group = groups[index]
|
||||
selection.add(group)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
OutlinedCard(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
) {
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clickable {
|
||||
selectGroupsDialog.show()
|
||||
}
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Text(stringResource(R.string.profile_groups))
|
||||
FlowRow {
|
||||
selected.forEach { group ->
|
||||
AssistChip(
|
||||
modifier = Modifier.padding(3.dp),
|
||||
onClick = { /*TODO*/ },
|
||||
label = { Text(group.display) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun CapsPanel(
|
||||
selected: Collection<Capabilities>,
|
||||
closeSelection: (selection: Set<Capabilities>) -> Unit
|
||||
) {
|
||||
val selectCapabilitiesDialog = rememberCustomDialog { dismiss ->
|
||||
val caps = Capabilities.entries.toTypedArray().sortedWith(
|
||||
compareBy<Capabilities> { if (selected.contains(it)) 0 else 1 }
|
||||
.then(compareBy { it.name })
|
||||
)
|
||||
val options = caps.map { value ->
|
||||
ListOption(
|
||||
titleText = value.display,
|
||||
subtitleText = value.desc,
|
||||
selected = selected.contains(value),
|
||||
)
|
||||
}
|
||||
|
||||
val selection = HashSet(selected)
|
||||
ListDialog(
|
||||
state = rememberUseCaseState(visible = true, onFinishedRequest = {
|
||||
closeSelection(selection)
|
||||
}, onCloseRequest = {
|
||||
dismiss()
|
||||
}),
|
||||
header = Header.Default(
|
||||
title = stringResource(R.string.profile_capabilities),
|
||||
),
|
||||
selection = ListSelection.Multiple(
|
||||
showCheckBoxes = true,
|
||||
options = options
|
||||
) { indecies, _ ->
|
||||
// Handle selection
|
||||
selection.clear()
|
||||
indecies.forEach { index ->
|
||||
val group = caps[index]
|
||||
selection.add(group)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
OutlinedCard(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
) {
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clickable {
|
||||
selectCapabilitiesDialog.show()
|
||||
}
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Text(stringResource(R.string.profile_capabilities))
|
||||
FlowRow {
|
||||
selected.forEach { group ->
|
||||
AssistChip(
|
||||
modifier = Modifier.padding(3.dp),
|
||||
onClick = { /*TODO*/ },
|
||||
label = { Text(group.display) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UidPanel(uid: Int, label: String, onUidChange: (Int) -> Unit) {
|
||||
|
||||
ListItem(headlineContent = {
|
||||
var isError by remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
var lastValidUid by remember {
|
||||
mutableIntStateOf(uid)
|
||||
}
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
label = { Text(label) },
|
||||
value = uid.toString(),
|
||||
isError = isError,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Number,
|
||||
imeAction = ImeAction.Done
|
||||
),
|
||||
keyboardActions = KeyboardActions(onDone = {
|
||||
keyboardController?.hide()
|
||||
}),
|
||||
onValueChange = {
|
||||
if (it.isEmpty()) {
|
||||
onUidChange(0)
|
||||
return@OutlinedTextField
|
||||
}
|
||||
val valid = isTextValidUid(it)
|
||||
|
||||
val targetUid = if (valid) it.toInt() else lastValidUid
|
||||
if (valid) {
|
||||
lastValidUid = it.toInt()
|
||||
}
|
||||
|
||||
onUidChange(targetUid)
|
||||
|
||||
isError = !valid
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun SELinuxPanel(
|
||||
profile: Natives.Profile,
|
||||
onSELinuxChange: (domain: String, rules: String) -> Unit
|
||||
) {
|
||||
val editSELinuxDialog = rememberCustomDialog { dismiss ->
|
||||
var domain by remember { mutableStateOf(profile.context) }
|
||||
var rules by remember { mutableStateOf(profile.rules) }
|
||||
|
||||
val inputOptions = listOf(
|
||||
InputTextField(
|
||||
text = domain,
|
||||
header = InputHeader(
|
||||
title = stringResource(id = R.string.profile_selinux_domain),
|
||||
),
|
||||
type = InputTextFieldType.OUTLINED,
|
||||
required = true,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Ascii,
|
||||
imeAction = ImeAction.Next
|
||||
),
|
||||
resultListener = {
|
||||
domain = it ?: ""
|
||||
},
|
||||
validationListener = { value ->
|
||||
// value can be a-zA-Z0-9_
|
||||
val regex = Regex("^[a-z_]+:[a-z0-9_]+:[a-z0-9_]+(:[a-z0-9_]+)?$")
|
||||
if (value?.matches(regex) == true) ValidationResult.Valid
|
||||
else ValidationResult.Invalid("Domain must be in the format of \"user:role:type:level\"")
|
||||
}
|
||||
),
|
||||
InputTextField(
|
||||
text = rules,
|
||||
header = InputHeader(
|
||||
title = stringResource(id = R.string.profile_selinux_rules),
|
||||
),
|
||||
type = InputTextFieldType.OUTLINED,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Ascii,
|
||||
),
|
||||
singleLine = false,
|
||||
resultListener = {
|
||||
rules = it ?: ""
|
||||
},
|
||||
validationListener = { value ->
|
||||
if (isSepolicyValid(value)) ValidationResult.Valid
|
||||
else ValidationResult.Invalid("SELinux rules is invalid!")
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
InputDialog(
|
||||
state = rememberUseCaseState(visible = true,
|
||||
onFinishedRequest = {
|
||||
onSELinuxChange(domain, rules)
|
||||
},
|
||||
onCloseRequest = {
|
||||
dismiss()
|
||||
}),
|
||||
header = Header.Default(
|
||||
title = stringResource(R.string.profile_selinux_context),
|
||||
),
|
||||
selection = InputSelection(
|
||||
input = inputOptions,
|
||||
onPositiveClick = { result ->
|
||||
// Handle selection
|
||||
},
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
ListItem(headlineContent = {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
editSELinuxDialog.show()
|
||||
},
|
||||
enabled = false,
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
disabledTextColor = MaterialTheme.colorScheme.onSurface,
|
||||
disabledBorderColor = MaterialTheme.colorScheme.outline,
|
||||
disabledPlaceholderColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
disabledLabelColor = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
),
|
||||
label = { Text(text = stringResource(R.string.profile_selinux_context)) },
|
||||
value = profile.context,
|
||||
onValueChange = { }
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun RootProfileConfigPreview() {
|
||||
var profile by remember { mutableStateOf(Natives.Profile("")) }
|
||||
RootProfileConfig(fixedName = true, profile = profile) {
|
||||
profile = it
|
||||
}
|
||||
}
|
||||
|
||||
private fun isTextValidUid(text: String): Boolean {
|
||||
return text.isNotEmpty() && text.isDigitsOnly() && text.toInt() >= 0 && text.toInt() <= Int.MAX_VALUE
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
package com.rifsxd.ksunext.ui.component.profile
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ReadMore
|
||||
import androidx.compose.material.icons.filled.ArrowDropDown
|
||||
import androidx.compose.material.icons.filled.ArrowDropUp
|
||||
import androidx.compose.material.icons.filled.Create
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.MenuAnchorType
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import com.rifsxd.ksunext.Natives
|
||||
import com.rifsxd.ksunext.R
|
||||
import com.rifsxd.ksunext.ui.util.listAppProfileTemplates
|
||||
import com.rifsxd.ksunext.ui.util.setSepolicy
|
||||
import com.rifsxd.ksunext.ui.viewmodel.getTemplateInfoById
|
||||
|
||||
/**
|
||||
* @author weishu
|
||||
* @date 2023/10/21.
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun TemplateConfig(
|
||||
profile: Natives.Profile,
|
||||
onViewTemplate: (id: String) -> Unit = {},
|
||||
onManageTemplate: () -> Unit = {},
|
||||
onProfileChange: (Natives.Profile) -> Unit
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
var template by rememberSaveable {
|
||||
mutableStateOf(profile.rootTemplate ?: "")
|
||||
}
|
||||
val profileTemplates = listAppProfileTemplates()
|
||||
val noTemplates = profileTemplates.isEmpty()
|
||||
|
||||
ListItem(headlineContent = {
|
||||
ExposedDropdownMenuBox(
|
||||
expanded = expanded,
|
||||
onExpandedChange = { expanded = it },
|
||||
) {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier
|
||||
.menuAnchor(MenuAnchorType.PrimaryNotEditable)
|
||||
.fillMaxWidth(),
|
||||
readOnly = true,
|
||||
label = { Text(stringResource(R.string.profile_template)) },
|
||||
value = template.ifEmpty { "None" },
|
||||
onValueChange = {},
|
||||
trailingIcon = {
|
||||
if (noTemplates) {
|
||||
IconButton(
|
||||
onClick = onManageTemplate
|
||||
) {
|
||||
Icon(Icons.Filled.Create, null)
|
||||
}
|
||||
} else if (expanded) Icon(Icons.Filled.ArrowDropUp, null)
|
||||
else Icon(Icons.Filled.ArrowDropDown, null)
|
||||
},
|
||||
)
|
||||
if (profileTemplates.isEmpty()) {
|
||||
return@ExposedDropdownMenuBox
|
||||
}
|
||||
ExposedDropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false }
|
||||
) {
|
||||
profileTemplates.forEach { tid ->
|
||||
val templateInfo =
|
||||
getTemplateInfoById(tid) ?: return@forEach
|
||||
DropdownMenuItem(
|
||||
text = { Text(tid) },
|
||||
onClick = {
|
||||
template = tid
|
||||
if (setSepolicy(tid, templateInfo.rules.joinToString("\n"))) {
|
||||
onProfileChange(
|
||||
profile.copy(
|
||||
rootTemplate = tid,
|
||||
rootUseDefault = false,
|
||||
uid = templateInfo.uid,
|
||||
gid = templateInfo.gid,
|
||||
groups = templateInfo.groups,
|
||||
capabilities = templateInfo.capabilities,
|
||||
context = templateInfo.context,
|
||||
namespace = templateInfo.namespace,
|
||||
)
|
||||
)
|
||||
}
|
||||
expanded = false
|
||||
},
|
||||
trailingIcon = {
|
||||
IconButton(onClick = {
|
||||
onViewTemplate(tid)
|
||||
}) {
|
||||
Icon(Icons.AutoMirrored.Filled.ReadMore, null)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,396 +0,0 @@
|
||||
package com.rifsxd.ksunext.ui.screen
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.animation.Crossfade
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
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.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.safeDrawing
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.AccountCircle
|
||||
import androidx.compose.material.icons.filled.Android
|
||||
import androidx.compose.material.icons.filled.AdminPanelSettings
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FilterChip
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
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.geometry.Offset
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
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
|
||||
import com.ramcosta.composedestinations.annotation.RootGraph
|
||||
import com.ramcosta.composedestinations.generated.destinations.AppProfileTemplateScreenDestination
|
||||
import com.ramcosta.composedestinations.generated.destinations.TemplateEditorScreenDestination
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import kotlinx.coroutines.launch
|
||||
import com.rifsxd.ksunext.Natives
|
||||
import com.rifsxd.ksunext.R
|
||||
import com.rifsxd.ksunext.ui.component.SwitchItem
|
||||
import com.rifsxd.ksunext.ui.component.profile.AppProfileConfig
|
||||
import com.rifsxd.ksunext.ui.component.profile.RootProfileConfig
|
||||
import com.rifsxd.ksunext.ui.component.profile.TemplateConfig
|
||||
import com.rifsxd.ksunext.ui.util.LocalSnackbarHost
|
||||
import com.rifsxd.ksunext.ui.util.forceStopApp
|
||||
import com.rifsxd.ksunext.ui.util.getSepolicy
|
||||
import com.rifsxd.ksunext.ui.util.launchApp
|
||||
import com.rifsxd.ksunext.ui.util.restartApp
|
||||
import com.rifsxd.ksunext.ui.util.setSepolicy
|
||||
import com.rifsxd.ksunext.ui.viewmodel.SuperUserViewModel
|
||||
import com.rifsxd.ksunext.ui.viewmodel.getTemplateInfoById
|
||||
|
||||
/**
|
||||
* @author weishu
|
||||
* @date 2023/5/16.
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Destination<RootGraph>
|
||||
@Composable
|
||||
fun AppProfileScreen(
|
||||
navigator: DestinationsNavigator,
|
||||
appInfo: SuperUserViewModel.AppInfo,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
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)
|
||||
|
||||
val packageName = appInfo.packageName
|
||||
val initialProfile = Natives.getAppProfile(packageName, appInfo.uid)
|
||||
if (initialProfile.allowSu) {
|
||||
initialProfile.rules = getSepolicy(packageName)
|
||||
}
|
||||
var profile by rememberSaveable {
|
||||
mutableStateOf(initialProfile)
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopBar(
|
||||
onBack = dropUnlessResumed { navigator.popBackStack() },
|
||||
scrollBehavior = scrollBehavior
|
||||
)
|
||||
},
|
||||
snackbarHost = { SnackbarHost(hostState = snackBarHost) },
|
||||
contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
|
||||
) { paddingValues ->
|
||||
AppProfileInner(
|
||||
modifier = Modifier
|
||||
.padding(paddingValues)
|
||||
.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||
.verticalScroll(rememberScrollState()),
|
||||
packageName = appInfo.packageName,
|
||||
appLabel = appInfo.label,
|
||||
appIcon = {
|
||||
AsyncImage(
|
||||
model = ImageRequest.Builder(context).data(appInfo.packageInfo).crossfade(true).build(),
|
||||
contentDescription = appInfo.label,
|
||||
modifier = Modifier
|
||||
.padding(4.dp)
|
||||
.width(48.dp)
|
||||
.height(48.dp)
|
||||
)
|
||||
},
|
||||
profile = profile,
|
||||
onViewTemplate = {
|
||||
getTemplateInfoById(it)?.let { info ->
|
||||
navigator.navigate(TemplateEditorScreenDestination(info))
|
||||
}
|
||||
},
|
||||
onManageTemplate = {
|
||||
navigator.navigate(AppProfileTemplateScreenDestination())
|
||||
},
|
||||
onProfileChange = {
|
||||
scope.launch {
|
||||
if (it.allowSu) {
|
||||
// sync with allowlist.c - forbid_system_uid
|
||||
if (appInfo.uid < 2000 && appInfo.uid != 1000) {
|
||||
snackBarHost.showSnackbar(suNotAllowed)
|
||||
return@launch
|
||||
}
|
||||
if (!it.rootUseDefault && it.rules.isNotEmpty() && !setSepolicy(profile.name, it.rules)) {
|
||||
snackBarHost.showSnackbar(failToUpdateSepolicy)
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
if (!Natives.setAppProfile(it)) {
|
||||
snackBarHost.showSnackbar(failToUpdateAppProfile.format(appInfo.uid))
|
||||
} else {
|
||||
profile = it
|
||||
viewModel.updateAppProfile(packageName, it)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AppProfileInner(
|
||||
modifier: Modifier = Modifier,
|
||||
packageName: String,
|
||||
appLabel: String,
|
||||
appIcon: @Composable () -> Unit,
|
||||
profile: Natives.Profile,
|
||||
onViewTemplate: (id: String) -> Unit = {},
|
||||
onManageTemplate: () -> Unit = {},
|
||||
onProfileChange: (Natives.Profile) -> Unit,
|
||||
) {
|
||||
val isRootGranted = profile.allowSu
|
||||
|
||||
Column(modifier = modifier) {
|
||||
AppMenuBox(packageName) {
|
||||
ListItem(
|
||||
headlineContent = { Text(appLabel) },
|
||||
supportingContent = { Text(packageName) },
|
||||
leadingContent = appIcon,
|
||||
)
|
||||
}
|
||||
|
||||
SwitchItem(
|
||||
icon = Icons.Filled.AdminPanelSettings,
|
||||
title = stringResource(id = R.string.superuser),
|
||||
checked = isRootGranted,
|
||||
onCheckedChange = { onProfileChange(profile.copy(allowSu = it)) },
|
||||
)
|
||||
|
||||
Crossfade(targetState = isRootGranted, label = "") { current ->
|
||||
Column(
|
||||
modifier = Modifier.padding(bottom = 6.dp + 48.dp + 6.dp /* SnackBar height */)
|
||||
) {
|
||||
if (current) {
|
||||
val initialMode = if (profile.rootUseDefault) {
|
||||
Mode.Default
|
||||
} else if (profile.rootTemplate != null) {
|
||||
Mode.Template
|
||||
} else {
|
||||
Mode.Custom
|
||||
}
|
||||
var mode by rememberSaveable {
|
||||
mutableStateOf(initialMode)
|
||||
}
|
||||
ProfileBox(mode, true) {
|
||||
// template mode shouldn't change profile here!
|
||||
if (it == Mode.Default || it == Mode.Custom) {
|
||||
onProfileChange(profile.copy(rootUseDefault = it == Mode.Default))
|
||||
}
|
||||
mode = it
|
||||
}
|
||||
Crossfade(targetState = mode, label = "") { currentMode ->
|
||||
if (currentMode == Mode.Template) {
|
||||
TemplateConfig(
|
||||
profile = profile,
|
||||
onViewTemplate = onViewTemplate,
|
||||
onManageTemplate = onManageTemplate,
|
||||
onProfileChange = onProfileChange
|
||||
)
|
||||
} else if (mode == Mode.Custom) {
|
||||
RootProfileConfig(
|
||||
fixedName = true,
|
||||
profile = profile,
|
||||
onProfileChange = onProfileChange
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val mode = if (profile.nonRootUseDefault) Mode.Default else Mode.Custom
|
||||
ProfileBox(mode, false) {
|
||||
onProfileChange(profile.copy(nonRootUseDefault = (it == Mode.Default)))
|
||||
}
|
||||
Crossfade(targetState = mode, label = "") { currentMode ->
|
||||
val modifyEnabled = currentMode == Mode.Custom
|
||||
AppProfileConfig(
|
||||
fixedName = true,
|
||||
profile = profile,
|
||||
enabled = modifyEnabled,
|
||||
onProfileChange = onProfileChange
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum class Mode(@StringRes private val res: Int) {
|
||||
Default(R.string.profile_default), Template(R.string.profile_template), Custom(R.string.profile_custom);
|
||||
|
||||
val text: String
|
||||
@Composable get() = stringResource(res)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun TopBar(
|
||||
onBack: () -> Unit,
|
||||
scrollBehavior: TopAppBarScrollBehavior? = null
|
||||
) {
|
||||
TopAppBar(
|
||||
title = {
|
||||
Text(stringResource(R.string.profile))
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(
|
||||
onClick = onBack
|
||||
) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
|
||||
},
|
||||
windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
|
||||
scrollBehavior = scrollBehavior
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ProfileBox(
|
||||
mode: Mode,
|
||||
hasTemplate: Boolean,
|
||||
onModeChange: (Mode) -> Unit,
|
||||
) {
|
||||
ListItem(
|
||||
headlineContent = { Text(stringResource(R.string.profile)) },
|
||||
supportingContent = { Text(mode.text) },
|
||||
leadingContent = { Icon(Icons.Filled.AccountCircle, null) },
|
||||
)
|
||||
HorizontalDivider(thickness = Dp.Hairline)
|
||||
ListItem(headlineContent = {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly
|
||||
) {
|
||||
FilterChip(
|
||||
selected = mode == Mode.Default,
|
||||
label = { Text(stringResource(R.string.profile_default)) },
|
||||
onClick = { onModeChange(Mode.Default) },
|
||||
)
|
||||
if (hasTemplate) {
|
||||
FilterChip(
|
||||
selected = mode == Mode.Template,
|
||||
label = { Text(stringResource(R.string.profile_template)) },
|
||||
onClick = { onModeChange(Mode.Template) },
|
||||
)
|
||||
}
|
||||
FilterChip(
|
||||
selected = mode == Mode.Custom,
|
||||
label = { Text(stringResource(R.string.profile_custom)) },
|
||||
onClick = { onModeChange(Mode.Custom) },
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AppMenuBox(packageName: String, content: @Composable () -> Unit) {
|
||||
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
var touchPoint: Offset by remember { mutableStateOf(Offset.Zero) }
|
||||
val density = LocalDensity.current
|
||||
|
||||
BoxWithConstraints(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures {
|
||||
touchPoint = it
|
||||
expanded = true
|
||||
}
|
||||
}
|
||||
) {
|
||||
|
||||
content()
|
||||
|
||||
val (offsetX, offsetY) = with(density) {
|
||||
(touchPoint.x.toDp()) to (touchPoint.y.toDp())
|
||||
}
|
||||
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
offset = DpOffset(offsetX, -offsetY),
|
||||
onDismissRequest = {
|
||||
expanded = false
|
||||
},
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(id = R.string.launch_app)) },
|
||||
onClick = {
|
||||
expanded = false
|
||||
launchApp(packageName)
|
||||
},
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(id = R.string.force_stop_app)) },
|
||||
onClick = {
|
||||
expanded = false
|
||||
forceStopApp(packageName)
|
||||
},
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(id = R.string.restart_app)) },
|
||||
onClick = {
|
||||
expanded = false
|
||||
restartApp(packageName)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun AppProfilePreview() {
|
||||
var profile by remember { mutableStateOf(Natives.Profile("")) }
|
||||
AppProfileInner(
|
||||
packageName = "icu.nullptr.test",
|
||||
appLabel = "Test",
|
||||
appIcon = { Icon(Icons.Filled.Android, null) },
|
||||
profile = profile,
|
||||
onProfileChange = {
|
||||
profile = it
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,274 +0,0 @@
|
||||
package com.rifsxd.ksunext.ui.screen
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.foundation.clickable
|
||||
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.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.Text
|
||||
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.setValue
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
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 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 kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import com.rifsxd.ksunext.Natives
|
||||
import com.rifsxd.ksunext.ksuApp
|
||||
import com.rifsxd.ksunext.R
|
||||
import com.rifsxd.ksunext.ui.component.ConfirmResult
|
||||
import com.rifsxd.ksunext.ui.component.rememberConfirmDialog
|
||||
import com.rifsxd.ksunext.ui.component.rememberLoadingDialog
|
||||
import com.rifsxd.ksunext.ui.util.LocalSnackbarHost
|
||||
import com.rifsxd.ksunext.ui.util.*
|
||||
|
||||
/**
|
||||
* @author rifsxd
|
||||
* @date 2025/1/14.
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Destination<RootGraph>
|
||||
@Composable
|
||||
fun BackupRestoreScreen(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 ->
|
||||
val loadingDialog = rememberLoadingDialog()
|
||||
val restoreDialog = rememberConfirmDialog()
|
||||
val backupDialog = rememberConfirmDialog()
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(paddingValues)
|
||||
.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
var showRebootDialog by remember { mutableStateOf(false) }
|
||||
|
||||
if (showRebootDialog) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { showRebootDialog = false },
|
||||
title = { Text(stringResource(R.string.reboot_required)) },
|
||||
text = { Text(stringResource(R.string.reboot_message)) },
|
||||
confirmButton = {
|
||||
TextButton(onClick = {
|
||||
showRebootDialog = false
|
||||
reboot()
|
||||
}) {
|
||||
Text(stringResource(R.string.reboot))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = { showRebootDialog = false }) {
|
||||
Text(stringResource(R.string.later))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
val moduleBackup = stringResource(id = R.string.module_backup)
|
||||
val backupMessage = stringResource(id = R.string.module_backup_message)
|
||||
ListItem(
|
||||
leadingContent = {
|
||||
Icon(
|
||||
Icons.Filled.Backup,
|
||||
moduleBackup
|
||||
)
|
||||
},
|
||||
headlineContent = { Text(moduleBackup) },
|
||||
modifier = Modifier.clickable {
|
||||
scope.launch {
|
||||
val result = backupDialog.awaitConfirm(title = moduleBackup, content = backupMessage)
|
||||
if (result == ConfirmResult.Confirmed) {
|
||||
loadingDialog.withLoading {
|
||||
moduleBackup()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if (showRebootDialog) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { showRebootDialog = false },
|
||||
title = { Text(stringResource(R.string.reboot_required)) },
|
||||
text = { Text(stringResource(R.string.reboot_message)) },
|
||||
confirmButton = {
|
||||
TextButton(onClick = {
|
||||
showRebootDialog = false
|
||||
reboot()
|
||||
}) {
|
||||
Text(stringResource(R.string.reboot))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = { showRebootDialog = false }) {
|
||||
Text(stringResource(R.string.later))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
|
||||
|
||||
var useOverlayFs by rememberSaveable {
|
||||
mutableStateOf(readMountSystemFile())
|
||||
}
|
||||
|
||||
val moduleRestore = stringResource(id = R.string.module_restore)
|
||||
val restoreMessage = stringResource(id = R.string.module_restore_message)
|
||||
|
||||
ListItem(
|
||||
leadingContent = {
|
||||
Icon(
|
||||
Icons.Filled.Restore,
|
||||
moduleRestore,
|
||||
tint = if (useOverlayFs) androidx.compose.material3.MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f) else androidx.compose.material3.MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
},
|
||||
headlineContent = {
|
||||
Text(
|
||||
moduleRestore,
|
||||
color = if (useOverlayFs) androidx.compose.material3.MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f) else androidx.compose.material3.MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
},
|
||||
modifier = Modifier.clickable(
|
||||
enabled = !useOverlayFs,
|
||||
onClick = {
|
||||
scope.launch {
|
||||
val result = restoreDialog.awaitConfirm(title = moduleRestore, content = restoreMessage)
|
||||
if (result == ConfirmResult.Confirmed) {
|
||||
loadingDialog.withLoading {
|
||||
moduleRestore()
|
||||
showRebootDialog = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
HorizontalDivider(thickness = Dp.Hairline)
|
||||
|
||||
val allowlistBackup = stringResource(id = R.string.allowlist_backup)
|
||||
val allowlistbackupMessage = stringResource(id = R.string.allowlist_backup_message)
|
||||
ListItem(
|
||||
leadingContent = {
|
||||
Icon(
|
||||
Icons.Filled.Backup,
|
||||
allowlistBackup
|
||||
)
|
||||
},
|
||||
headlineContent = { Text(allowlistBackup) },
|
||||
modifier = Modifier.clickable {
|
||||
scope.launch {
|
||||
val result = backupDialog.awaitConfirm(title = allowlistBackup, content = allowlistbackupMessage)
|
||||
if (result == ConfirmResult.Confirmed) {
|
||||
loadingDialog.withLoading {
|
||||
allowlistBackup()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
val allowlistRestore = stringResource(id = R.string.allowlist_restore)
|
||||
val allowlistrestoreMessage = stringResource(id = R.string.allowlist_restore_message)
|
||||
ListItem(
|
||||
leadingContent = {
|
||||
Icon(
|
||||
Icons.Filled.Restore,
|
||||
allowlistRestore
|
||||
)
|
||||
},
|
||||
headlineContent = { Text(allowlistRestore) },
|
||||
modifier = Modifier.clickable {
|
||||
scope.launch {
|
||||
val result = restoreDialog.awaitConfirm(title = allowlistRestore, content = allowlistrestoreMessage)
|
||||
if (result == ConfirmResult.Confirmed) {
|
||||
loadingDialog.withLoading {
|
||||
allowlistRestore()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun TopBar(
|
||||
onBack: () -> Unit = {},
|
||||
scrollBehavior: TopAppBarScrollBehavior? = null
|
||||
) {
|
||||
TopAppBar(
|
||||
title = { Text(stringResource(R.string.backup_restore)) }, 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 BackupPreview() {
|
||||
BackupRestoreScreen(EmptyDestinationsNavigator)
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package com.rifsxd.ksunext.ui.screen
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material.icons.outlined.*
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import com.ramcosta.composedestinations.generated.destinations.HomeScreenDestination
|
||||
import com.ramcosta.composedestinations.generated.destinations.ModuleScreenDestination
|
||||
import com.ramcosta.composedestinations.generated.destinations.SuperUserScreenDestination
|
||||
import com.ramcosta.composedestinations.generated.destinations.SettingScreenDestination
|
||||
import com.ramcosta.composedestinations.spec.DirectionDestinationSpec
|
||||
import com.rifsxd.ksunext.R
|
||||
|
||||
enum class BottomBarDestination(
|
||||
val direction: DirectionDestinationSpec,
|
||||
@StringRes val label: Int,
|
||||
val iconSelected: ImageVector,
|
||||
val iconNotSelected: ImageVector,
|
||||
val rootRequired: Boolean,
|
||||
) {
|
||||
Home(HomeScreenDestination, R.string.home, Icons.Filled.Home, Icons.Outlined.Home, false),
|
||||
SuperUser(SuperUserScreenDestination, R.string.superuser, Icons.Filled.AdminPanelSettings, Icons.Outlined.AdminPanelSettings, true),
|
||||
Module(ModuleScreenDestination, R.string.module, Icons.Filled.Layers, Icons.Outlined.Layers, true),
|
||||
Settings(SettingScreenDestination, R.string.settings, Icons.Filled.Settings, Icons.Outlined.Settings, false)
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
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)
|
||||
)
|
||||
}
|
||||
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)
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
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)
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
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
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.safeDrawing
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.Save
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.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
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.dropUnlessResumed
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.annotation.RootGraph
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import com.rifsxd.ksunext.R
|
||||
import com.rifsxd.ksunext.ui.component.KeyEventBlocker
|
||||
import com.rifsxd.ksunext.ui.util.LocalSnackbarHost
|
||||
import com.rifsxd.ksunext.ui.util.runModuleAction
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
@Composable
|
||||
@Destination<RootGraph>
|
||||
fun ExecuteModuleActionScreen(navigator: DestinationsNavigator, moduleId: String) {
|
||||
var text by rememberSaveable { mutableStateOf("") }
|
||||
var tempText: String
|
||||
val logContent = rememberSaveable { StringBuilder() }
|
||||
val snackBarHost = LocalSnackbarHost.current
|
||||
val scope = rememberCoroutineScope()
|
||||
val scrollState = rememberScrollState()
|
||||
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
|
||||
onDispose {
|
||||
view.keepScreenOn = false
|
||||
}
|
||||
}
|
||||
|
||||
BackHandler(enabled = isActionRunning) {
|
||||
// Disable back button if action is running
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
if (text.isNotEmpty()) {
|
||||
return@LaunchedEffect
|
||||
}
|
||||
withContext(Dispatchers.IO) {
|
||||
runModuleAction(
|
||||
moduleId = moduleId,
|
||||
onStdout = {
|
||||
tempText = "$it\n"
|
||||
if (tempText.startsWith("[H[J")) { // clear command
|
||||
text = tempText.substring(6)
|
||||
} else {
|
||||
text += tempText
|
||||
}
|
||||
logContent.append(it).append("\n")
|
||||
},
|
||||
onStderr = {
|
||||
logContent.append(it).append("\n")
|
||||
}
|
||||
).let {
|
||||
actionResult = it
|
||||
}
|
||||
}
|
||||
isActionRunning = false
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopBar(
|
||||
isActionRunning = isActionRunning,
|
||||
onBack = dropUnlessResumed {
|
||||
navigator.popBackStack()
|
||||
},
|
||||
onSave = {
|
||||
if (!isActionRunning) {
|
||||
scope.launch {
|
||||
val format = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault())
|
||||
val date = format.format(Date())
|
||||
val file = File(
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
|
||||
"KernelSU_Next_module_action_log_${date}.log"
|
||||
)
|
||||
file.writeText(logContent.toString())
|
||||
snackBarHost.showSnackbar("Log saved to ${file.absolutePath}")
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
floatingActionButton = {
|
||||
if (!isActionRunning) {
|
||||
ExtendedFloatingActionButton(
|
||||
text = { Text(text = stringResource(R.string.close)) },
|
||||
icon = { Icon(Icons.Filled.Close, contentDescription = null) },
|
||||
onClick = {
|
||||
navigator.popBackStack()
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
contentWindowInsets = WindowInsets.safeDrawing,
|
||||
snackbarHost = { SnackbarHost(snackBarHost) }
|
||||
) { innerPadding ->
|
||||
KeyEventBlocker {
|
||||
it.key == Key.VolumeDown || it.key == Key.VolumeUp
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize(1f)
|
||||
.padding(innerPadding)
|
||||
.verticalScroll(scrollState),
|
||||
) {
|
||||
LaunchedEffect(text) {
|
||||
scrollState.animateScrollTo(scrollState.maxValue)
|
||||
}
|
||||
Text(
|
||||
modifier = Modifier.padding(8.dp),
|
||||
text = if (developerOptionsEnabled) logContent.toString() else text,
|
||||
fontSize = MaterialTheme.typography.bodySmall.fontSize,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun TopBar(isActionRunning: Boolean, onBack: () -> Unit = {}, onSave: () -> Unit = {}) {
|
||||
TopAppBar(
|
||||
title = { Text(stringResource(R.string.action)) },
|
||||
navigationIcon = {
|
||||
IconButton(
|
||||
onClick = onBack,
|
||||
enabled = !isActionRunning
|
||||
) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
|
||||
},
|
||||
actions = {
|
||||
IconButton(
|
||||
onClick = onSave,
|
||||
enabled = !isActionRunning
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Save,
|
||||
contentDescription = stringResource(id = R.string.save_log),
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user