Compare commits

...

224 Commits

Author SHA1 Message Date
weishu
3291538446 manager: allow to query language if country is unknown. close #1495 2024-03-21 14:45:33 +08:00
weishu
e38a5e52d2 kernel: we should take ownership over fd 2024-03-21 14:15:11 +08:00
weishu
b3a15e2b6b kernel: Fix the incorrect judgment condition. 2024-03-21 11:48:02 +08:00
weishu
c5d423c4eb kernel: ignore all non application uid 2024-03-21 11:45:44 +08:00
weishu
4511d4b7bf kernel: remove unused module_api 2024-03-21 11:36:36 +08:00
weishu
64908583e9 kernel: Fix compile warning 2024-03-21 11:32:30 +08:00
weishu
c408710b11 kernel: minor fixes 2024-03-21 11:24:56 +08:00
weishu
bc1e03feb1 kernel: remove unused headers 2024-03-20 23:14:30 +08:00
Houvven
39b025b235 add user custom select lkm file button on install screen top bar (#1491) 2024-03-20 22:29:04 +08:00
weishu
65a0f0070a manager: print space to avoid button overlap. close #1478 2024-03-20 21:48:00 +08:00
weishu
8b71d3c9ba ksud: try find KMI from installed modules 2024-03-20 21:33:41 +08:00
dependabot[bot]
2bcb6a93c0 build(deps): bump com.google.devtools.ksp from 1.9.22-1.0.18 to 1.9.23-1.0.19 in /manager (#1487)
Bumps [com.google.devtools.ksp](https://github.com/google/ksp) from
1.9.22-1.0.18 to 1.9.23-1.0.19.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/google/ksp/releases">com.google.devtools.ksp's
releases</a>.</em></p>
<blockquote>
<h2>1.9.23-1.0.19</h2>
<h3>New APIs</h3>
<ul>
<li><a
href="https://redirect.github.com/google/ksp/issues/1708">#1708</a>
<code>SymbolProcessorEnvironment.kspVersion</code></li>
<li><a
href="https://redirect.github.com/google/ksp/issues/1707">#1707</a>
<code>CodeGenerator.associateWithFunctions</code> and
<code>CodeGenerator.associateWithProperties</code></li>
</ul>
<h3>Issues fixed in KSP2</h3>
<ul>
<li><a
href="https://redirect.github.com/google/ksp/issues/1691">#1691</a>
IllegalStateException: Value type not found for value</li>
<li><a
href="https://redirect.github.com/google/ksp/issues/1719">#1719</a> The
order of symbols returned from Resolver.getSymbolsWithAnnotation() is
different</li>
<li><a
href="https://redirect.github.com/google/ksp/issues/1718">#1718</a>
Getting packageName of Kotlin types returns empty String</li>
<li><a
href="https://redirect.github.com/google/ksp/issues/1721">#1721</a>
KSAnnotation packageName is an empty String for a type from a different
module</li>
<li><a
href="https://redirect.github.com/google/ksp/issues/1722">#1722</a>
Resolver.getDeclarationsFromPackage() returns declarations from the
default package when passing in an unknown package</li>
<li><a
href="https://redirect.github.com/google/ksp/issues/1717">#1717</a>
Resolver.getJvmName() returns different results for annotation args</li>
<li><a
href="https://redirect.github.com/google/ksp/issues/1725">#1725</a>
asMemberOf() throws exception with a generic type without arguments</li>
<li><a
href="https://redirect.github.com/google/ksp/issues/1728">#1728</a>
ClassCastException when calling KSType.replace() with empty list</li>
<li><a
href="https://redirect.github.com/google/ksp/issues/1713">#1713</a>
NoClassDefFoundError for LZ4Factory when trying KSP2</li>
<li><a
href="https://redirect.github.com/google/ksp/issues/1665">#1665</a>
NoClassDefFound in ksp.useKSP2=true mode</li>
<li><a
href="https://redirect.github.com/google/ksp/issues/1733">#1733</a> ABI
incompatibility with kotlin-compiler-embeddable in 2.0.0-Beta4</li>
<li><a
href="https://redirect.github.com/google/ksp/issues/1714">#1714</a>
Generated resources are not added to KotlinCompilation inputs</li>
<li><a
href="https://redirect.github.com/google/ksp/issues/1747">#1747</a>
isCompanionObject is false for companion objects from KOTLIN_LIB</li>
<li><a
href="https://redirect.github.com/google/ksp/issues/1743">#1743</a>
Incorrect type parameter variances</li>
<li><a
href="https://redirect.github.com/google/ksp/issues/1759">#1759</a>
IllegalStateException when getting the modifiers from properties in a
Java annotation declaration</li>
</ul>
<h3>Issues fixed in KSP Gradle Plugin</h3>
<ul>
<li><a
href="https://redirect.github.com/google/ksp/issues/1712">#1712</a>
Analysis API artifacts have the wrong common-deps dependency</li>
<li><a
href="https://redirect.github.com/google/ksp/issues/1775">#1775</a>
1.0.18 creates circular dependencies with kapt tasks</li>
<li><a
href="https://redirect.github.com/google/ksp/issues/1772">#1772</a>
Update plugin com.google.devtools.ksp to v1.9.22-1.0.18 BUILD
FAILED</li>
</ul>
<h3>Known issues</h3>
<ul>
<li><a
href="https://redirect.github.com/google/ksp/issues/1776">#1776</a> KSP2
has higher memory usage when the compile classpath is very large.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/google/ksp/commits/1.9.23-1.0.19">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=com.google.devtools.ksp&package-manager=gradle&previous-version=1.9.22-1.0.18&new-version=1.9.23-1.0.19)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-20 21:03:39 +08:00
weishu
51880e3e90 ci: revert apksign plugin 2024-03-20 20:03:58 +08:00
weishu
4cd435b194 [no ci]: Don't upload ci manager 2024-03-20 19:22:41 +08:00
weishu
c986b7a53a Fix manager signature (#1489)
f48f2fea59
2024-03-20 19:12:39 +08:00
weishu
808342bf04 kernel: Fix sepolicy on ColorOS14 2024-03-20 17:43:37 +08:00
weishu
0b9f675013 ci: fix manager ci 2024-03-20 17:42:17 +08:00
weishu
f19d157887 manager: tar oplus log if exists 2024-03-20 16:24:36 +08:00
weishu
a160a7bf0d ci: fix typo 2024-03-20 16:13:54 +08:00
weishu
ef26aba4d8 ci: build manager when kernel changed, don't upload apk for pr builds 2024-03-20 15:42:29 +08:00
weishu
71b56ba700 kernel: fix panic cast 2024-03-20 15:39:07 +08:00
weishu
d958e6d7e7 ci: only post manager to tg 2024-03-20 15:34:06 +08:00
weishu
815f4d0428 kernel: hook newfstatat/faccessat syscall instead of unstable symbol 2024-03-20 15:15:26 +08:00
weishu
2a64784a33 kernel: hook syscall instead of unstable symbol 2024-03-20 14:21:19 +08:00
Caner Karaca
8f33926aa0 Add Dependabot, Update Dependencies and Workflows (#1440)
Build may fail because of some major dependency updates. Needs changes,
changes/fixes welcomed.

Main goal is keeping all things up-to-date.

---------

Co-authored-by: weishu <twsxtd@gmail.com>
2024-03-20 12:52:34 +08:00
weishu
2b0d19928a manager: don't show mode for non gki 2024-03-19 21:12:43 +08:00
Fede2782
1fc1ffe2ab Docs: add backport notice in module umount docs (#1476)
This aims to uniform the documentation since the official introduction
of pre-GKI modules umount feature
2024-03-19 15:41:22 +08:00
dabao1955
97faab6be4 kernel: Use CONFIG_KSU=m to compile lkm (#1468)
before:
CONFIG_KSU=y
CONFIG_KSU_MODULE=y

after:
CONFIG_KSU=m

---------

Signed-off-by: dabao1955 <dabao1955@163.com>
Co-authored-by: weishu <twsxtd@gmail.com>
2024-03-19 15:40:38 +08:00
backslashxx
247aa877e4 fixup! Suggest non-gki kernel users to backport path_umount (#1477)
My bad.

as reported by @AzusaHana on tg

![image](https://github.com/tiann/KernelSU/assets/118538522/a67f97c2-20f7-4ee6-9ae1-9f9089376857)
2024-03-19 15:39:54 +08:00
weishu
cbd47329e8 ci: no need to cache bot session 2024-03-19 13:32:29 +08:00
weishu
eb25644a0e ci: Don't upload images to group, uploading manager is enough because we can use manager to install directly 2024-03-19 13:31:02 +08:00
weishu
65b5ce2a50 ci: Remove kernel builds deprecated by Google 2024-03-19 12:19:02 +08:00
weishu
8c44e82db2 manager: Filter ignore case. fix #1470 2024-03-19 12:17:32 +08:00
weishu
79a1410fd3 manager: Correct minimal lkm version 2024-03-19 11:53:14 +08:00
weishu
ce0c397a65 kernel: support query working mode 2024-03-19 11:52:17 +08:00
weishu
99847cb986 manager: Show working mode 2024-03-19 11:50:45 +08:00
weishu
f41d73f7eb ksud: try parse kmi from gki modules if uname is modified 2024-03-19 10:37:17 +08:00
igor
7f73827658 website: update translation (#1473) 2024-03-19 09:53:45 +08:00
TheNeutrinoRaged
053fce61c0 [CI][A13] a13-5.10 security date 2024-04 (#1475)
My Pixel 7a March 2024 update has kernel version
5.10.189-android13-4-00012-g1217bb583cc5-ab11174560 and Android security
update 2024-03


https://cs.android.com/android/kernel/superproject/+/common-android13-5.10-2024-03:common/Makefile

Thanks
2024-03-19 09:51:38 +08:00
weishu
8ae6eaa5e3 ci: we don't need to build-lkm separetly because build-manager depends on it. 2024-03-18 23:24:32 +08:00
weishu
35553afd12 ci: Fix manager build 2024-03-18 23:20:41 +08:00
weishu
0c11d210a9 manager: support offline patch 2024-03-18 23:16:24 +08:00
weishu
9759a779cd embed LKM to ksud (#1472) 2024-03-18 23:12:46 +08:00
weishu
4bad691ec8 kernel: don't remove from sysfs when debug is enabled 2024-03-18 19:12:56 +08:00
weishu
fefb02e578 kernel: remove it from sysfs 2024-03-18 18:50:53 +08:00
Soo-Hwan Na
d6770467fa kernel: Make it compile on 3.18 (maybe older) kernels (#1460)
input-event-codes.h:

Input: add input-event-codes header file
(f902dd8934)
This was in 4.4-rc, so 4.4.0 or above has it else no.

aio.h:
fs: move struct kiocb to fs.h
(e2e40f2c1e)

Below this version, we need to explicitly include aio.h for struct kiocb
This was in 4.1-rc, so 4.0 or below should do the include

uaccess.h, sched.h was present for long times, but 4.10 splited out to
include/sched/ but the current ifdef is not including uaccess.h for
lower versions than 4.4. Fix it.
2024-03-18 13:13:00 +08:00
weishu
95dc7fcbe1 ci: fix version incorrect of avd kernel. android_ci config use sandbox and cannot access git 2024-03-18 12:30:09 +08:00
backslashxx
b4cfc2f298 Suggest non-gki kernel users to backport path_umount (#1464)
Most kernel builders have to touch their kernel source code anyway, why
not also tell them to backport path_umount so even non-gki users can
benefit from this?

I know this might be a bit controversial as this will raise the barrier
of entry, but the benefits are just so high.

Idea was from OnlyTomInSecond on KernelSU group chat way back, and it
has been on the discussions for some time

references:
https://t.me/KernelSU_group/27237/176515
https://t.me/KernelSU_group/3249/184908

https://github.com/tiann/KernelSU/discussions/955#discussioncomment-7617166

03d233db8b
https://github.com/tiann/KernelSU/pull/1060 


https://elixir.bootlin.com/linux/v5.9.1/source/fs/namespace.c#L1728
https://elixir.bootlin.com/linux/v5.10.9/source/fs/namespace.c#L1730
https://elixir.bootlin.com/linux/v6.5/source/fs/namespace.c#L1887
https://github.com/tiann/KernelSU/pull/1464#issuecomment-2002492107


Kernel side change examples
5.4
961d978862
4.19
164917f56d
4.14
c07c70a0c5
4.9
195f07593a
4.4
21ea33fe41
https://github.com/tiann/KernelSU/pull/1464#issuecomment-2002424069
ofcourse having someone on 3.18 confirm this will be nice.

**PROS**: umount modules for everyone
**CONS**: barrier of entry +1

---------

Co-authored-by: Christoph Hellwig <hch@lst.de>
Co-authored-by: Fede2782 <78815152+Fede2782@users.noreply.github.com>
Co-authored-by: Tom <31297720+onlytominsecond@users.noreply.github.com>
2024-03-18 10:27:31 +08:00
hosizoraru
6016937d5a ci: a14-6.1 patch level 2024-02 to 03 (#1465)
https://android.googlesource.com/kernel/common/+/refs/heads/android14-6.1-2024-03
android14-6.1-2024-03 已经发布

https://android.googlesource.com/kernel/common/+/refs/heads/android14-6.1-2024-03/Makefile
从 Makefile 来看依旧是 6.1.68
2024-03-17 21:47:00 +08:00
weishu
117b4dc051 manager: check init_boot more precisely 2024-03-17 17:41:35 +08:00
weishu
f6d552c797 ksud: ensure post-fs-data.d is created by post ota 2024-03-17 17:25:42 +08:00
weishu
a5e76553e4 manager: Fix new version tip 2024-03-17 13:30:13 +08:00
weishu
44c0b3a767 skipci: Fix release upload 2024-03-17 13:15:55 +08:00
weishu
177ef6b634 manager: Add tips for select boot image 2024-03-17 12:00:44 +08:00
Weblate (bot)
9a4ea27e9d Translations update from Hosted Weblate (#1454)
Translations update from [Hosted Weblate](https://hosted.weblate.org)
for
[KernelSU/Manager](https://hosted.weblate.org/projects/kernelsu/manager/).



Current translation status:

![Weblate translation
status](https://hosted.weblate.org/widget/kernelsu/manager/horizontal-auto.svg)

---------

Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Misaka <79515833+misakazip@users.noreply.github.com>
Co-authored-by: I g o r <igormczampola1@gmail.com>
Co-authored-by: yuztass <inkognito0901@gmail.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Madis Otenurm <robotkoer@gmail.com>
Co-authored-by: dabao1955 <dabao1955@163.com>
Co-authored-by: ngocanhtve <ngocanh.tve@gmail.com>
Co-authored-by: Integral <integral@member.fsf.org>
Co-authored-by: Igor Sorocean <sorocean.igor@gmail.com>
Co-authored-by: weishu tian <twsxtd@gmail.com>
Co-authored-by: Skallr2 <pm563838@gmail.com>
Co-authored-by: charlotte <charlotterose@duck.com>
Co-authored-by: sus <jeffpeng2012@gmail.com>
Co-authored-by: Caner Karaca <canerkaraca_23@hotmail.com>
Co-authored-by: Ali Beyaz <alipolatbeyaz@gmail.com>
2024-03-17 10:19:05 +08:00
igor
339e75be24 website: fix typo (#1456) 2024-03-17 09:08:46 +08:00
weishu
cf210d629f ci: Fix avd build (#1457) 2024-03-17 09:07:52 +08:00
weishu
ca480a5ec3 ci: Add lkm to release 2024-03-16 22:59:22 +08:00
weishu
23263a55de try fix 2024-03-16 12:21:03 +08:00
weishu
f65ea5a340 manager: Add install menu 2024-03-16 11:46:13 +08:00
weishu
ad6e2390f5 manager: Add CN translation 2024-03-16 11:37:31 +08:00
weishu
383f164453 remove ccache, bazel don't use 2024-03-16 11:37:30 +08:00
sewn
f675ce9aba [CI][A13] a13-5.10 patch level 2024-02 (#1449)
My Pixel 7a has a kernel version
`5.10.177-android13-4-00003-ga7208022a7ea-ab1081582`, with a security
patch of 2024-02, but the only available kernel build for that is
security patch 2023-07 which causes a bootloop.
2024-03-16 11:32:32 +08:00
weishu
7fd760f4f4 manager: Fix loading dialog 2024-03-16 11:13:50 +08:00
weishu
972d347a14 manager: Add string resource 2024-03-16 11:13:50 +08:00
weishu
ca8a88f0cc manager: Fix reboot button is missing when flash 2024-03-16 11:13:50 +08:00
weishu
e39be55db8 ksud: Fix magisk detect 2024-03-16 11:13:50 +08:00
Weblate (bot)
d00d3cbf82 Translations update from Hosted Weblate (#1437)
Translations update from [Hosted Weblate](https://hosted.weblate.org)
for
[KernelSU/Manager](https://hosted.weblate.org/projects/kernelsu/manager/).



Current translation status:

![Weblate translation
status](https://hosted.weblate.org/widget/kernelsu/manager/horizontal-auto.svg)

---------

Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: Misaka <79515833+misakazip@users.noreply.github.com>
Co-authored-by: I g o r <igormczampola1@gmail.com>
Co-authored-by: yuztass <inkognito0901@gmail.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Madis Otenurm <robotkoer@gmail.com>
Co-authored-by: dabao1955 <dabao1955@163.com>
Co-authored-by: ngocanhtve <ngocanh.tve@gmail.com>
Co-authored-by: Integral <integral@member.fsf.org>
Co-authored-by: Igor Sorocean <sorocean.igor@gmail.com>
Co-authored-by: weishu tian <twsxtd@gmail.com>
Co-authored-by: Skallr2 <pm563838@gmail.com>
Co-authored-by: charlotte <charlotterose@duck.com>
Co-authored-by: sus <jeffpeng2012@gmail.com>
Co-authored-by: Caner Karaca <canerkaraca_23@hotmail.com>
2024-03-16 11:08:56 +08:00
cachiusa
7168a974be Add nethunter.root template (#1445)
This app requires DAC_OVERRIDE, DAC_READ_SEARCH, SYS_PTRACE, SYS_ADMIN
(for /data/local r/w) and SYS_CHROOT, SETGID (to run chroot and run it's
processes)

Devices with NetHunter installed is already considered compromised due
to lack of security features(like SELinux), therefore users are advised
not to store private data

It's not really worth restricting more capabilities of the app.
2024-03-16 10:54:00 +08:00
TheNeutrinoRaged
ddc086c4ef Update installation.md (#1451)
typo flush -> flash
2024-03-16 10:53:10 +08:00
sus
076511e275 Updated the Traditional Chinese translations for the website and templates. (#1453)
Signed-off-by: sus <54392299+jeffpeng3@users.noreply.github.com>
2024-03-16 10:52:53 +08:00
weishu
9d5529fb09 ksud: Fix magisk detect 2024-03-16 09:22:37 +08:00
weishu
ceb00dfdfd ci: remove avd build disk cache 2024-03-15 22:28:00 +08:00
weishu
39504ec2f3 ci: Fix release 2024-03-15 22:14:42 +08:00
weishu
1642e92c6f ci: Fix symbol strip 2024-03-15 21:00:44 +08:00
weishu
0f220f4044 ci: Fix release and LKM upload 2024-03-15 20:54:32 +08:00
weishu
2c34ec1742 ci: fix avd build 2024-03-15 20:29:53 +08:00
Ylarod
7568d55be1 Build KernelSU as LKM (#1254)
Co-authored-by: weishu <twsxtd@gmail.com>
2024-03-15 18:53:24 +08:00
Coconut
e3998c0744 kernel:Compatible with devices based on Huawei EMUI10 (#1447)
EMUI 10 kernel version is 4.14.xxx.  
The SELinux of Huawei's modified EMUI10 kernel is still similar to the
EMUI 9 version. This commit not support HarmonyOS 2 based EMUI 10.
2024-03-14 15:18:59 +08:00
Ylarod
50914ce39b Fix typo (#1444) 2024-03-13 18:04:58 +08:00
zalnars
6af2480008 Fix typos (#1443) 2024-03-12 13:15:03 +08:00
余空
625e1aafd1 ci: Add more kernel branches (#1442)
* Android12 5.10.205
* Android13 5.10.205
* Android13 5.15.144
* Update os_patch_level
2024-03-11 21:37:16 +08:00
weishu
d77988c1ac ksud: catch dmesg in bootlog 2024-03-11 14:20:27 +08:00
weishu
fe7ec370d4 ksud: fmt & tidy 2024-03-11 14:01:21 +08:00
weishu
ce5aa990ed ksud: don't patch if it's already patched 2024-03-11 12:48:25 +08:00
TinyHai
22a1276a22 manager: a small fix in InstallScreen (#1434)
今天刷一个模块,刷入时要配置一些内容,然后发现每次输出我都得手动滑动一下才能看全内容,就很难受。气得我直接翻源码,就有了这个PR   :P

- 防止logContent在重组时丢失。
- 修复输出内容总是自动滚动到上次内容的最底部,而不是最新内容的最底部的f问题。
2024-03-08 19:35:52 +08:00
loogeo
f9a4186dc7 Update build-kernel-a14.yml (#1432) 2024-03-08 12:39:24 +08:00
lyf
8b29137e83 [CI][A14] a14-5.15 patch level 2024-01 and 2024-02 (#1433)
Since android14 5.15.137 (2024-01) was released with QPR3 Beta2 on Pixel
8(Pro)
2024-03-08 12:39:17 +08:00
igor
ae17001033 website: update translation (#1423) 2024-03-08 10:32:08 +08:00
Syuugo
0eea198c2f Upgrade Gradle and AGP (#1431)
and Fix batch line config
2024-03-08 10:31:41 +08:00
TinyHai
425713fad3 manager: refine dialog component & add an animation to UpdateCard (#1429) 2024-03-08 10:31:14 +08:00
WindyDay
7611accc33 Add docs about Android 14 Kernel (#1421)
First time Pr to this project, not sure if I done it in the correct
format
2024-03-05 23:39:55 +08:00
riChar
323eaa0242 Add types in package.json (#1415)
The package can not be imported into TS project without this option.
[docs](https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html#including-declarations-in-your-npm-package)
2024-03-04 23:05:38 +08:00
igor
217755bb5a website: fixed typos and update translation (#1407) 2024-03-04 19:16:39 +08:00
weishu
170cd3f912 ci: Add android 15 avd kernel (#1414) 2024-03-04 19:12:48 +08:00
weishu
1d7d406745 manager: change webview debug icon 2024-03-04 15:10:16 +08:00
weishu
c8fc6a0656 ksud: resize image if it is shrinked 2024-03-04 13:50:00 +08:00
weishu
3829894d4d Use fallback method to mount overlayfs when fsopen one failed
Co-authored-by: natsumerinchan
2024-03-04 12:26:19 +08:00
5ec1cff
cd772fa250 manager: allow enable webview debugging (#1412) 2024-03-03 22:24:02 +08:00
weishu
dbe43b1540 ksud: remove permission mode for symlink 2024-03-01 23:10:03 +08:00
weishu
8a59fe1969 ksud: Copy directory permission mode 2024-03-01 22:46:53 +08:00
weishu
2a4fa94af0 ksud: Add more logs 2024-02-29 22:43:48 +08:00
weishu
6de330b00a ksud: Add some logs 2024-02-29 22:40:42 +08:00
weishu
8c0d06bc68 misc: Add just command 2024-02-29 20:35:03 +08:00
weishu
ed254b7ab4 ksud: fmt 2024-02-29 20:34:50 +08:00
weishu
5355625ed6 ksud: correctly copy chr device and keep xattr. close #1397 2024-02-29 19:23:11 +08:00
5ec1cff
7b89ec89c0 ci: support android 14 AVD (#1405) 2024-02-29 17:36:38 +08:00
weishu
5aa025c3f0 ksud: Add ksud to manager's su path 2024-02-29 14:04:10 +08:00
weishu
e39a80f91e webui: use global mount namespace by default. 2024-02-29 13:59:13 +08:00
weishu
622a7d73dc Revert "webui: support mount master mode"
This reverts commit 922703d2ff.
2024-02-29 13:58:44 +08:00
weishu
922703d2ff webui: support mount master mode 2024-02-29 13:55:07 +08:00
Fede2782
f459dfad54 English Faq: add wrong storage size on some Samsung (#1400)
#1389
2024-02-29 13:47:45 +08:00
Wang Han
3e2de84a81 Guard a few logprint in prctl path with KSU_DEBUG (#1402) 2024-02-29 13:47:22 +08:00
weishu
796f8a448a kernel: fix bazel build 2024-02-26 16:54:14 +08:00
Lycs-D
7775ce3938 ci: update android12-5.10 os_patch_level to 2024-01 (#1378) 2024-02-26 15:59:56 +08:00
Mufanc
2fb5334ac6 fix kernelsu.spawn && add type definitions (#1395) 2024-02-26 15:35:23 +08:00
weishu
afe0e691aa kernel: Unshallow the repo in Makefile. close #1365 2024-02-26 12:23:51 +08:00
Celica Sylphil
532796de48 website: Fix zh_CN and ja_JP paths (#1394) 2024-02-26 10:16:20 +08:00
dabao1955
e691c62811 website: fix ja guide broken links (#1392)
Signed-off-by: dabao1955 <dabao1955@163.com>
2024-02-26 09:49:10 +08:00
Weblate (bot)
3f341a4e3a Translations update from Hosted Weblate (#1376)
Translations update from [Hosted Weblate](https://hosted.weblate.org)
for
[KernelSU/Manager](https://hosted.weblate.org/projects/kernelsu/manager/).



Current translation status:

![Weblate translation
status](https://hosted.weblate.org/widget/kernelsu/manager/horizontal-auto.svg)

---------

Co-authored-by: yuztass <inkognito0901@gmail.com>
Co-authored-by: Federico Lombardo <mlomb.federalberto@gmail.com>
Co-authored-by: I g o r <igormczampola1@gmail.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Kazuki Nakashima <flukfik41@gmail.com>
Co-authored-by: Rex_sa <rex.sa@pm.me>
Co-authored-by: dabao1955 <dabao1955@163.com>
Co-authored-by: / <sahmatov267@gmail.com>
2024-02-25 23:11:08 +08:00
weishu
40d7bc6256 ksud: Fix incorrect dir copy 2024-02-25 22:55:24 +08:00
igor
56dbc980f4 website: update translation (#1377) 2024-02-25 22:48:22 +08:00
weishu
bf71ff133c manager: Add adb file details to log 2024-02-25 22:36:58 +08:00
weishu
a9b156df43 manager: Add ksu file real size to logs 2024-02-25 22:33:04 +08:00
weishu
1690e5db02 manager: Use global mount namespace to gather logs 2024-02-25 22:30:53 +08:00
weishu
300d9d4cca ksud: Force creating new module format to avoid many wired issues. close #1384, close #1381 2024-02-25 22:29:13 +08:00
dabao1955
3f12080dfe website: update Japanese translation (#1387)
Signed-off-by: dabao1955 <dabao1955@163.com>
2024-02-25 20:24:49 +08:00
weishu
b670db2d22 ksud: fix punch hole 2024-02-25 20:21:17 +08:00
heinu
62a31b3dc2 manager: Allow http for more localhost (#1385) 2024-02-25 18:21:52 +08:00
weishu
a395b1011e manager: Allow http for localhost 2024-02-24 11:20:14 +08:00
weishu
406070914a website: Add docs for module WebUI 2024-02-23 22:43:31 +08:00
weishu
8685fa1f60 js: relicense js library to Apache 2.0 2024-02-23 21:30:02 +08:00
weishu
c95163b144 manager: Enter -> Open 2024-02-23 19:47:37 +08:00
weishu
648d56da39 manager: use kernelsu's domain instead of default one 2024-02-23 18:54:40 +08:00
weishu
33c0a9eebd manager: remove http that was introduced before 2024-02-23 18:49:18 +08:00
Weblate (bot)
3f86fb016d Translations update from Hosted Weblate (#1319)
Translations update from [Hosted Weblate](https://hosted.weblate.org)
for
[KernelSU/Manager](https://hosted.weblate.org/projects/kernelsu/manager/).



Current translation status:

![Weblate translation
status](https://hosted.weblate.org/widget/kernelsu/manager/horizontal-auto.svg)

---------

Co-authored-by: yuztass <inkognito0901@gmail.com>
Co-authored-by: 聖小熊 <as406010503@gmail.com>
Co-authored-by: dabao1955 <dabao1955@163.com>
Co-authored-by: I g o r <igormczampola1@gmail.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Igor Sorocean <sorocean.igor@gmail.com>
Co-authored-by: Skallr2 <pm563838@gmail.com>
Co-authored-by: weishu <twsxtd@gmail.com>
2024-02-23 18:32:56 +08:00
weishu
66316e76f5 manager: Add entry for module ui 2024-02-23 18:28:28 +08:00
weishu
5591a94f87 manager: create new root shell for module installation to avoid block other su operations 2024-02-23 18:28:28 +08:00
weishu
f855f8148a manager: use global mnt shell to aovid nsenter 2024-02-23 18:28:28 +08:00
weishu
0c52f24612 ksud: remove link manager 2024-02-23 18:08:53 +08:00
weishu
9635a00036 manager: use SuFile to load webview assets to avoid spoofing manager's mount namespace 2024-02-23 18:04:08 +08:00
weishu
cbc04ff6df ksud: support global mnt for debug su 2024-02-23 18:04:00 +08:00
igor
8e448767a5 update templates (#1371) 2024-02-23 16:55:53 +08:00
那年雪落
2820779947 kernel: Add back Makefile new line with posix compatible (#1372) 2024-02-23 16:55:22 +08:00
weishu
a99c69f9b4 manager: Usse WebViewAssetLoader instead of file uri. refer: https://developer.android.com/reference/androidx/webkit/WebViewAssetLoader
androidCompileSdkVersion changed to meet webview library requirements
2024-02-23 16:12:53 +08:00
weishu
a829707b16 js: Allow spawn(command, options) call, fix memory leak 2024-02-23 09:16:00 +08:00
weishu
77d16ac896 js: support spawn jsapi 2024-02-23 00:16:04 +08:00
weishu
d02855a40a js: simplify the exec call 2024-02-22 22:41:50 +08:00
weishu
b904680f13 js: Add more API and README 2024-02-22 22:09:27 +08:00
weishu
811c68cac0 js: Add jsapi package 2024-02-22 20:42:15 +08:00
weishu
f20ccc1728 manager: Add jsapi: toast 2024-02-22 20:40:52 +08:00
weishu
66e7db2a4e manager: Add more abilities to js exec 2024-02-22 20:39:46 +08:00
weishu
e6b05b1d3c ksud: fix mount view of manager when 'umount modules by default' is enabled 2024-02-22 19:08:37 +08:00
weishu
329010a694 manager: mount modules webui resources to manager directly. 2024-02-22 16:26:39 +08:00
weishu
9c4d20c0f2 ksud: remove http serve mode 2024-02-22 16:26:14 +08:00
weishu
355b55a01d ksud: use bind mount to serve module webui 2024-02-22 16:26:14 +08:00
Masum Reza
e85646fad4 Added adaway.root template (#1337)
Adaway only needs the following permissions to work properly:
DAC_OVERRIDE, SYS_PTRACE.

Note: [systemless hosts kernelsu
module](https://github.com/symbuzzer/systemless-hosts-KernelSU-module)
needs to be installed, to add support.

This PR only addresses the minimal permission requirements of Adaway to
let it modify hosts file.
2024-02-21 09:57:23 +08:00
dabao1955
4969c5f548 Translate templates into Japanese (#1364)
Signed-off-by: dabao1955 <dabao1955@163.com>
2024-02-21 09:55:26 +08:00
weishu
55f8f2da90 manager: support full screen for webui 2024-02-20 23:25:57 +08:00
weishu
65bff7bf03 manager: Allow localstroage for webview 2024-02-20 20:23:43 +08:00
weishu
30dfbbdc0e ksud: support self stop server 2024-02-20 19:58:40 +08:00
weishu
fceffc9cfe manager: support load module webui 2024-02-20 19:21:07 +08:00
weishu
01b685ce58 kernel: Allow system_server to kill su process 2024-02-20 18:16:43 +08:00
weishu
cbd184421c ksud: Add support for module webui 2024-02-20 16:39:05 +08:00
weishu
b0a42abf4f ksud: Add support for module webui 2024-02-20 16:23:40 +08:00
weishu
cfc982f2f3 ksud: don't reclaim when enable/disable modules 2024-02-19 16:36:41 +08:00
weishu
e0e7058d14 ksud: reclaim sparse space when install/uninstall modules. close #1367 2024-02-19 15:29:03 +08:00
weishu
e0802b0d15 ksud: check image before shrink 2024-02-19 12:31:35 +08:00
igor
81f15ef120 Translate templates into Brazilian Portuguese (#1362)
Co-authored-by: weishu <twsxtd@gmail.com>
2024-02-18 11:40:48 +08:00
Syuugo
20c19d7126 Update mamager configs (#1359)
Upgrade Gradle and AGP.

Fixing workflow.
2024-02-18 11:40:05 +08:00
Pr0pHesyer
a360cd87c0 Update msm8998 in repos.json (#1363)
A repository still under maintenance
2024-02-18 11:39:50 +08:00
Ali Beyaz
ea9b572402 Turkish translations of Root Templates (#1356) 2024-02-17 11:24:39 +08:00
5ec1cff
6bf9e0478e ci: upload manager mappings (#1351) 2024-02-07 01:15:34 +08:00
LoveSy
abf0dacb36 Add fallback to mount syscall (#1349) 2024-02-05 17:36:07 +08:00
github-actions[bot]
263b986bcd [add device]: (#1345)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/1344

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-02-04 10:53:42 +08:00
weishu
15bdd9f507 ci: fix wsa and chromeos ci 2024-02-04 10:52:57 +08:00
backslashxx
810a62f795 [Add devices] daisy, sakura, ysl, sunny/mojito, fog/rain/wind (#1340)
Multiple devices

- Mi A2 Lite (daisy) / Redmi 6 Pro (sakura) + Redmi S2/Y2 (ysl) - 4.9

60a7363a15

4c67fcbcb6
- Redmi Note 10 (sunny/mojito) - 4.14

51cbedbeaa

96634ef252
- Redmi 10C (fog/rain/wind) - 4.19

fd2e365b80

126694822e
2024-02-03 20:40:10 +08:00
weishu
07e475c5dc kernel: prevent become manager when failed. close #1328 2024-02-03 20:03:26 +08:00
Masum Reza
eb02e42bc7 Added shizuku.root template (#1330)
Shizuku only needs DAC_OVERRIDE to execute the script to start the
Shizuku service.
Also added bengali translation for the name and description.
2024-02-02 13:08:55 +08:00
weishu
5db51b0715 manager: fix misleading tips when grant root failed. 2024-02-02 12:25:30 +08:00
weishu
60d2685f7e ksud: Fix dependency 2024-02-02 11:25:54 +08:00
LoveSy
a4b9ea04a4 Use as_ref instead of as_slice (#1336) 2024-02-02 10:40:36 +08:00
LoveSy
f80d0764b5 Use rustix for setgroups (#1334) 2024-02-01 23:35:42 +08:00
LoveSy
f80769a82a Recursive bind mount (#1332) 2024-02-01 23:29:19 +08:00
LoveSy
64269c8c4f Use rustix for prctl (#1333) 2024-02-01 23:28:56 +08:00
weishu
9f04482b90 ksud: allow to set upperdir and workdir for overlayfs 2024-02-01 18:02:10 +08:00
weishu
aca505c3e6 ksud: Fix bind mount failed 2024-02-01 17:15:44 +08:00
weishu
d4826bc97c ksud: fmt 2024-02-01 16:33:33 +08:00
weishu
4efc8164f1 ksud: Fix overlayfs mount 2024-02-01 16:32:18 +08:00
weishu
0fc25cf091 ksud: remove unused methods 2024-02-01 16:32:18 +08:00
Ali Beyaz
ca438291cc Update README_TR.md (#1329) 2024-02-01 15:44:06 +08:00
LoveSy
d6cab60e6d Merge pull request #1325 from tiann/rustix 2024-02-01 14:19:18 +08:00
LoveSy
4d4bd4793f Use new mount api 2024-02-01 01:50:30 +08:00
LoveSy
c1a2cbf1e4 Use rustix to replace some unsafe calls 2024-02-01 00:35:51 +08:00
igor
4b1fb121b4 website: update translation (#1322) 2024-01-31 11:16:57 +08:00
weishu
883a3e3407 ksud: force-stop manager when set-manager 2024-01-31 11:15:23 +08:00
weishu
27bd18f60e ksud: fix potential slow copy 2024-01-30 22:34:33 +08:00
weishu
7cb5fb47e1 ksud: Add command to shrink image 2024-01-30 13:23:49 +08:00
weishu
d43b40572d ksud: clippy 2024-01-30 12:59:24 +08:00
weishu
c99b5b31c1 ksud: fmt 2024-01-30 12:58:20 +08:00
weishu
ca960a2a8f ksud: shrink image before resize 2024-01-30 12:56:59 +08:00
weishu
cce423a2f6 ksud: Add cli for fast copy sparse file 2024-01-30 12:56:59 +08:00
weishu
946fb6f999 ksud: default 1T for sparse file 2024-01-30 12:56:59 +08:00
weishu
b6ecce4317 ksud: use default block size to reduce image size 2024-01-30 12:56:59 +08:00
weishu
be70a91f16 ksud: resize the journal size of image 2024-01-30 12:56:59 +08:00
weishu
71c2790f08 ksud: remove unnecessary image check 2024-01-30 12:56:59 +08:00
Bot_wxt1221
8733b390ca [Change device]Onepluus 6T&6 (#1315)
Because of the different implementation of dynastic partition. It only
boots on crdroid.
2024-01-30 11:08:17 +08:00
c4e106d6f8 website: [pt_BR]: Add description for sparse file (#1321)
Signed-off-by: 明 <akariondev@gmail.com>
Signed-off-by: akari <akariondev@gmail.com>
Co-authored-by: Ylarod <me@ylarod.cn>
Co-authored-by: weishu <twsxtd@gmail.com>
2024-01-30 11:06:41 +08:00
weishu
b612efcfad ksud: sparse file default 256G 2024-01-29 21:49:39 +08:00
weishu
7f53882007 manager: Fix icon for settings update 2024-01-29 21:43:55 +08:00
weishu
23ba3182cf website: Add description for sparse file 2024-01-29 21:42:52 +08:00
weishu
8abd37a35c manager: Add option to disable update close #1303 2024-01-29 21:33:24 +08:00
weishu
d7bc853bfc ksud: use sparse image to avoiding resize image. close #1220 2024-01-29 18:50:19 +08:00
weishu
16c5aba4ff ksud: fix dd failure 2024-01-29 15:51:54 +08:00
Jung-Chi Wang
3914242457 [Add devices] Oneplus 7 Serials (#1317)
Add unofficial support devices

![20240127213056](https://github.com/tiann/KernelSU/assets/447101/feeb6be7-7e96-4572-9062-879fbb1ae08d)
2024-01-27 22:10:40 +08:00
Weblate (bot)
eaa12161d6 Translations update from Hosted Weblate (#1284)
Translations update from [Hosted Weblate](https://hosted.weblate.org)
for
[KernelSU/Manager](https://hosted.weblate.org/projects/kernelsu/manager/).



Current translation status:

![Weblate translation
status](https://hosted.weblate.org/widget/kernelsu/manager/horizontal-auto.svg)

---------

Co-authored-by: 聖小熊 <as406010503@gmail.com>
Co-authored-by: I g o r <igormczampola1@gmail.com>
Co-authored-by: dabao1955 <dabao1955@163.com>
Co-authored-by: Mahendar Y <mahendar625934@gmail.com>
Co-authored-by: Ali Beyaz <alipolatbeyaz@gmail.com>
Co-authored-by: Integral <integral@murena.io>
Co-authored-by: 周港 <z200645049@gmail.com>
Co-authored-by: LolekLiam <liamstaric@gmail.com>
Co-authored-by: Skallr2 <pm563838@gmail.com>
Co-authored-by: charlotte <charlotterose@duck.com>
2024-01-27 11:31:11 +08:00
秋秋
0f985917f9 ci: Remove ccache patch (#1312)
We don't need it
2024-01-24 14:11:19 +08:00
igor
a569b1c76e docs: fix typos in readme (#1311) 2024-01-23 21:12:11 +08:00
KeJia
7f1ea2e178 [非官方支持设备]修正K-Nel-M1721内核的仓库网址 (#1308)
合并之前没发现偏偏合并以后发现多了个https://
之前的合并请求关闭了,只能再开一个()
2024-01-22 20:35:24 +08:00
Guanran928
da89a45d56 fix typo (#1300)
AdAday -> AdAway
2024-01-22 15:23:56 +08:00
KeJia
dc2fb20d24 [Add devices]Meizu M6 Note (#1305)
Add an unofficial support device
I will follow the updates of KernelSU to maintain the kernel for a long
time
2024-01-22 15:23:38 +08:00
Fede2782
d7625722db [add device]: Samsung Galaxy A34 5G (#1293) 2024-01-19 09:06:55 +08:00
igor
4144f10d9a website: fix translation readme: fix translation (#1297) 2024-01-19 09:06:31 +08:00
aaddaf1a78 website/docs: we don't need to use markdown for this, as it's not exactly a patch or sh file. (#1298)
```
# KernelSU 
CONFIG_KSU=y
```

---------

Signed-off-by: 明 <akariondev@gmail.com>
Signed-off-by: akari <akariondev@gmail.com>
Co-authored-by: Ylarod <me@ylarod.cn>
Co-authored-by: weishu <twsxtd@gmail.com>
2024-01-19 09:05:56 +08:00
181 changed files with 6915 additions and 3091 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.bat eol=crlf

21
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: daily
- package-ecosystem: cargo
directory: userspace/ksud
schedule:
interval: daily
- package-ecosystem: gradle
directory: manager
schedule:
interval: daily
- package-ecosystem: npm
directory: website
schedule:
interval: daily

View File

@@ -0,0 +1,71 @@
<?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>

View File

@@ -0,0 +1,37 @@
<manifest>
<!-- https://ci.android.com/builds/submitted/11275718/kernel_virt_aarch64/latest/manifest_11275718.xml -->
<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="43337ece156eabd735426a0b007637bb52fa7339">
<linkfile dest="tools/bazel" src="kleaf/bazel.sh"/>
<linkfile dest="WORKSPACE" src="kleaf/bazel.WORKSPACE"/>
</project>
<project path="common" name="kernel/common" revision="515a956763d8c874d9a7e23528332bf907b31748"/>
<project path="kernel/common-patches" name="kernel/common-patches" revision="495419530db8761a40f8db9fb734a9be78fa25fd">
<linkfile dest="common/patches" src="android-mainline"/>
</project>
<project path="kernel/tests" name="kernel/tests" revision="99abfd276063ab3a7748939aa55e107aaca903f6"/>
<project path="kernel/configs" name="kernel/configs" revision="786dab5f2f49b983b7c448d45a50c62d36e9f7f9"/>
<project path="common-modules/virtual-device" name="kernel/common-modules/virtual-device" revision="5c7466d6fc47f7ee2245f9ee6471cd78e6ff82f0"/>
<project path="prebuilts/clang/host/linux-x86" name="platform/prebuilts/clang/host/linux-x86" revision="1400cf7d2f0d28c425737d7b58c1f67c52db087f" 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="99e41849eb3895574b1dc7e854ca15cb3fb11a71"/>
<project path="prebuilts/build-tools" name="platform/prebuilts/build-tools" clone-depth="1" groups="ddk" revision="93e69718fd53f0c3dd7f0087657dfe2e78926830"/>
<project path="prebuilts/clang-tools" name="platform/prebuilts/clang-tools" clone-depth="1" revision="bf33473342630944198190ff74e6ca09a9bcfdeb"/>
<project path="prebuilts/kernel-build-tools" name="kernel/prebuilts/build-tools" clone-depth="1" groups="ddk" revision="4b68c02455e6ce5c87ccf8e09e629f0177771a8c"/>
<project path="prebuilts/rust" name="platform/prebuilts/rust" revision="7e636e2a1b7cf415c3c01981e439d98843dc4973" clone-depth="1"/>
<project path="prebuilts/tradefed" name="platform/tools/tradefederation/prebuilts" clone-depth="1" revision="79d9ec16c1e4e747b0bfad9a80a1665080c42d7b"/>
<project path="prebuilts/asuite" name="platform/prebuilts/asuite" clone-depth="1" revision="9e2738f6242785a3b2096010ce63363a160c122f"/>
<project path="tools/mkbootimg" name="platform/system/tools/mkbootimg" revision="722e6fa37d508b190fafa9a8ce9f6d571fad3a8c"/>
<project path="prebuilts/jdk/jdk11" name="platform/prebuilts/jdk/jdk11" revision="06351a976e772d8a9cdb133bb982032c64ee9e53" clone-depth="1" groups="ddk"/>
<project path="prebuilts/ndk-r26" name="toolchain/prebuilts/ndk/r26" clone-depth="1" groups="ddk" revision="e87abe7cbe9143d239ba54f32c64ca697adcba75"/>
<project path="external/bazel-skylib" name="platform/external/bazel-skylib" groups="ddk" revision="930baaa09975eb3809629a72806acbe9494dd224"/>
<project path="build/bazel_common_rules" name="platform/build/bazel_common_rules" groups="ddk" revision="5fb8d26dfb2565e0e2d8b6630d241b5f5675e0b1"/>
<project path="external/libcap-ng" name="platform/external/libcap-ng" revision="2bcc92ae19481dd2b8d3ce3abdfbbee49261abe6"/>
<project path="external/libcap" name="platform/external/libcap" revision="9577b17009379649c9220edca7d0077311445b95"/>
<project path="external/stardoc" name="platform/external/stardoc" groups="ddk" revision="85b0f239303220d902ad919ff27d2da475fc12e2"/>
<project path="external/python/absl-py" name="platform/external/python/absl-py" groups="ddk" revision="8cc5fc4798ef442b0c5b70c1ecc7e45a8f6eb2f8"/>
<project path="external/bazelbuild-rules_cc" name="platform/external/bazelbuild-rules_cc" groups="ddk" revision="9a4853f0327e0266818c8d6b4967e2e8f36b1a88"/>
<project path="external/bazelbuild-rules_python" name="platform/external/bazelbuild-rules_python" groups="ddk" revision="3e21f23d9400ba51f10e9b76016ff6d472829b4e"/>
<project path="external/bazelbuild-rules_rust" name="platform/external/bazelbuild-rules_rust" revision="bdd24099a80555ff8a4441e8bb47f4c7cfe413f8"/>
</manifest>

View File

@@ -1,48 +0,0 @@
From f1e398602b989ac197cdd0fda4a7c4c323b03eb9 Mon Sep 17 00:00:00 2001
From: DozNaka <dozdguide@gmail.com>
Date: Mon, 11 Apr 2022 20:43:45 -0400
Subject: [PATCH] Makefile: Use CCACHE for faster compilation
---
Makefile | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/Makefile b/Makefile
index e8b8d5894..51e8aac6e 100644
--- a/Makefile
+++ b/Makefile
@@ -442,21 +442,21 @@ KBUILD_HOSTLDLIBS := $(HOST_LFS_LIBS) $(HOSTLDLIBS)
# Make variables (CC, etc...)
CPP = $(CC) -E
ifneq ($(LLVM),)
-CC = clang
-LD = ld.lld
-AR = llvm-ar
+CC = $(CCACHE) clang
+LD = $(CCACHE) ld.lld
+AR = $(CCACHE) llvm-ar
NM = llvm-nm
-OBJCOPY = llvm-objcopy
-OBJDUMP = llvm-objdump
+OBJCOPY = $(CCACHE) llvm-objcopy
+OBJDUMP = $(CCACHE) llvm-objdump
READELF = llvm-readelf
STRIP = llvm-strip
else
-CC = $(CROSS_COMPILE)gcc
-LD = $(CROSS_COMPILE)ld
-AR = $(CROSS_COMPILE)ar
+CC = $(CCACHE) $(CROSS_COMPILE)gcc
+LD = $(CCACHE) $(CROSS_COMPILE)ld
+AR = $(CCACHE) $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
-OBJCOPY = $(CROSS_COMPILE)objcopy
-OBJDUMP = $(CROSS_COMPILE)objdump
+OBJCOPY = $(CCACHE) $(CROSS_COMPILE)objcopy
+OBJDUMP = $(CCACHE) $(CROSS_COMPILE)objdump
READELF = $(CROSS_COMPILE)readelf
STRIP = $(CROSS_COMPILE)strip
endif
--
2.37.2

View File

@@ -1,48 +0,0 @@
From f1e398602b989ac197cdd0fda4a7c4c323b03eb9 Mon Sep 17 00:00:00 2001
From: DozNaka <dozdguide@gmail.com>
Date: Mon, 11 Apr 2022 20:43:45 -0400
Subject: [PATCH] Makefile: Use CCACHE for faster compilation
---
Makefile | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/Makefile b/Makefile
index e8b8d5894..51e8aac6e 100644
--- a/Makefile
+++ b/Makefile
@@ -442,21 +442,21 @@ KBUILD_HOSTLDLIBS := $(HOST_LFS_LIBS) $(HOSTLDLIBS)
# Make variables (CC, etc...)
CPP = $(CC) -E
ifneq ($(LLVM),)
-CC = clang
-LD = ld.lld
-AR = llvm-ar
+CC = $(CCACHE) clang
+LD = $(CCACHE) ld.lld
+AR = $(CCACHE) llvm-ar
NM = llvm-nm
-OBJCOPY = llvm-objcopy
-OBJDUMP = llvm-objdump
+OBJCOPY = $(CCACHE) llvm-objcopy
+OBJDUMP = $(CCACHE) llvm-objdump
READELF = llvm-readelf
STRIP = llvm-strip
else
-CC = $(CROSS_COMPILE)gcc
-LD = $(CROSS_COMPILE)ld
-AR = $(CROSS_COMPILE)ar
+CC = $(CCACHE) $(CROSS_COMPILE)gcc
+LD = $(CCACHE) $(CROSS_COMPILE)ld
+AR = $(CCACHE) $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
-OBJCOPY = $(CROSS_COMPILE)objcopy
-OBJDUMP = $(CROSS_COMPILE)objdump
+OBJCOPY = $(CCACHE) $(CROSS_COMPILE)objcopy
+OBJDUMP = $(CCACHE) $(CROSS_COMPILE)objdump
READELF = $(CROSS_COMPILE)readelf
STRIP = $(CROSS_COMPILE)strip
endif
--
2.37.2

View File

@@ -51,7 +51,7 @@ build_from_image() {
echo "[+] Images to upload"
find . -type f -name "*.gz"
find . -type f -name "*.gz" -exec python3 "$GITHUB_WORKSPACE"/KernelSU/scripts/ksubot.py {} +
# find . -type f -name "*.gz" -exec python3 "$GITHUB_WORKSPACE"/KernelSU/scripts/ksubot.py {} +
}
for dir in Image*; do

View File

@@ -30,7 +30,7 @@ build_from_image() {
echo '[+] Images to upload'
find . -type f -name "*.gz"
find . -type f -name "*.gz" -exec python3 "$GITHUB_WORKSPACE"/KernelSU/scripts/ksubot.py {} +
# find . -type f -name "*.gz" -exec python3 "$GITHUB_WORKSPACE"/KernelSU/scripts/ksubot.py {} +
}
for dir in Image*; do

View File

@@ -26,7 +26,7 @@ jobs:
- name: Make pull request
if: steps.handle-add-device.outputs.success == 'true'
id: cpr
uses: peter-evans/create-pull-request@v4
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "[add device]: ${{ steps.handle-add-device.outputs.device }}"
@@ -53,7 +53,7 @@ jobs:
message: "Cannot create pull request. Please check the issue content. Or you can create a pull request manually."
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: close issue
uses: peter-evans/close-issue@v1
uses: peter-evans/close-issue@v3
with:
issue-number: ${{ github.event.issue.number }}
token: ${{ secrets.GITHUB_TOKEN }}

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

@@ -0,0 +1,135 @@
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-latest
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
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/.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
env:
PATCH_PATH: ${{ inputs.patch_path }}
IS_DEBUG_KERNEL: ${{ inputs.debug }}
run: |
cd $GITHUB_WORKSPACE/android-kernel
echo "[+] KernelSU setup"
GKI_ROOT=$(pwd)
echo "[+] GKI_ROOT: $GKI_ROOT"
echo "[+] Copy KernelSU driver to $GKI_ROOT/common/drivers"
ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $GKI_ROOT/common/drivers/kernelsu
echo "[+] Add KernelSU driver to Makefile"
DRIVER_MAKEFILE=$GKI_ROOT/common/drivers/Makefile
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "\nobj-y += kernelsu/\n" >> "$DRIVER_MAKEFILE"
echo "[+] Apply KernelSU patches"
cd $GKI_ROOT/common/ && git apply $GITHUB_WORKSPACE/KernelSU/.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/kernel/Makefile
fi
repo status
echo "[+] KernelSU setup done."
cd $GITHUB_WORKSPACE/KernelSU
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 "KernelSUBot"
cd common/ && git add -A && git commit -a -m "Add KernelSU"
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 }}"

View File

@@ -21,22 +21,6 @@ jobs:
strategy:
matrix:
include:
- sub_level: 66
os_patch_level: 2022-01
- sub_level: 81
os_patch_level: 2022-03
- sub_level: 101
os_patch_level: 2022-05
- sub_level: 110
os_patch_level: 2022-07
- sub_level: 117
os_patch_level: 2022-09
- sub_level: 136
os_patch_level: 2022-11
- sub_level: 149
os_patch_level: 2023-01
- sub_level: 160
os_patch_level: 2023-03
- sub_level: 168
os_patch_level: 2023-05
- sub_level: 177
@@ -44,7 +28,9 @@ jobs:
- sub_level: 185
os_patch_level: 2023-09
- sub_level: 198
os_patch_level: 2023-11
os_patch_level: 2024-01
- sub_level: 205
os_patch_level: 2024-03
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
@@ -97,7 +83,8 @@ jobs:
- name: Bot session cache
id: bot_session_cache
uses: actions/cache@v3
uses: actions/cache@v4
if: false
with:
path: scripts/ksubot.session
key: ${{ runner.os }}-bot-session
@@ -132,4 +119,4 @@ jobs:
version_name: android12-5.10.177
tag: android12-5.10-2023-06
os_patch_level: 2023-06
patch_path: "5.10"
patch_path: "5.10"

View File

@@ -21,21 +21,15 @@ jobs:
strategy:
matrix:
include:
- version: "5.10"
sub_level: 107
os_patch_level: 2022-11
- version: "5.10"
sub_level: 149
os_patch_level: 2023-01
- version: "5.10"
sub_level: 157
os_patch_level: 2023-03
- version: "5.10"
sub_level: 168
os_patch_level: 2023-05
- version: "5.10"
sub_level: 177
os_patch_level: 2023-06
os_patch_level: 2023-07
- version: "5.10"
sub_level: 177
os_patch_level: 2024-02
- version: "5.10"
sub_level: 186
os_patch_level: 2023-08
@@ -48,15 +42,12 @@ jobs:
- version: "5.10"
sub_level: 198
os_patch_level: 2023-12
- version: "5.15"
sub_level: 41
os_patch_level: 2022-11
- version: "5.15"
sub_level: 74
os_patch_level: 2023-01
- version: "5.15"
sub_level: 78
os_patch_level: 2023-03
- version: "5.10"
sub_level: 205
os_patch_level: 2024-02
- version: "5.10"
sub_level: 205
os_patch_level: 2024-03
- version: "5.15"
sub_level: 94
os_patch_level: 2023-05
@@ -72,6 +63,9 @@ jobs:
- version: "5.15"
sub_level: 137
os_patch_level: 2023-12
- version: "5.15"
sub_level: 144
os_patch_level: 2024-02
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
@@ -124,7 +118,8 @@ jobs:
- name: Bot session cache
id: bot_session_cache
uses: actions/cache@v3
uses: actions/cache@v4
if: false
with:
path: scripts/ksubot.session
key: ${{ runner.os }}-bot-session

View File

@@ -27,6 +27,12 @@ jobs:
- version: "5.15"
sub_level: 131
os_patch_level: 2023-11
- version: "5.15"
sub_level: 137
os_patch_level: 2024-01
- version: "5.15"
sub_level: 144
os_patch_level: 2024-03
- version: "6.1"
sub_level: 25
os_patch_level: 2023-10
@@ -35,7 +41,10 @@ jobs:
os_patch_level: 2023-11
- version: "6.1"
sub_level: 57
os_patch_level: 2023-12
os_patch_level: 2024-01
- version: "6.1"
sub_level: 68
os_patch_level: 2024-03
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
@@ -88,7 +97,8 @@ jobs:
- name: Bot session cache
id: bot_session_cache
uses: actions/cache@v3
uses: actions/cache@v4
if: false
with:
path: scripts/ksubot.session
key: ${{ runner.os }}-bot-session
@@ -123,10 +133,13 @@ jobs:
- version: "5.15"
sub_level: 110
os_patch_level: 2023-09
- version: "6.1"
sub_level: 68
os_patch_level: 2024-03
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 }}
patch_path: ${{ matrix.version }}

View File

@@ -82,7 +82,7 @@ jobs:
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
echo "[+] Apply KernelSU patches"
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/5.10/*.patch
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/5.10/*.patch || echo "[-] No patch found"
echo "[+] Patch script/setlocalversion"
sed -i 's/-dirty//g' $KERNEL_ROOT/scripts/setlocalversion
@@ -114,35 +114,4 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: kernel-ARCVM-${{ matrix.arch }}-${{ matrix.version }}
path: "${{ env.file_path }}"
- name: Bot session cache
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
id: bot_session_cache
uses: actions/cache@v3
with:
path: scripts/ksubot.session
key: ${{ runner.os }}-bot-session
- name: Post to Telegram
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
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 }}
run: |
TITLE=kernel-ARCVM-${{ matrix.arch }}-${{ matrix.version }}
echo "[+] title: $TITLE"
export TITLE
export VERSION="${{ env.kernelsu_version }}"
echo "[+] Compress images"
gzip -n -f -9 "${{ env.file_path }}"
echo "[+] Image to upload"
ls -l "${{ env.file_path }}.gz"
if [ -n "${{ secrets.BOT_TOKEN }}" ]; then
pip3 install telethon==1.31.1
python3 "$GITHUB_WORKSPACE/KernelSU/scripts/ksubot.py" "${{ env.file_path }}.gz"
fi
path: "${{ env.file_path }}"

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

@@ -0,0 +1,37 @@
name: Build Kernel - AVD
on:
push:
branches: ["main", "ci", "checkci"]
paths:
- ".github/workflows/build-kernel-avd.yml"
- ".github/workflows/avd-kernel.yml"
- ".github/workflows/manifests/*xml"
- "kernel/**"
pull_request:
branches: ["main"]
paths:
- ".github/workflows/build-kernel-avd.yml"
- ".github/workflows/avd-kernel.yml"
- ".github/workflows/manifests/*.xml"
- "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"
with:
version_name: ${{ matrix.version }}
manifest_name: ${{ matrix.manifest }}
arch: ${{ matrix.arch }}
debug: true

View File

@@ -13,13 +13,29 @@ on:
- '.github/workflows/ksud.yml'
- 'userspace/ksud/**'
jobs:
build-lkm:
uses: ./.github/workflows/build-lkm.yml
secrets: inherit
build:
needs: build-lkm
strategy:
matrix:
include:
- target: aarch64-linux-android
os: ubuntu-latest
- target: x86_64-linux-android
- target: x86_64-pc-windows-gnu # only for build
os: ubuntu-latest
- target: x86_64-pc-windows-gnu # windows pc
os: ubuntu-latest
- target: x86_64-apple-darwin # Intel mac
os: macos-latest
- target: aarch64-apple-darwin # M chip mac
os: macos-latest
- target: aarch64-unknown-linux-musl # arm64 Linux
os: ubuntu-latest
- target: x86_64-unknown-linux-musl # x86 Linux
os: ubuntu-latest
uses: ./.github/workflows/ksud.yml
with:
target: ${{ matrix.target }}
os: ${{ matrix.os }}

42
.github/workflows/build-lkm.yml vendored Normal file
View File

@@ -0,0 +1,42 @@
name: Build LKM for KernelSU
on:
push:
branches: ["main", "ci", "checkci"]
paths:
- ".github/workflows/gki-kernel.yml"
- ".github/workflows/build-lkm.yml"
- "kernel/**"
pull_request:
branches: ["main"]
paths:
- ".github/workflows/gki-kernel.yml"
- ".github/workflows/build-lkm.yml"
- "kernel/**"
workflow_call:
jobs:
build-lkm:
strategy:
matrix:
include:
- version: "android12-5.10"
sub_level: 198
os_patch_level: "2024-01"
- version: "android13-5.10"
sub_level: 198
os_patch_level: 2023-12
- version: "android13-5.15"
sub_level: 137
os_patch_level: 2023-12
- version: "android14-5.15"
sub_level: 110
os_patch_level: 2023-09
- version: "android14-6.1"
sub_level: 43
os_patch_level: 2023-11
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

View File

@@ -2,10 +2,11 @@ name: Build Manager
on:
push:
branches: [ "main" ]
branches: [ "main", "ci" ]
paths:
- '.github/workflows/build-manager.yml'
- 'manager/**'
- 'kernel/**'
- 'userspace/ksud/**'
pull_request:
branches: [ "main" ]
@@ -14,7 +15,12 @@ on:
workflow_call:
jobs:
build-lkm:
uses: ./.github/workflows/build-lkm.yml
secrets: inherit
build-ksud:
needs: build-lkm
strategy:
matrix:
include:
@@ -50,11 +56,13 @@ jobs:
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
run: |
if [ ! -z "${{ secrets.KEYSTORE }}" ]; then
echo KEYSTORE_PASSWORD='${{ secrets.KEYSTORE_PASSWORD }}' >> gradle.properties
echo KEY_ALIAS='${{ secrets.KEY_ALIAS }}' >> gradle.properties
echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}' >> gradle.properties
echo KEYSTORE_FILE='../key.jks' >> gradle.properties
echo ${{ secrets.KEYSTORE }} | base64 --decode > key.jks
{
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
@@ -64,7 +72,7 @@ jobs:
java-version: "17"
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
uses: gradle/gradle-build-action@v3
with:
gradle-home-cache-cleanup: true
@@ -100,14 +108,22 @@ jobs:
- name: Upload build artifact
uses: actions/upload-artifact@v4
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
with:
name: manager
path: manager/app/build/outputs/apk/release/*.apk
- name: Upload mappings
uses: actions/upload-artifact@v4
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
with:
name: "mappings"
path: "manager/app/build/outputs/mapping/release/"
- name: Bot session cache
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
id: bot_session_cache
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: scripts/ksubot.session
key: ${{ runner.os }}-bot-session

View File

@@ -36,29 +36,4 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: su
path: ./userspace/su/libs
- name: Bot session cache
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
id: bot_session_cache
uses: actions/cache@v3
with:
path: scripts/ksubot.session
key: ${{ runner.os }}-bot-session
- name: Upload to telegram
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
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 }}
TITLE: SU
run: |
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
export VERSION=$(git rev-list --count HEAD)
pip3 install telethon==1.31.1
mv ./userspace/su/libs/arm64-v8a/su su-arm64
mv ./userspace/su/libs/x86_64/su su-x86_64
python3 scripts/ksubot.py su-arm64 su-x86_64
fi
path: ./userspace/su/libs

View File

@@ -22,14 +22,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# cross build failed after Rust 1.68, see https://github.com/cross-rs/cross/issues/1222
- run: rustup default 1.67.0
- run: rustup update --force-non-host stable-x86_64-unknown-linux-gnu
- uses: Swatinem/rust-cache@v2
with:
workspaces: userspace/ksud
- name: Install cross
run: cargo install cross --locked
run: |
cargo install cross --git https://github.com/cross-rs/cross --rev 66845c1
- name: Run clippy
run: |

View File

@@ -29,7 +29,7 @@ on:
for example: 2021-11
default: 2022-05
patch_path:
required: true
required: false
type: string
description: >
Directory name of .github/patches/<patch_path>
@@ -49,6 +49,10 @@ on:
required: false
type: boolean
default: false
build_lkm:
required: false
type: boolean
default: false
secrets:
BOOT_SIGN_KEY:
required: false
@@ -124,13 +128,15 @@ jobs:
ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $GKI_ROOT/common/drivers/kernelsu
echo "[+] Add KernelSU driver to Makefile"
DRIVER_MAKEFILE=$GKI_ROOT/common/drivers/Makefile
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_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 patches"
cd $GKI_ROOT/common/ && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/$PATCH_PATH/*.patch || echo "[-] No patch found"
if [ "$IS_DEBUG_KERNEL" = "true" ]; then
echo "[+] Enable debug features for kernel"
echo "ccflags-y += -DCONFIG_KSU_DEBUG" >> $GITHUB_WORKSPACE/KernelSU/kernel/Makefile
printf "\nccflags-y += -DCONFIG_KSU_DEBUG\n" >> $GITHUB_WORKSPACE/KernelSU/kernel/Makefile
fi
repo status
echo "[+] KernelSU setup done."
@@ -154,6 +160,34 @@ jobs:
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: |
@@ -163,7 +197,7 @@ jobs:
cd common/ && git add -A && git commit -a -m "Add KernelSU"
repo status
- name: Build boot.img
- name: Build Kernel/LKM
working-directory: android-kernel
run: |
if [ ! -z ${{ vars.EXPECTED_SIZE }} ] && [ ! -z ${{ vars.EXPECTED_HASH }} ]; then
@@ -171,7 +205,7 @@ jobs:
export KSU_EXPECTED_HASH=${{ vars.EXPECTED_HASH }}
fi
if [ -e build/build.sh ]; then
CCACHE="/usr/bin/ccache" LTO=thin BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh
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
@@ -184,20 +218,34 @@ jobs:
OUTDIR=android-kernel/dist
fi
mkdir output
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/
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

View File

@@ -5,32 +5,53 @@ on:
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: ubuntu-latest
runs-on: ${{ inputs.os }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
# cross build failed after Rust 1.68, see https://github.com/cross-rs/cross/issues/1222
- run: rustup default 1.67.0
- name: Download artifacts
uses: actions/download-artifact@v4
- name: Prepare LKM fies
if: ${{ inputs.pack_lkm }}
run: |
cp android*-lkm/*_kernelsu.ko ./userspace/ksud/bin/aarch64/
- name: Setup rustup
run: |
rustup update stable
rustup target add x86_64-apple-darwin
rustup target add aarch64-apple-darwin
- uses: Swatinem/rust-cache@v2
with:
workspaces: userspace/ksud
cache-targets: false
- name: Install cross
run: cargo install cross --locked
run: |
cargo install cross --git https://github.com/cross-rs/cross --rev 66845c1
- name: Build ksud
run: cross build --target ${{ inputs.target }} --release --manifest-path ./userspace/ksud/Cargo.toml
run: CROSS_NO_WARNINGS=0 cross build --target ${{ inputs.target }} --release --manifest-path ./userspace/ksud/Cargo.toml
- name: Upload ksud artifact
uses: actions/upload-artifact@v4
with:
name: ksud-${{ inputs.target }}
path: userspace/ksud/target/**/release/ksud
path: userspace/ksud/target/**/release/ksud*

View File

@@ -67,10 +67,11 @@ jobs:
run: ls -R
- name: release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
with:
files: |
manager/*.apk
android*-lkm/*_kernelsu.ko
AnyKernel3-*.zip
boot-images-*/Image-*/*.img.gz
kernel-WSA*.zip

View File

@@ -30,7 +30,7 @@ jobs:
- name: Cache LLVM
id: cache-llvm
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ./llvm
key: llvm-12.0.1
@@ -75,7 +75,7 @@ jobs:
DRIVER_MAKEFILE=$KERNEL_ROOT/drivers/Makefile
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
echo "[+] Apply KernelSU patches"
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/5.15/*.patch
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/5.15/*.patch || echo "[-] No patch found"
echo "[+] KernelSU setup done."
cd $GITHUB_WORKSPACE/KernelSU
VERSION=$(($(git rev-list --count HEAD) + 10200))
@@ -101,35 +101,4 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: kernel-WSA-${{ inputs.arch }}-${{ inputs.version }}
path: "${{ env.file_path }}"
- name: Bot session cache
if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.ref_type == 'tag'
id: bot_session_cache
uses: actions/cache@v3
with:
path: scripts/ksubot.session
key: ${{ runner.os }}-bot-session
- name: Post to Telegram
if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.ref_type == 'tag'
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 }}
run: |
TITLE=kernel-${{ inputs.arch }}-WSA-${{ inputs.version }}
echo "[+] title: $TITLE"
export TITLE
export VERSION="${{ env.kernelsu_version }}"
echo "[+] Compress images"
gzip -n -f -9 "${{ env.file_path }}"
echo "[+] Image to upload"
ls -l "${{ env.file_path }}.gz"
if [ -n "${{ secrets.BOT_TOKEN }}" ]; then
pip3 install telethon==1.31.1
python3 "$GITHUB_WORKSPACE/KernelSU/scripts/ksubot.py" "${{ env.file_path }}.gz"
fi
path: "${{ env.file_path }}"

View File

@@ -1,5 +1,4 @@
**English** | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
**English** | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU
@@ -7,13 +6,12 @@
A Kernel-based root solution for Android devices.
[![latest release badge](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## Features
1. Kernel-based `su` and root access management.
@@ -43,12 +41,13 @@ To help translate KernelSU or improve existing translations, please use [Weblate
- Telegram: [@KernelSU](https://t.me/KernelSU)
## 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)
- 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).
## Credits

View File

@@ -1,4 +1,4 @@
[English](README.md) | [Español](README_ES.md) | **简体中文** | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
[English](README.md) | [Español](README_ES.md) | **简体中文** | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU
@@ -6,18 +6,17 @@
一个 Android 上基于内核的 root 方案。
[![latest release badge](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## 特性
- 基于内核的 `su` 和权限管理。
- 基于 [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) 的模块系统。
- [App Profile](https://kernelsu.org/guide/app-profile.html): 把 Root 权限关进笼子里。
- [App Profile](https://kernelsu.org/zh_CN/guide/app-profile.html): 把 Root 权限关进笼子里。
## 兼容状态
@@ -25,13 +24,13 @@ KernelSU 官方支持 GKI 2.0 的设备内核版本5.10以上);旧内核
WSA, ChromeOS 和运行在容器上的 Android 也可以与 KernelSU 一起工作。
目前支持架构 : `arm64-v8a``x86_64`
目前支持架构 : `arm64-v8a``x86_64`
## 使用方法
- [安装教程](https://kernelsu.org/zh_CN/guide/installation.html)
- [如何构建?](https://kernelsu.org/zh_CN/guide/how-to-build.html)
- [官方网站](https://kernelsu.org/)
- [官方网站](https://kernelsu.org/zh_CN/)
## 参与翻译
@@ -42,12 +41,13 @@ WSA, ChromeOS 和运行在容器上的 Android 也可以与 KernelSU 一起工
- Telegram: [@KernelSU](https://t.me/KernelSU)
## 安全性
有关报告 KernelSU 安全漏洞的信息,请参阅 [SECURITY.md](/SECURITY.md).
有关报告 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)
- 目录 `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)
## 鸣谢

View File

@@ -1,47 +1,56 @@
[ 🇬🇧 English](README.md) | 🇪🇸 **Español** | [🇨🇳 简体中文](README_CN.md) | [🇹🇼 繁體中文](README_TW.md) | [ 🇯🇵 日本語](README_JP.md) | [🇵🇱 Polski](README_PL.md) | [🇧🇷 Portuguese-Brazil](README_PT-BR.md) | [🇹🇷 Türkçe](README_TR.md) | [🇷🇺Русский](README_RU.md) | [🇻🇳Tiếng Việt](README_VI.md) | [ɪᴅ indonesia](README_ID.md) | [עברית](README_iw.md) | [🇮🇳हिंदी](README_IN.md)
[English](README.md) | **Español** | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
<div style="display: flex; align-items: center;">
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="">
<div style="margin-left: 20px;">
<span style="font-size: large; "><b>KernelSU</b></span>
<br>
<span style="font-size: medium; "><i>Una solución root basada en el kernel para dispositivos Android.</i></span>
</div>
</div>
# KernelSU
## 🚀 Características
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
**1.** Binario `su` basado en el kernel y gestión de acceso root.<br/>
**2.** Sistema de módulos basado en **OverlayFS**.
Una solución root basada en el kernel para dispositivos Android.
## ✅ Estado de compatibilidad
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localización-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Seguir-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/Licencia-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## Características
1. Binario `su` basado en el kernel y gestión de acceso root.
2. Sistema de módulos basado en [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
## Estado de compatibilidad
**KernelSU** soporta de forma oficial dispositivos Android con **GKI 2.0** (a partir de la versión **5.10** del kernel). Los kernels antiguos (a partir de la versión **4.14**) también son compatibles, pero necesitas compilarlos por tu cuenta.
El **Subsistema de Windows para Android (WSA)** e implementaciones de Android basadas en contenedores, como **Waydroid**, también deberían funcionar con **KernelSU** integrado.
Con esto, WSA, ChromeOS y Android basado en contenedores están todos compatibles.
Actualmente se soportan las siguientes **ABIs**: `arm64-v8a`; `x86_64`.
Actualmente, solo se admiten las arquitecturas `arm64-v8a` y `x86_64`.
## 📖 Uso
## Uso
[¿Cómo instalarlo?](https://kernelsu.org/guide/installation.html)
- [¿Cómo instalarlo?](https://kernelsu.org/guide/installation.html)
- [¿Cómo compilarlo?](https://kernelsu.org/guide/how-to-build.html)
- [Site oficial](https://kernelsu.org/)
## 🔨 Compilación
## Traducción
[¿Cómo compilarlo?](https://kernelsu.org/guide/how-to-build.html)
Para ayudar a traducir KernelSU o mejorar las traducciones existentes, utilice [Weblate](https://hosted.weblate.org/engage/kernelsu/). Ya no se aceptan PR de la traducción de Manager porque entrará en conflicto con Weblate.
## 💬 Discusión
## Discusión
- Telegram: [@KernelSU](https://t.me/KernelSU)
## ⚖️ Licencia
## Seguridad
- Los archivos bajo el directorio `kernel` están licenciados bajo [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- Todas las demás partes, a excepción del directorio `kernel`, están licenciados bajo [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html).
Para obtener información sobre cómo informar vulnerabilidades de seguridad en KernelSU, consulte [SECURITY.md](/SECURITY.md).
## 👥 Créditos
## Licencia
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): la idea de **KernelSU**.
- [genuine](https://github.com/brevent/genuine/): la validación del **esquema de firmas APK v2**.
- Los archivos bajo el directorio `kernel` están licenciados bajo [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- Todas las demás partes, a excepción del directorio `kernel`, están licenciados bajo [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
## Créditos
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): la idea de KernelSU.
- [Magisk](https://github.com/topjohnwu/Magisk): la poderosa herramienta root.
- [genuine](https://github.com/brevent/genuine/): validación de firma apk v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): algunas habilidades de rootkit.
- [Magisk](https://github.com/topjohnwu/Magisk): la implementación de la **política de SELinux (SEPolicy)**.

View File

@@ -1,13 +1,21 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portugis-Brasil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | **Indonesia** | [עברית](README_iw.md) | [हिंदी](README_IN.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | **Indonesia** | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
Solusi root berbasis Kernel untuk perangkat Android.
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## Fitur
1. Manajemen akses root dan `su` berbasis kernel.
2. Sistem modul berdasarkan overlayfs.
2. Sistem modul berdasarkan [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
3. [Profil Aplikasi](https://kernelsu.org/guide/app-profile.html): Kunci daya root di dalam sangkar.
## Status Kompatibilitas
@@ -20,9 +28,9 @@ Dan ABI yang didukung saat ini adalah: `arm64-v8a` dan `x86_64`
## Penggunaan
- [Petunjuk Instalasi](https://kernelsu.org/guide/installation.html)
- [Bagaimana cara membuat?](https://kernelsu.org/guide/how-to-build.html)
- [Situs Web Resmi](https://kernelsu.org/)
- [Petunjuk Instalasi](https://kernelsu.org/id_ID/guide/installation.html)
- [Bagaimana cara membuat?](https://kernelsu.org/id_ID/guide/how-to-build.html)
- [Situs Web Resmi](https://kernelsu.org/id_ID/)
## Terjemahan
@@ -34,8 +42,8 @@ Untuk menerjemahkan KernelSU ke dalam bahasa Anda atau menyempurnakan terjemahan
## Lisensi
- File di bawah direktori `kernel` adalah [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- Semua bagian lain kecuali direktori `kernel` adalah [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
- File di bawah direktori `kernel` adalah [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- Semua bagian lain kecuali direktori `kernel` adalah [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
## Kredit

View File

@@ -1,19 +1,21 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | **हिंदी**
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | **हिंदी**
# KernelSU
<div style="display: flex; align-items: center;">
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="">
<div style="margin-left: 20px;">
<span style="font-size: large; "><b>KernelSU</b></span>
<br>
<span style="font-size: medium; "><i>Android उपकरणों के लिए कर्नेल-आधारित रूट समाधान।</i></span>
</div>
</div>
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
Android उपकरणों के लिए कर्नेल-आधारित रूट समाधान।
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## विशेषताएँ
1. कर्नेल-आधारित `su` और रूट एक्सेस प्रबंधन।
2. Overlayfs पर आधारित मॉड्यूल प्रणाली।
2. [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) पर आधारित मॉड्यूल प्रणाली।
3. [App Profile](https://kernelsu.org/guide/app-profile.html): Root शक्ति को पिंजरे में बंद कर दो।
## अनुकूलता अवस्था
@@ -40,8 +42,8 @@ KernelSU का अनुवाद करने या मौजूदा अन
## लाइसेंस
- `Kernel` निर्देशिका के अंतर्गत फ़ाइलें हैं [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- `Kernel` निर्देशिका को छोड़कर अन्य सभी भाग हैं [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
- `Kernel` निर्देशिका के अंतर्गत फ़ाइलें हैं [GPL-2-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)
## आभार सूची

View File

@@ -1,13 +1,21 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | **עברית** | [हिंदी](README_IN.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | **עברית** | [हिंदी](README_IN.md)
# KernelSU
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
פתרון לניהול root מבוסס על Kernel עבור מכשירי Android.
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## תכונות
1. ניהול root ו־`su` מבוססים על Kernel.
2. מערכת מודולים מבוססת overlayfs.
2. מערכת מודולים מבוססת [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
3. [פרופיל אפליקציה](https://kernelsu.org/guide/app-profile.html): נעילת גישת root בכלוב.
## מצב תאימות
@@ -34,12 +42,12 @@ KernelSU תומך במכשירי Android GKI 2.0 (kernel 5.10+) באופן רש
## רשיון
- קבצים תחת הספרייה `kernel` מוגנים על פי [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- כל החלקים האחרים, למעט הספרייה `kernel`, מוגנים על פי [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
- קבצים תחת הספרייה `kernel` מוגנים על פי [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): כמה יכולות רוט.
- [Diamorphine](https://github.com/m0nad/Diamorphine): כמה יכולות רוט.

View File

@@ -1,4 +1,4 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | **日本語** | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | **日本語** | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU
@@ -6,19 +6,18 @@
Android におけるカーネルベースの root ソリューションです。
[![latest release badge](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![weblate](https://img.shields.io/badge/Localização-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Siga-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/Licença-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## 特徴
1. カーネルベースの `su` と権限管理
2. OverlayFS に基づくモジュールシステム
1. カーネルベースの `su` と権限管理
2. [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) に基づくモジュールシステム
3. [アプリのプロファイル](https://kernelsu.org/guide/app-profile.html): root の権限をケージ内に閉じ込めます。
## 対応状況
KernelSU は GKI 2.0 デバイス(カーネルバージョン 5.10 以上を公式にサポートしています。古いカーネル4.14以上)とも互換性がありますが、自分でカーネルをビルドする必要があります。
@@ -31,7 +30,7 @@ WSA 、ChromeOS とコンテナ上で動作する Android でも KernelSU を統
- [インストール方法はこちら](https://kernelsu.org/ja_JP/guide/installation.html)
- [ビルド方法はこちら](https://kernelsu.org/guide/how-to-build.html)
- [公式サイト](https://kernelsu.org)
- [公式サイト](https://kernelsu.org/ja_JP/)
## 翻訳
@@ -43,13 +42,12 @@ KernelSU をあなたの言語に翻訳するか、既存の翻訳を改善す
## ライセンス
- `kernel` ディレクトリの下にあるすべてのファイル: [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- `kernel` ディレクトリ以外のすべてのファイル: [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
- `kernel` ディレクトリの下にあるすべてのファイル: [GPL-2-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 のスキル
- [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 のスキル

View File

@@ -1,13 +1,21 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | **Polski** | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | **Polski** | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
Rozwiązanie root oparte na jądrze dla urządzeń z systemem Android.
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## Cechy
1. Oparte na jądrze `su` i zarządzanie dostępem roota.
2. System modułów oparty na overlayfs.
2. System modułów oparty na [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
## Kompatybilność
@@ -19,24 +27,29 @@ Aktualnie obsługiwane ABI to : `arm64-v8a` i `x86_64`.
## Użycie
[Instalacja](https://kernelsu.org/guide/installation.html)
- [Instalacja](https://kernelsu.org/guide/installation.html)
- [Jak skompilować?](https://kernelsu.org/guide/how-to-build.html)
## Kompilacja
## Tłumaczenie
[Jak skompilować?](https://kernelsu.org/guide/how-to-build.html)
Aby pomóc w tłumaczeniu KernelSU lub ulepszyć istniejące tłumaczenia, użyj [Weblate](https://hosted.weblate.org/engage/kernelsu/). PR tłumaczenia Managera nie jest już akceptowany, ponieważ będzie kolidował z Weblate.
## Dyskusja
- Telegram: [@KernelSU](https://t.me/KernelSU)
## Bezpieczeństwo
Informacje na temat zgłaszania luk w zabezpieczeniach w KernelSU można znaleźć w pliku [SECURITY.md](/SECURITY.md).
## Licencja
- Pliki w katalogu `kernel` są na licencji [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- Wszystkie inne części poza katalogiem `kernel` są na licencji [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
- Pliki w katalogu `kernel` są na licencji [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- Wszystkie inne części poza katalogiem `kernel` są na licencji [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
## Podziękowania
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): pomysłodawca KernelSU.
- [Magisk](https://github.com/topjohnwu/Magisk): implementacja sepolicy.
- [genuine](https://github.com/brevent/genuine/): walidacja podpisu apk v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): cenna znajomość rootkitów.
- [Magisk](https://github.com/topjohnwu/Magisk): implementacja sepolicy.

View File

@@ -1,4 +1,4 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | **Português (Brasil)** | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | **Português (Brasil)** | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU
@@ -6,21 +6,19 @@
Uma solução root baseada em kernel para dispositivos Android.
[![latest release badge](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![weblate](https://img.shields.io/badge/Localização-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Siga-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localização-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Seguir-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/Licença-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## Características
1. `su` e gerenciamento de acesso root baseado em kernel.
2. Sistema modular baseado em overlayfs.
2. Sistema modular baseado em [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
## Estado de compatibilidade
O KernelSU oferece suporte oficial a dispositivos Android GKI 2.0 (kernel 5.10+). Kernels mais antigos (4.14+) também são compatíveis, mas o kernel terá que ser construído manualmente.
@@ -29,22 +27,27 @@ Com isso, WSA, ChromeOS e Android baseado em contêiner são todos suportados.
Atualmente, apenas `arm64-v8a` e `x86_64` são suportados.
## Uso
- [Instalação](https://kernelsu.org/pt_BR/guide/installation.html)
- [Como construir o KernelSU?](https://kernelsu.org/pt_BR/guide/how-to-build.html)
- [Site oficial](https://kernelsu.org/pt_BR/)
## Tradução
Para contribuir com a tradução do KernelSU ou aprimorar traduções existentes, por favor, utilize o [Weblate](https://hosted.weblate.org/engage/kernelsu/). PR para a tradução do Gerenciador não são mais aceitos, pois podem entrar em conflito com o Weblate.
Para contribuir com a tradução do KernelSU ou aprimorar traduções existentes, por favor, utilize o [Weblate](https://hosted.weblate.org/engage/kernelsu/). PR para a tradução do Gerenciador não são mais aceitas, pois podem entrar em conflito com o Weblate.
## Discussão
- Telegram: [@KernelSU](https://t.me/KernelSU)
## 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](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- Todas as outras partes, exceto o diretório `kernel` são [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
- 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).
## Créditos

View File

@@ -1,13 +1,22 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | **Русский** | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | **Русский** | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
Решение на основе ядра root для Android-устройств.
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## Особенности
1. Управление `su` и root-доступом на основе ядра.
2. Система модулей на основе overlayfs.
2. Система модулей на основе [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
3. [Профиль приложений](https://kernelsu.org/ru_RU/guide/app-profile.html): Запри корневую силу в клетке.
## Совместимость
@@ -19,11 +28,9 @@ WSA и Android на основе контейнеров также должны
## Использование
[Установка](https://kernelsu.org/ru_RU/guide/installation.html)
## Сборка
[Как собрать?](https://kernelsu.org/ru_RU/guide/how-to-build.html)
- [Установка](https://kernelsu.org/ru_RU/guide/installation.html)
- [Как собрать?](https://kernelsu.org/ru_RU/guide/how-to-build.html)
- [официальный сайт](https://kernelsu.org/ru_RU/)
## Обсуждение
@@ -31,12 +38,12 @@ WSA и Android на основе контейнеров также должны
## Лицензия
- Файлы в директории `kernel` - [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- Все остальные части, кроме директории `kernel` - [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
- Файлы в директории `kernel` [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- Все остальные части, кроме директории `kernel` [GPL-3-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): реализация sepolicy.
- [genuine](https://github.com/brevent/genuine/): проверка подписи apk v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): некоторые навыки руткита.
- [Magisk](https://github.com/topjohnwu/Magisk): реализация sepolicy.

View File

@@ -1,4 +1,4 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | **Türkçe** | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | **Türkçe** | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU
@@ -6,17 +6,16 @@
Android cihazlar için kernel tabanlı root çözümü.
[![latest release badge](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## Özellikler
1. Kernel-tabanlı `su` ve root erişimi yönetimi.
2. Overlayfs'ye dayalı modül sistemi.
2. [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS)'ye dayalı modül sistemi.
3. [Uygulama profili](https://kernelsu.org/guide/app-profile.html): Root gücünü bir kafese kapatın.
## Uyumluluk Durumu
@@ -42,12 +41,13 @@ KernelSU'nun çevirisine veya mevcut çevirilerin iyileştirilmesine yardımcı
- Telegram: [@KernelSU](https://t.me/KernelSU)
## Güvenlik
KernelSU'daki güvenlik açıklarını bildirme hakkında bilgi için, bkz. [SECURITY.md](/SECURITY.md).
KernelSU'daki güvenlik açıklarını bildirme hakkında bilgi için, bkz [SECURITY.md](/SECURITY.md).
## Lisans
- `kernel` klasöründeki dosyalar [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) lisansı altındadır.
- `kernel` klasörü dışındaki bütün diğer bölümler [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html) lisansı altındadır.
- `kernel` klasöründeki dosyalar [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) lisansı altındadır.
- `kernel` klasörü dışındaki bütün diğer bölümler [GPL-3-veya-sonraki](https://www.gnu.org/licenses/gpl-3.0.html) lisansı altındadır.
## Krediler

View File

@@ -1,13 +1,21 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | **繁體中文** | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | **繁體中文** | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
一個基於核心的 Android 裝置 Root 解決方案
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## 功能
- 基於核心的 Su 和 Root 存取權管理。
- 基於 Overlayfs 的模組系統。
- 基於核心的 `su` 和 Root 存取權管理。
- 基於 [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) 的模組系統。
## 相容性狀態
@@ -15,15 +23,12 @@ KernelSU 官方支援 Android GKI 2.0 的裝置 (核心版本 5.10+);舊版核
WSA 和執行在容器中的 Android 也可以與 KernelSU 一同運作。
目前支援架構:`arm64-v8a``x86_64`
目前支援架構:`arm64-v8a``x86_64`
## 使用方法
[安裝教學](https://kernelsu.org/zh_TW/guide/installation.html)
## 建置
[如何建置?](https://kernelsu.org/zh_TW/guide/how-to-build.html)
- [安裝教學](https://kernelsu.org/zh_TW/guide/installation.html)
- [如何建置?](https://kernelsu.org/zh_TW/guide/how-to-build.html)
### 討論
@@ -31,12 +36,12 @@ WSA 和執行在容器中的 Android 也可以與 KernelSU 一同運作。
## 授權
- 目錄 `kernel` 下所有檔案為 [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
-`kernel` 目錄的其他部分均為 [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
- 目錄 `kernel` 下所有檔案為 [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
-`kernel` 目錄的其他部分均為 [GPL-3-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)sepolicy 實作。
- [genuine](https://github.com/brevent/genuine/)apk v2 簽章驗證。
- [Diamorphine](https://github.com/m0nad/Diamorphine):一些 rootkit 技巧。
- [Magisk](https://github.com/topjohnwu/Magisk)sepolicy 實作。

View File

@@ -1,13 +1,21 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | **Tiếng Việt** | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | **Tiếng Việt** | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
# KernelSU
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
Giải pháp root thông qua thay đổi trên Kernel hệ điều hành cho các thiết bị Android.
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## Tính năng
1. Hỗ trợ gói thực thi `su` và quản lý quyền root.
2. Hệ thống mô-đun thông qua overlayfs.
2. Hệ thống mô-đun thông qua [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
3. [App Profile](https://kernelsu.org/guide/app-profile.html): Hạn chế quyền root của ứng dụng.
## Tình trạng tương thích
@@ -16,7 +24,7 @@ KernelSU chính thức hỗ trợ các thiết bị Android với kernel GKI 2.0
WSA, ChromeOS và Android dựa trên container(container-based) cũng được hỗ trợ bởi KernelSU.
Hiên tại Giao diện nhị phân của ứng dụng (ABI) được hỗ trợ bao gồm `arm64-v8a``x86_64`
Hiên tại Giao diện nhị phân của ứng dụng (ABI) được hỗ trợ bao gồm `arm64-v8a``x86_64`.
## Sử dụng
@@ -34,12 +42,12 @@ Nếu bạn muốn hỗ trợ dịch KernelSU sang một ngôn ngữ khác hoặ
## Giấy phép
- Tất cả các file trong thư mục `kernel` dùng giấy phép [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- Tất cả các thành phần khác ngoại trừ thư mục `kernel` dùng giấy phép [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
- Tất cả các file trong thư mục `kernel` dùng giấy phép [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- Tất cả các thành phần khác ngoại trừ thư mục `kernel` dùng giấy phép [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
## Lời cảm ơn
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): ý tưởng cho KernelSU.
- [Magisk](https://github.com/topjohnwu/Magisk): công cụ root mạnh mẽ.
- [genuine](https://github.com/brevent/genuine/): phương pháp xác thực apk v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): các phương pháp ẩn của rootkit .
- [Diamorphine](https://github.com/m0nad/Diamorphine): các phương pháp ẩn của rootkit.

111
js/README.md Normal file
View File

@@ -0,0 +1,111 @@
# Library for KernelSU's module WebUI
## Install
```sh
yarn add kernelsu
```
## API
### exec
Spawns a **root** shell and runs a command within that shell, passing the `stdout` and `stderr` to a Promise when complete.
- `command` `<string>` The command to run, with space-separated arguments.
- `options` `<Object>`
- `cwd` - Current working directory of the child process
- `env` - Environment key-value pairs
```javascript
import { exec } from 'kernelsu';
const { errno, stdout, stderr } = await exec('ls -l', { cwd: '/tmp' });
if (errno === 0) {
// success
console.log(stdout);
}
```
### spawn
Spawns a new process using the given `command` in **root** shell, with command-line arguments in `args`. If omitted, `args` defaults to an empty array.
Returns a `ChildProcess`, Instances of the ChildProcess represent spawned child processes.
- `command` `<string>` The command to run.
- `args` `<string[]>` List of string arguments.
- `options` `<Object>`:
- `cwd` `<string>` - Current working directory of the child process
- `env` `<Object>` - Environment key-value pairs
Example of running `ls -lh /data`, capturing `stdout`, `stderr`, and the exit code:
```javascript
import { spawn } from 'kernelsu';
const ls = spawn('ls', ['-lh', '/data']);
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
});
ls.on('exit', (code) => {
console.log(`child process exited with code ${code}`);
});
```
#### ChildProcess
##### Event 'exit'
- `code` `<number>` The exit code if the child exited on its own.
The `'exit'` event is emitted after the child process ends. If the process exited, `code` is the final exit code of the process, otherwise null
##### Event 'error'
- `err` `<Error>` The error.
The `'error'` event is emitted whenever:
- The process could not be spawned.
- The process could not be killed.
##### `stdout`
A `Readable Stream` that represents the child process's `stdout`.
```javascript
const subprocess = spawn('ls');
subprocess.stdout.on('data', (data) => {
console.log(`Received chunk ${data}`);
});
```
#### `stderr`
A `Readable Stream` that represents the child process's `stderr`.
### fullScreen
Request the WebView enter/exit full screen.
```javascript
import { fullScreen } from 'kernelsu';
fullScreen(true);
```
### toast
Show a toast message.
```javascript
import { toast } from 'kernelsu';
toast('Hello, world!');
```

45
js/index.d.ts vendored Normal file
View File

@@ -0,0 +1,45 @@
interface ExecOptions {
cwd?: string,
env?: { [key: string]: string }
}
interface ExecResults {
errno: number,
stdout: string,
stderr: string
}
declare function exec(command: string): Promise<ExecResults>;
declare function exec(command: string, options: ExecOptions): Promise<ExecResults>;
interface SpawnOptions {
cwd?: string,
env?: { [key: string]: string }
}
interface Stdio {
on(event: 'data', callback: (data: string) => void)
}
interface ChildProcess {
stdout: Stdio,
stderr: Stdio,
on(event: 'exit', callback: (code: number) => void)
on(event: 'error', callback: (err: any) => void)
}
declare function spawn(command: string): ChildProcess;
declare function spawn(command: string, args: string[]): ChildProcess;
declare function spawn(command: string, options: SpawnOptions): ChildProcess;
declare function spawn(command: string, args: string[], options: SpawnOptions): ChildProcess;
declare function fullScreen(isFullScreen: boolean);
declare function toast(message: string);
export {
exec,
spawn,
fullScreen,
toast
}

115
js/index.js Normal file
View File

@@ -0,0 +1,115 @@
let callbackCounter = 0;
function getUniqueCallbackName(prefix) {
return `${prefix}_callback_${Date.now()}_${callbackCounter++}`;
}
export function exec(command, options) {
if (typeof options === "undefined") {
options = {};
}
return new Promise((resolve, reject) => {
// Generate a unique callback function name
const callbackFuncName = getUniqueCallbackName("exec");
// Define the success callback function
window[callbackFuncName] = (errno, stdout, stderr) => {
resolve({ errno, stdout, stderr });
cleanup(callbackFuncName);
};
function cleanup(successName) {
delete window[successName];
}
try {
ksu.exec(command, JSON.stringify(options), callbackFuncName);
} catch (error) {
reject(error);
cleanup(callbackFuncName);
}
});
}
function Stdio() {
this.listeners = {};
}
Stdio.prototype.on = function (event, listener) {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event].push(listener);
};
Stdio.prototype.emit = function (event, ...args) {
if (this.listeners[event]) {
this.listeners[event].forEach((listener) => listener(...args));
}
};
function ChildProcess() {
this.listeners = {};
this.stdin = new Stdio();
this.stdout = new Stdio();
this.stderr = new Stdio();
}
ChildProcess.prototype.on = function (event, listener) {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event].push(listener);
};
ChildProcess.prototype.emit = function (event, ...args) {
if (this.listeners[event]) {
this.listeners[event].forEach((listener) => listener(...args));
}
};
export function spawn(command, args, options) {
if (typeof args === "undefined") {
args = [];
} else if (!(args instanceof Array)) {
// allow for (command, options) signature
options = args;
}
if (typeof options === "undefined") {
options = {};
}
const child = new ChildProcess();
const childCallbackName = getUniqueCallbackName("spawn");
window[childCallbackName] = child;
function cleanup(name) {
delete window[name];
}
child.on("exit", code => {
cleanup(childCallbackName);
});
try {
ksu.spawn(
command,
JSON.stringify(args),
JSON.stringify(options),
childCallbackName
);
} catch (error) {
child.emit("error", error);
cleanup(childCallbackName);
}
return child;
}
export function fullScreen(isFullScreen) {
ksu.fullScreen(isFullScreen);
}
export function toast(message) {
ksu.toast(message);
}

26
js/package.json Normal file
View File

@@ -0,0 +1,26 @@
{
"name": "kernelsu",
"version": "1.0.6",
"description": "Library for KernelSU's module WebUI",
"main": "index.js",
"types": "index.d.ts",
"scripts": {
"test": "npm run test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/tiann/KernelSU.git"
},
"keywords": [
"su",
"kernelsu",
"module",
"webui"
],
"author": "weishu",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/tiann/KernelSU/issues"
},
"homepage": "https://github.com/tiann/KernelSU#readme"
}

14
justfile Normal file
View File

@@ -0,0 +1,14 @@
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

View File

@@ -5,13 +5,15 @@ config KSU
depends on OVERLAY_FS
default y
help
Enable kernel-level root privileges on Android System.
Enable kernel-level root privileges on Android System.
To compile as a module, choose M here: the
module will be called kernelsu.
config KSU_DEBUG
bool "KernelSU debug mode"
depends on KSU
default n
help
Enable KernelSU debug mode
Enable KernelSU debug mode.
endmenu

View File

@@ -1,19 +1,25 @@
obj-y += ksu.o
obj-y += allowlist.o
kernelsu-objs := apk_sign.o
obj-y += kernelsu.o
obj-y += module_api.o
obj-y += sucompat.o
obj-y += uid_observer.o
obj-y += manager.o
obj-y += core_hook.o
obj-y += ksud.o
obj-y += embed_ksud.o
obj-y += kernel_compat.o
kernelsu-objs := ksu.o
kernelsu-objs += allowlist.o
kernelsu-objs += apk_sign.o
kernelsu-objs += sucompat.o
kernelsu-objs += uid_observer.o
kernelsu-objs += manager.o
kernelsu-objs += core_hook.o
kernelsu-objs += ksud.o
kernelsu-objs += embed_ksud.o
kernelsu-objs += kernel_compat.o
kernelsu-objs += selinux/selinux.o
kernelsu-objs += selinux/sepolicy.o
kernelsu-objs += selinux/rules.o
ccflags-y += -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-generic/errno.h
obj-$(CONFIG_KSU) += kernelsu.o
obj-y += selinux/
# .git is a text file while the module is imported by 'git submodule add'.
ifeq ($(shell test -e $(srctree)/$(src)/../.git; echo $$?),0)
$(shell cd $(srctree)/$(src); /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin [ -f ../.git/shallow ] && git fetch --unshallow)
KSU_GIT_VERSION := $(shell cd $(srctree)/$(src); /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin git rev-list --count HEAD)
# ksu_version: major * 10000 + git version + 200 for historical reasons
$(eval KSU_VERSION=$(shell expr 10000 + $(KSU_GIT_VERSION) + 200))
@@ -24,6 +30,14 @@ $(warning "KSU_GIT_VERSION not defined! It is better to make KernelSU a git subm
ccflags-y += -DKSU_VERSION=16
endif
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
ifndef KSU_EXPECTED_SIZE
KSU_EXPECTED_SIZE := 0x033b
endif
@@ -42,5 +56,15 @@ $(info -- KernelSU Manager signature hash: $(KSU_EXPECTED_HASH))
ccflags-y += -DEXPECTED_SIZE=$(KSU_EXPECTED_SIZE)
ccflags-y += -DEXPECTED_HASH=\"$(KSU_EXPECTED_HASH)\"
ifeq ($(shell grep -q "int path_umount" $(srctree)/fs/namespace.c; echo $$?),0)
ccflags-y += -DKSU_UMOUNT
else
$(info -- Did you know you can backport path_umount to fs/namespace.c from 5.9?)
$(info -- Read: https://kernelsu.org/guide/how-to-integrate-for-non-gki.html#how-to-backport-path_umount)
endif
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
ccflags-y += -Wno-declaration-after-statement
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function
# Keep a new line here!! Because someone may append config

View File

@@ -20,8 +20,14 @@
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
#define PRCTL_SYMBOL "__arm64_sys_prctl"
#define SYS_READ_SYMBOL "__arm64_sys_read"
#define SYS_NEWFSTATAT_SYMBOL "__arm64_sys_newfstatat"
#define SYS_FACCESSAT_SYMBOL "__arm64_sys_faccessat"
#else
#define PRCTL_SYMBOL "sys_prctl"
#define SYS_READ_SYMBOL "sys_read"
#define SYS_NEWFSTATAT_SYMBOL "sys_newfstatat"
#define SYS_FACCESSAT_SYMBOL "sys_faccessat"
#endif
#elif defined(__x86_64__)
@@ -41,8 +47,14 @@
#define __PT_IP_REG ip
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
#define PRCTL_SYMBOL "__x64_sys_prctl"
#define SYS_READ_SYMBOL "__x64_sys_read"
#define SYS_NEWFSTATAT_SYMBOL "__x64_sys_newfstatat"
#define SYS_FACCESSAT_SYMBOL "__x64_sys_faccessat"
#else
#define PRCTL_SYMBOL "sys_prctl"
#define SYS_READ_SYMBOL "sys_read"
#define SYS_NEWFSTATAT_SYMBOL "sys_newfstatat"
#define SYS_FACCESSAT_SYMBOL "sys_faccessat"
#endif
#else

View File

@@ -4,12 +4,21 @@
#include "linux/err.h"
#include "linux/init.h"
#include "linux/init_task.h"
#include "linux/irqflags.h"
#include "linux/kallsyms.h"
#include "linux/kernel.h"
#include "linux/kprobes.h"
#include "linux/list.h"
#include "linux/lsm_hooks.h"
#include "linux/mm.h"
#include "linux/mm_types.h"
#include "linux/nsproxy.h"
#include "linux/path.h"
#include "linux/printk.h"
#include "linux/sched.h"
#include "linux/security.h"
#include "linux/stddef.h"
#include "linux/types.h"
#include "linux/uaccess.h"
#include "linux/uidgid.h"
#include "linux/version.h"
@@ -25,6 +34,7 @@
#include "klog.h" // IWYU pragma: keep
#include "ksu.h"
#include "ksud.h"
#include "linux/vmalloc.h"
#include "manager.h"
#include "selinux/selinux.h"
#include "uid_observer.h"
@@ -43,16 +53,11 @@ static inline bool is_allow_su()
return ksu_is_allow_uid(current_uid().val);
}
static inline bool is_isolated_uid(uid_t uid)
static inline bool is_unsupported_uid(uid_t uid)
{
#define FIRST_ISOLATED_UID 99000
#define LAST_ISOLATED_UID 99999
#define FIRST_APP_ZYGOTE_ISOLATED_UID 90000
#define LAST_APP_ZYGOTE_ISOLATED_UID 98999
#define LAST_APPLICATION_UID 19999
uid_t appid = uid % 100000;
return (appid >= FIRST_ISOLATED_UID && appid <= LAST_ISOLATED_UID) ||
(appid >= FIRST_APP_ZYGOTE_ISOLATED_UID &&
appid <= LAST_APP_ZYGOTE_ISOLATED_UID);
return appid > LAST_APPLICATION_UID;
}
static struct group_info root_groups = { .usage = ATOMIC_INIT(2) };
@@ -128,7 +133,8 @@ void escape_to_root(void)
// setup capabilities
// we need CAP_DAC_READ_SEARCH becuase `/data/adb/ksud` is not accessible for non root process
// we add it here but don't add it to cap_inhertiable, it would be dropped automaticly after exec!
u64 cap_for_ksud = profile->capabilities.effective | CAP_DAC_READ_SEARCH;
u64 cap_for_ksud =
profile->capabilities.effective | CAP_DAC_READ_SEARCH;
memcpy(&cred->cap_effective, &cap_for_ksud,
sizeof(cred->cap_effective));
memcpy(&cred->cap_inheritable, &profile->capabilities.effective,
@@ -209,8 +215,8 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
return 0;
}
// always ignore isolated app uid
if (is_isolated_uid(current_uid().val)) {
// always ignore unsupported app uid, such as isolated uid, sdk sandbox uid
if (is_unsupported_uid(current_uid().val)) {
return 0;
}
@@ -219,7 +225,9 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
return 0;
}
// pr_info("option: 0x%x, cmd: %ld\n", option, arg2);
#ifdef CONFIG_KSU_DEBUG
pr_info("option: 0x%x, cmd: %ld\n", option, arg2);
#endif
if (arg2 == CMD_BECOME_MANAGER) {
// quick check
@@ -230,8 +238,10 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
return 0;
}
if (ksu_is_manager_uid_valid()) {
#ifdef CONFIG_KSU_DEBUG
pr_info("manager already exist: %d\n",
ksu_get_manager_uid());
#endif
return 0;
}
@@ -243,7 +253,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
#ifdef CONFIG_KSU_DEBUG
pr_err("become_manager: copy param err\n");
#endif
return 0;
goto block;
}
// for user 0, it is /data/data
@@ -261,7 +271,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
if (startswith(param, (char *)prefix) != 0) {
pr_info("become_manager: invalid param: %s\n", param);
return 0;
goto block;
}
// stat the param, app must have permission to do this
@@ -269,12 +279,13 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
struct path path;
if (kern_path(param, LOOKUP_DIRECTORY, &path)) {
pr_err("become_manager: kern_path err\n");
return 0;
goto block;
}
if (path.dentry->d_inode->i_uid.val != current_uid().val) {
uid_t inode_uid = path.dentry->d_inode->i_uid.val;
path_put(&path);
if (inode_uid != current_uid().val) {
pr_err("become_manager: path uid != current uid\n");
path_put(&path);
return 0;
goto block;
}
char *pkg = param + strlen(prefix);
pr_info("become_manager: param pkg: %s\n", pkg);
@@ -284,8 +295,10 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("become_manager: prctl reply error\n");
}
return 0;
}
path_put(&path);
block:
last_failed_uid = current_uid().val;
return 0;
}
@@ -307,6 +320,15 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
if (copy_to_user(arg3, &version, sizeof(version))) {
pr_err("prctl reply error, cmd: %lu\n", arg2);
}
#ifdef MODULE
u32 is_lkm = 0x1;
#else
u32 is_lkm = 0x0;
#endif
if (arg4 &&
copy_to_user(arg4, &is_lkm, sizeof(is_lkm))) {
pr_err("prctl reply error, cmd: %lu\n", arg2);
}
}
return 0;
}
@@ -496,7 +518,7 @@ static bool should_umount(struct path *path)
static void ksu_umount_mnt(struct path *path, int flags)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) || defined(KSU_UMOUNT)
int err = path_umount(path, flags);
if (err) {
pr_info("umount %s failed: %d\n", path->dentry->d_iname, err);
@@ -546,7 +568,7 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
return 0;
}
if (!is_appuid(new_uid) || is_isolated_uid(new_uid.val)) {
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;
}
@@ -569,11 +591,13 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
// when we umount for such process, that is a disaster!
bool is_zygote_child = is_zygote(old->security);
if (!is_zygote_child) {
pr_info("handle umount ignore non zygote child: %d\n", current->pid);
pr_info("handle umount ignore non zygote child: %d\n",
current->pid);
return 0;
}
// umount the target mnt
pr_info("handle umount for uid: %d, pid: %d\n", new_uid.val, current->pid);
pr_info("handle umount for uid: %d, pid: %d\n", new_uid.val,
current->pid);
// fixme: use `collect_mounts` and `iterate_mount` to iterate all mountpoint and
// filter the mountpoint whose target is `/data/adb`
@@ -697,6 +721,7 @@ static int ksu_task_fix_setuid(struct cred *new, const struct cred *old,
return ksu_handle_setuid(new, old);
}
#ifndef MODULE
static struct security_hook_list ksu_hooks[] = {
LSM_HOOK_INIT(task_prctl, ksu_task_prctl),
LSM_HOOK_INIT(inode_rename, ksu_inode_rename),
@@ -716,21 +741,180 @@ void __init ksu_lsm_hook_init(void)
#endif
}
#else
static int override_security_head(void *head, const void *new_head, size_t len)
{
unsigned long base = (unsigned long)head & PAGE_MASK;
unsigned long offset = offset_in_page(head);
// this is impossible for our case because the page alignment
// but be careful for other cases!
BUG_ON(offset + len > PAGE_SIZE);
struct page *page = phys_to_page(__pa(base));
if (!page) {
return -EFAULT;
}
void *addr = vmap(&page, 1, VM_MAP, PAGE_KERNEL);
if (!addr) {
return -ENOMEM;
}
local_irq_disable();
memcpy(addr + offset, new_head, len);
local_irq_enable();
vunmap(addr);
return 0;
}
static void free_security_hook_list(struct hlist_head *head)
{
struct hlist_node *temp;
struct security_hook_list *entry;
if (!head)
return;
hlist_for_each_entry_safe (entry, temp, head, list) {
hlist_del(&entry->list);
kfree(entry);
}
kfree(head);
}
struct hlist_head *copy_security_hlist(struct hlist_head *orig)
{
struct hlist_head *new_head = kmalloc(sizeof(*new_head), GFP_KERNEL);
if (!new_head)
return NULL;
INIT_HLIST_HEAD(new_head);
struct security_hook_list *entry;
struct security_hook_list *new_entry;
hlist_for_each_entry (entry, orig, list) {
new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
if (!new_entry) {
free_security_hook_list(new_head);
return NULL;
}
*new_entry = *entry;
hlist_add_tail_rcu(&new_entry->list, new_head);
}
return new_head;
}
#define LSM_SEARCH_MAX 180 // This should be enough to iterate
static void *find_head_addr(void *security_ptr, int *index)
{
if (!security_ptr) {
return NULL;
}
struct hlist_head *head_start =
(struct hlist_head *)&security_hook_heads;
for (int i = 0; i < LSM_SEARCH_MAX; i++) {
struct hlist_head *head = head_start + i;
struct security_hook_list *pos;
hlist_for_each_entry (pos, head, list) {
if (pos->hook.capget == security_ptr) {
if (index) {
*index = i;
}
return head;
}
}
}
return NULL;
}
#define GET_SYMBOL_ADDR(sym) \
({ \
void *addr = kallsyms_lookup_name(#sym ".cfi_jt"); \
if (!addr) { \
addr = kallsyms_lookup_name(#sym); \
} \
addr; \
})
#define KSU_LSM_HOOK_HACK_INIT(head_ptr, name, func) \
do { \
static struct security_hook_list hook = { \
.hook = { .name = func } \
}; \
hook.head = head_ptr; \
hook.lsm = "ksu"; \
struct hlist_head *new_head = copy_security_hlist(hook.head); \
if (!new_head) { \
pr_err("Failed to copy security list: %s\n", #name); \
break; \
} \
hlist_add_tail_rcu(&hook.list, new_head); \
if (override_security_head(hook.head, new_head, \
sizeof(*new_head))) { \
free_security_hook_list(new_head); \
pr_err("Failed to hack lsm for: %s\n", #name); \
} \
} while (0)
void __init ksu_lsm_hook_init(void)
{
void *cap_prctl = GET_SYMBOL_ADDR(cap_task_prctl);
void *prctl_head = find_head_addr(cap_prctl, NULL);
if (prctl_head) {
if (prctl_head != &security_hook_heads.task_prctl) {
pr_warn("prctl's address has shifted!\n");
}
KSU_LSM_HOOK_HACK_INIT(prctl_head, task_prctl, ksu_task_prctl);
} else {
pr_warn("Failed to find task_prctl!\n");
}
int inode_killpriv_index = -1;
void *cap_killpriv = GET_SYMBOL_ADDR(cap_inode_killpriv);
find_head_addr(cap_killpriv, &inode_killpriv_index);
if (inode_killpriv_index < 0) {
pr_warn("Failed to find inode_rename, use kprobe instead!\n");
register_kprobe(&renameat_kp);
} else {
int inode_rename_index = inode_killpriv_index +
&security_hook_heads.inode_rename -
&security_hook_heads.inode_killpriv;
struct hlist_head *head_start =
(struct hlist_head *)&security_hook_heads;
void *inode_rename_head = head_start + inode_rename_index;
if (inode_rename_head != &security_hook_heads.inode_rename) {
pr_warn("inode_rename's address has shifted!\n");
}
KSU_LSM_HOOK_HACK_INIT(inode_rename_head, inode_rename,
ksu_inode_rename);
}
void *cap_setuid = GET_SYMBOL_ADDR(cap_task_fix_setuid);
void *setuid_head = find_head_addr(cap_setuid, NULL);
if (setuid_head) {
if (setuid_head != &security_hook_heads.task_fix_setuid) {
pr_warn("setuid's address has shifted!\n");
}
KSU_LSM_HOOK_HACK_INIT(setuid_head, task_fix_setuid,
ksu_task_fix_setuid);
} else {
pr_warn("Failed to find task_fix_setuid!\n");
}
smp_mb();
}
#endif
void __init ksu_core_init(void)
{
#ifndef MODULE
pr_info("ksu_lsm_hook_init\n");
ksu_lsm_hook_init();
#else
pr_info("ksu_kprobe_init\n");
ksu_kprobe_init();
#endif
}
void ksu_core_exit(void)
{
#ifndef MODULE
pr_info("ksu_kprobe_exit\n");
ksu_kprobe_exit();
#endif
}

View File

@@ -3,13 +3,10 @@
#include "linux/nsproxy.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
#include "linux/sched/task.h"
#include "linux/uaccess.h"
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
#include "linux/uaccess.h"
#include "linux/sched.h"
#else
#include "linux/sched.h"
#endif
#include "linux/uaccess.h"
#include "klog.h" // IWYU pragma: keep
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)

View File

@@ -1,4 +1,6 @@
#include "linux/export.h"
#include "linux/fs.h"
#include "linux/kobject.h"
#include "linux/module.h"
#include "linux/workqueue.h"
@@ -60,6 +62,11 @@ int __init kernelsu_init(void)
pr_alert("KPROBES is disabled, KernelSU may not work, please check https://kernelsu.org/guide/how-to-integrate-for-non-gki.html");
#endif
#ifdef MODULE
#ifndef CONFIG_KSU_DEBUG
kobject_del(&THIS_MODULE->mkobj.kobj);
#endif
#endif
return 0;
}

View File

@@ -1,9 +1,19 @@
#include "asm/current.h"
#include "linux/compat.h"
#include "linux/cred.h"
#include "linux/dcache.h"
#include "linux/err.h"
#include "linux/file.h"
#include "linux/fs.h"
#include "linux/version.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
#include "linux/input-event-codes.h"
#else
#include "uapi/linux/input.h"
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)
#include "linux/aio.h"
#endif
#include "linux/kprobes.h"
#include "linux/printk.h"
#include "linux/types.h"
@@ -376,6 +386,17 @@ int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
return 0;
}
int ksu_handle_sys_read(unsigned int fd, char __user **buf_ptr, size_t *count_ptr)
{
struct file *file = fget(fd);
if (!file) {
return 0;
}
int result = ksu_handle_vfs_read(&file, buf_ptr, count_ptr, NULL);
fput(file);
return result;
}
static unsigned int volumedown_pressed_count = 0;
static bool is_volumedown_enough(unsigned int count)
@@ -451,7 +472,8 @@ static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
return ksu_handle_execveat_ksud(fd, filename_ptr, &argv, NULL, NULL);
}
static int read_handler_pre(struct kprobe *p, struct pt_regs *regs)
// remove this later!
__maybe_unused static int vfs_read_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
struct file **file_ptr = (struct file **)&PT_REGS_PARM1(regs);
char __user **buf_ptr = (char **)&PT_REGS_PARM2(regs);
@@ -461,6 +483,20 @@ static int read_handler_pre(struct kprobe *p, struct pt_regs *regs)
return ksu_handle_vfs_read(file_ptr, buf_ptr, count_ptr, pos_ptr);
}
static int sys_read_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
struct pt_regs *real_regs = (struct pt_regs *)PT_REGS_PARM1(regs);
#else
struct pt_regs *real_regs = regs;
#endif
unsigned int fd = PT_REGS_PARM1(real_regs);
char __user **buf_ptr = (char __user **)&PT_REGS_PARM2(real_regs);
size_t count_ptr = (size_t *) &PT_REGS_PARM3(real_regs);
return ksu_handle_sys_read(fd, buf_ptr, count_ptr);
}
static int input_handle_event_handler_pre(struct kprobe *p,
struct pt_regs *regs)
{
@@ -481,10 +517,17 @@ static struct kprobe execve_kp = {
.pre_handler = execve_handler_pre,
};
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
static struct kprobe vfs_read_kp = {
.symbol_name = SYS_READ_SYMBOL,
.pre_handler = sys_read_handler_pre,
};
#else
static struct kprobe vfs_read_kp = {
.symbol_name = "vfs_read",
.pre_handler = read_handler_pre,
.pre_handler = vfs_read_handler_pre,
};
#endif
static struct kprobe input_handle_event_kp = {
.symbol_name = "input_handle_event",

View File

@@ -1,33 +0,0 @@
#include "linux/kallsyms.h"
#define RE_EXPORT_SYMBOL1(ret, func, t1, v1) \
ret ksu_##func(t1 v1) \
{ \
return func(v1); \
} \
EXPORT_SYMBOL(ksu_##func);
#define RE_EXPORT_SYMBOL2(ret, func, t1, v1, t2, v2) \
ret ksu_##func(t1 v1, t2 v2) \
{ \
return func(v1, v2); \
} \
EXPORT_SYMBOL(ksu_##func);
RE_EXPORT_SYMBOL1(unsigned long, kallsyms_lookup_name, const char *, name)
// RE_EXPORT_SYMBOL2(int, register_kprobe, struct kprobe *, p)
// RE_EXPORT_SYMBOL2(void, unregister_kprobe, struct kprobe *, p)
// RE_EXPORT_SYMBOL2(int, register_kprobe, struct kprobe *, p)
// RE_EXPORT_SYMBOL2(void, unregister_kprobe, struct kprobe *, p)
// int ksu_register_kprobe(struct kprobe *p);
// void ksu_unregister_kprobe(struct kprobe *p);
// int ksu_register_kprobes(struct kprobe **kps, int num);
// void ksu_unregister_kprobes(struct kprobe **kps, int num);
// int ksu_register_kretprobe(struct kretprobe *rp);
// void unregister_kretprobe(struct kretprobe *rp);
// int register_kretprobes(struct kretprobe **rps, int num);
// void unregister_kretprobes(struct kretprobe **rps, int num);

View File

@@ -131,6 +131,10 @@ void apply_kernelsu_rules()
ksu_allow(db, "system_server", "untrusted_app_all_devpts", "chr_file",
"write");
// 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();
}

View File

@@ -15,7 +15,9 @@
* From ss/ebitmap.h
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) && \
LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \
LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) && \
LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
#ifdef HISI_SELINUX_EBITMAP_RO
#define CONFIG_IS_HW_HISI
#endif
@@ -619,6 +621,22 @@ static bool add_genfscon(struct policydb *db, const char *fs_name,
return false;
}
static void *ksu_realloc(void *old, size_t new_size, size_t old_size)
{
// we can't use krealloc, because it may be read-only
void *new = kzalloc(new_size, GFP_ATOMIC);
if (!new) {
return NULL;
}
if (old_size) {
memcpy(new, old, old_size);
}
// we can't use kfree, because it may be read-only
// there maybe some leaks, maybe we can check ptr_write, but it's not a big deal
// kfree(old);
return new;
}
static bool add_type(struct policydb *db, const char *type_name, bool attr)
{
#ifdef KSU_SUPPORT_ADD_TYPE
@@ -652,29 +670,30 @@ static bool add_type(struct policydb *db, const char *type_name, bool attr)
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
size_t new_size = sizeof(struct ebitmap) * db->p_types.nprim;
struct ebitmap *new_type_attr_map_array =
(krealloc(db->type_attr_map_array, new_size, GFP_ATOMIC));
struct type_datum **new_type_val_to_struct =
krealloc(db->type_val_to_struct,
sizeof(*db->type_val_to_struct) * db->p_types.nprim,
GFP_ATOMIC);
ksu_realloc(db->type_attr_map_array,
value * sizeof(struct ebitmap),
(value - 1) * sizeof(struct ebitmap));
if (!new_type_attr_map_array) {
pr_err("add_type: alloc type_attr_map_array failed\n");
return false;
}
struct type_datum **new_type_val_to_struct =
ksu_realloc(db->type_val_to_struct,
sizeof(*db->type_val_to_struct) * value,
sizeof(*db->type_val_to_struct) * (value - 1));
if (!new_type_val_to_struct) {
pr_err("add_type: alloc type_val_to_struct failed\n");
return false;
}
char **new_val_to_name_types =
krealloc(db->sym_val_to_name[SYM_TYPES],
sizeof(char *) * db->symtab[SYM_TYPES].nprim,
GFP_KERNEL);
ksu_realloc(db->sym_val_to_name[SYM_TYPES],
sizeof(char *) * value,
sizeof(char *) * (value - 1));
if (!new_val_to_name_types) {
pr_err("add_type: alloc val_to_name failed\n");
return false;

View File

@@ -44,7 +44,7 @@ echo '[+] Add kernel su driver to Makefile'
DRIVER_MAKEFILE=$DRIVER_DIR/Makefile
DRIVER_KCONFIG=$DRIVER_DIR/Kconfig
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "obj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE"
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 '[+] Done.'
echo '[+] Done.'

View File

@@ -40,7 +40,7 @@ static char __user *sh_user_path(void)
}
int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
int *flags)
int * __unused_flags)
{
const char su[] = SU_PATH;
@@ -75,7 +75,8 @@ int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags)
char path[sizeof(su) + 1];
memset(path, 0, sizeof(path));
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)
// 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
// https://elixir.bootlin.com/linux/v5.18/source/fs/stat.c#L216
const char sh[] = SH_PATH;
@@ -131,7 +132,7 @@ int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
#ifdef CONFIG_KPROBES
static int faccessat_handler_pre(struct kprobe *p, struct pt_regs *regs)
__maybe_unused static int faccessat_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
int *dfd = (int *)PT_REGS_PARM1(regs);
const char __user **filename_user = (const char **)&PT_REGS_PARM2(regs);
@@ -142,7 +143,21 @@ static int faccessat_handler_pre(struct kprobe *p, struct pt_regs *regs)
return ksu_handle_faccessat(dfd, filename_user, mode, flags);
}
static int newfstatat_handler_pre(struct kprobe *p, struct pt_regs *regs)
static int sys_faccessat_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
struct pt_regs *real_regs = (struct pt_regs *)PT_REGS_PARM1(regs);
#else
struct pt_regs *real_regs = regs;
#endif
int *dfd = (int *)PT_REGS_PARM1(real_regs);
const char __user **filename_user = (const char **)&PT_REGS_PARM2(real_regs);
int *mode = (int *)&PT_REGS_PARM3(real_regs);
return ksu_handle_faccessat(dfd, filename_user, mode, NULL);
}
__maybe_unused static int newfstatat_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
int *dfd = (int *)&PT_REGS_PARM1(regs);
const char __user **filename_user = (const char **)&PT_REGS_PARM2(regs);
@@ -157,6 +172,20 @@ static int newfstatat_handler_pre(struct kprobe *p, struct pt_regs *regs)
return ksu_handle_stat(dfd, filename_user, flags);
}
static int sys_newfstatat_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
struct pt_regs *real_regs = (struct pt_regs *)PT_REGS_PARM1(regs);
#else
struct pt_regs *real_regs = regs;
#endif
int *dfd = (int *)&PT_REGS_PARM1(real_regs);
const char __user **filename_user = (const char **)&PT_REGS_PARM2(real_regs);
int *flags = (int *)&PT_REGS_SYSCALL_PARM4(real_regs);
return ksu_handle_stat(dfd, filename_user, flags);
}
// https://elixir.bootlin.com/linux/v5.10.158/source/fs/exec.c#L1864
static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
@@ -167,6 +196,12 @@ static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
return ksu_handle_execveat_sucompat(fd, filename_ptr, NULL, NULL, NULL);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
static struct kprobe faccessat_kp = {
.symbol_name = SYS_FACCESSAT_SYMBOL,
.pre_handler = sys_faccessat_handler_pre,
};
#else
static struct kprobe faccessat_kp = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
.symbol_name = "do_faccessat",
@@ -175,7 +210,14 @@ static struct kprobe faccessat_kp = {
#endif
.pre_handler = faccessat_handler_pre,
};
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
static struct kprobe newfstatat_kp = {
.symbol_name = SYS_NEWFSTATAT_SYMBOL,
.pre_handler = sys_newfstatat_handler_pre,
};
#else
static struct kprobe newfstatat_kp = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
.symbol_name = "vfs_statx",
@@ -184,6 +226,7 @@ static struct kprobe newfstatat_kp = {
#endif
.pre_handler = newfstatat_handler_pre,
};
#endif
static struct kprobe execve_kp = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)

View File

@@ -40,7 +40,7 @@ android {
}
composeOptions {
kotlinCompilerExtensionVersion = "1.4.3"
kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get()
}
packaging {
@@ -93,12 +93,14 @@ dependencies {
implementation(libs.com.google.accompanist.drawablepainter)
implementation(libs.com.google.accompanist.navigation.animation)
implementation(libs.com.google.accompanist.systemuicontroller)
implementation(libs.com.google.accompanist.webview)
implementation(libs.compose.destinations.animations.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)
@@ -113,4 +115,5 @@ dependencies {
implementation(libs.sheet.compose.dialogs.input)
implementation(libs.markdown)
implementation(libs.androidx.webkit)
}

View File

@@ -13,6 +13,7 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/Theme.KernelSU"
tools:targetApi="33">
<activity

View File

@@ -46,6 +46,12 @@ Java_me_weishu_kernelsu_Natives_isSafeMode(JNIEnv *env, jclass clazz) {
return is_safe_mode();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_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");

View File

@@ -47,10 +47,14 @@ bool become_manager(const char* 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;
if (ksuctl(CMD_GET_VERSION, &version, nullptr)) {
return version;
int32_t lkm = 0;
ksuctl(CMD_GET_VERSION, &version, &lkm);
if (!is_lkm && lkm != 0) {
is_lkm = true;
}
return version;
}
@@ -63,6 +67,11 @@ 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;

View File

@@ -17,6 +17,8 @@ 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.

View File

@@ -5,6 +5,7 @@ import coil.Coil
import coil.ImageLoader
import me.zhanghai.android.appiconloader.coil.AppIconFetcher
import me.zhanghai.android.appiconloader.coil.AppIconKeyer
import java.io.File
lateinit var ksuApp: KernelSUApplication
@@ -24,6 +25,11 @@ class KernelSUApplication : Application() {
}
.build()
)
val webroot = File(dataDir, "webroot")
if (!webroot.exists()) {
webroot.mkdir()
}
}

View File

@@ -37,6 +37,23 @@ fun parseKernelVersion(version: String): KernelVersion {
}
}
fun parseKMI(input: String): String? {
val regex = Regex("(.* )?(\\d+\\.\\d+)(\\S+)?(android\\d+)(.*)")
val result = regex.find(input)
return result?.let {
val androidVersion = it.groups[4]?.value ?: ""
val kernelVersion = it.groups[2]?.value ?: ""
"$androidVersion-$kernelVersion"
}
}
fun getKMI(): String? {
Os.uname().release.let {
return parseKMI(it)
}
}
fun getKernelVersion(): KernelVersion {
Os.uname().release.let {
return parseKernelVersion(it)

View File

@@ -18,6 +18,9 @@ object Natives {
// 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
const val KERNEL_SU_DOMAIN = "u:r:su:s0"
const val ROOT_UID = 0
@@ -39,6 +42,9 @@ object Natives {
val isSafeMode: Boolean
external get
val isLkmMode: Boolean
external get
external fun uidShouldUmount(uid: Int): Boolean
/**

View File

@@ -5,13 +5,7 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
@@ -20,18 +14,18 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import androidx.navigation.compose.currentBackStackEntryAsState
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
import com.ramcosta.composedestinations.DestinationsNavHost
import com.ramcosta.composedestinations.navigation.popBackStack
import com.ramcosta.composedestinations.utils.isRouteOnBackStackAsState
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.ksuApp
import me.weishu.kernelsu.ui.component.rememberDialogHostState
import me.weishu.kernelsu.ui.screen.BottomBarDestination
import me.weishu.kernelsu.ui.screen.NavGraphs
import me.weishu.kernelsu.ui.theme.KernelSUTheme
import me.weishu.kernelsu.ui.util.LocalDialogHost
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.rootAvailable
class MainActivity : ComponentActivity() {
@@ -43,13 +37,15 @@ class MainActivity : ComponentActivity() {
KernelSUTheme {
val navController = rememberAnimatedNavController()
val snackbarHostState = remember { SnackbarHostState() }
val navBackStackEntry by navController.currentBackStackEntryAsState()
val route = navBackStackEntry?.destination?.route
val showBottomBar = route == null || !route.startsWith("web_screen")
Scaffold(
bottomBar = { BottomBar(navController) },
bottomBar = { if (showBottomBar) BottomBar(navController) },
snackbarHost = { SnackbarHost(snackbarHostState) }
) { innerPadding ->
CompositionLocalProvider(
LocalSnackbarHost provides snackbarHostState,
LocalDialogHost provides rememberDialogHostState(),
) {
DestinationsNavHost(
modifier = Modifier.padding(innerPadding),
@@ -66,7 +62,7 @@ class MainActivity : ComponentActivity() {
@Composable
private fun BottomBar(navController: NavHostController) {
val isManager = Natives.becomeManager(ksuApp.packageName)
val fullFeatured = isManager && !Natives.requireNewKernel()
val fullFeatured = isManager && !Natives.requireNewKernel() && rootAvailable()
NavigationBar(tonalElevation = 8.dp) {
BottomBarDestination.values().forEach { destination ->
if (!fullFeatured && destination.rootRequired) return@forEach

View File

@@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
@@ -52,11 +53,9 @@ fun AboutCard() {
}
@Composable
fun AboutDialog(showAboutDialog: MutableState<Boolean>) {
if (showAboutDialog.value) {
Dialog(onDismissRequest = { showAboutDialog.value = false }) {
AboutCard()
}
fun AboutDialog(dismiss: () -> Unit) {
Dialog(onDismissRequest = { dismiss() }) {
AboutCard()
}
}

View File

@@ -1,8 +1,10 @@
package me.weishu.kernelsu.ui.component
import android.graphics.text.LineBreaker
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
@@ -10,14 +12,10 @@ 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.AlertDialog
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
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
@@ -28,48 +26,48 @@ 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.CancellableContinuation
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import me.weishu.kernelsu.ui.util.LocalDialogHost
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
interface DialogVisuals
private const val TAG = "DialogComponent"
interface LoadingDialogVisuals : DialogVisuals
interface PromptDialogVisuals : DialogVisuals {
interface ConfirmDialogVisuals : Parcelable {
val title: String
val content: String
}
interface ConfirmDialogVisuals : PromptDialogVisuals {
val isMarkdown: Boolean
val confirm: String?
val dismiss: String?
val isMarkdown: Boolean
}
sealed interface DialogData {
val visuals: DialogVisuals
@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 LoadingDialogData : DialogData {
override val visuals: LoadingDialogVisuals
fun dismiss()
interface DialogHandle {
val isShown: Boolean
val dialogType: String
fun show()
fun hide()
}
interface PromptDialogData : DialogData {
override val visuals: PromptDialogVisuals
fun dismiss()
}
interface ConfirmDialogData : PromptDialogData {
override val visuals: ConfirmDialogVisuals
fun confirm()
interface LoadingDialogHandle : DialogHandle {
suspend fun <R> withLoading(block: suspend () -> R): R
fun showLoading()
}
sealed interface ConfirmResult {
@@ -77,143 +75,313 @@ sealed interface ConfirmResult {
object Canceled : ConfirmResult
}
class DialogHostState {
interface ConfirmDialogHandle : DialogHandle {
val visuals: ConfirmDialogVisuals
private object LoadingDialogVisualsImpl : LoadingDialogVisuals
private data class PromptDialogVisualsImpl(
override val title: String, override val content: String
) : PromptDialogVisuals
private data class ConfirmDialogVisualsImpl(
override val title: String,
override val content: String,
override val confirm: String?,
override val dismiss: String?,
override val isMarkdown: Boolean,
) : ConfirmDialogVisuals
private data class LoadingDialogDataImpl(
override val visuals: LoadingDialogVisuals,
private val continuation: CancellableContinuation<Unit>,
) : LoadingDialogData {
override fun dismiss() {
if (continuation.isActive) continuation.resume(Unit)
}
}
private data class PromptDialogDataImpl(
override val visuals: PromptDialogVisuals,
private val continuation: CancellableContinuation<Unit>,
) : PromptDialogData {
override fun dismiss() {
if (continuation.isActive) continuation.resume(Unit)
}
}
private data class ConfirmDialogDataImpl(
override val visuals: ConfirmDialogVisuals,
private val continuation: CancellableContinuation<ConfirmResult>
) : ConfirmDialogData {
override fun confirm() {
if (continuation.isActive) continuation.resume(ConfirmResult.Confirmed)
}
override fun dismiss() {
if (continuation.isActive) continuation.resume(ConfirmResult.Canceled)
}
}
private val mutex = Mutex()
var currentDialogData by mutableStateOf<DialogData?>(null)
private set
suspend fun showLoading() {
try {
mutex.withLock {
suspendCancellableCoroutine { continuation ->
currentDialogData = LoadingDialogDataImpl(
visuals = LoadingDialogVisualsImpl, continuation = continuation
)
}
}
} finally {
currentDialogData = null
}
}
suspend fun <R> withLoading(block: suspend () -> R) = coroutineScope {
val showLoading = launch {
showLoading()
}
val result = block()
showLoading.cancel()
result
}
suspend fun showPrompt(title: String, content: String) {
try {
mutex.withLock {
suspendCancellableCoroutine { continuation ->
currentDialogData = PromptDialogDataImpl(
visuals = PromptDialogVisualsImpl(title, content),
continuation = continuation
)
}
}
} finally {
currentDialogData = null
}
}
suspend fun showConfirm(
fun showConfirm(
title: String,
content: String,
markdown: Boolean = false,
confirm: String? = null,
dismiss: String? = null
): ConfirmResult = mutex.withLock {
try {
return@withLock suspendCancellableCoroutine { continuation ->
currentDialogData = ConfirmDialogDataImpl(
visuals = ConfirmDialogVisualsImpl(title, content, confirm, dismiss, markdown),
continuation = continuation
)
)
suspend fun awaitConfirm(
title: String,
content: String,
markdown: Boolean = false,
confirm: String? = null,
dismiss: String? = null
): ConfirmResult
}
private abstract class DialogHandleBase(
protected val visible: MutableState<Boolean>,
protected 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()
}
} finally {
currentDialogData = null
}
}
}
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 rememberDialogHostState(): DialogHostState {
fun rememberLoadingDialog(): LoadingDialogHandle {
val visible = remember {
mutableStateOf(false)
}
val coroutineScope = rememberCoroutineScope()
if (visible.value) {
LoadingDialog()
}
return remember {
DialogHostState()
}
}
private inline fun <reified T : DialogData> DialogData?.tryInto(): T? {
return when (this) {
is T -> this
else -> null
LoadingDialogHandleImpl(visible, coroutineScope)
}
}
@Composable
fun LoadingDialog(
state: DialogHostState = LocalDialogHost.current,
) {
state.currentDialogData.tryInto<LoadingDialogData>() ?: return
val dialogProperties = remember {
DialogProperties(dismissOnClickOutside = false, dismissOnBackPress = false)
private fun rememberConfirmDialog(visuals: ConfirmDialogVisuals, callback: ConfirmCallback): ConfirmDialogHandle {
val visible = rememberSaveable {
mutableStateOf(false)
}
Dialog(onDismissRequest = {}, properties = dialogProperties) {
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)
) {
@@ -227,41 +395,10 @@ fun LoadingDialog(
}
@Composable
fun PromptDialog(
state: DialogHostState = LocalDialogHost.current,
) {
val promptDialogData = state.currentDialogData.tryInto<PromptDialogData>() ?: return
val visuals = promptDialogData.visuals
private fun ConfirmDialog(visuals: ConfirmDialogVisuals, confirm: () -> Unit, dismiss: () -> Unit) {
AlertDialog(
onDismissRequest = {
promptDialogData.dismiss()
},
title = {
Text(text = visuals.title)
},
text = {
Text(text = visuals.content)
},
confirmButton = {
TextButton(onClick = { promptDialogData.dismiss() }) {
Text(text = stringResource(id = android.R.string.ok))
}
},
dismissButton = null,
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ConfirmDialog(state: DialogHostState = LocalDialogHost.current) {
val confirmDialogData = state.currentDialogData.tryInto<ConfirmDialogData>() ?: return
val visuals = confirmDialogData.visuals
AlertDialog(
onDismissRequest = {
confirmDialogData.dismiss()
dismiss()
},
title = {
Text(text = visuals.title)
@@ -274,17 +411,18 @@ fun ConfirmDialog(state: DialogHostState = LocalDialogHost.current) {
}
},
confirmButton = {
TextButton(onClick = { confirmDialogData.confirm() }) {
TextButton(onClick = confirm) {
Text(text = visuals.confirm ?: stringResource(id = android.R.string.ok))
}
},
dismissButton = {
TextButton(onClick = { confirmDialogData.dismiss() }) {
TextButton(onClick = dismiss) {
Text(text = visuals.dismiss ?: stringResource(id = android.R.string.cancel))
}
},
)
}
@Composable
private fun MarkdownContent(content: String) {
val contentColor = LocalContentColor.current
@@ -307,5 +445,6 @@ private fun MarkdownContent(content: String) {
update = {
Markwon.create(it.context).setMarkdown(it, content)
it.setTextColor(contentColor.toArgb())
})
}
)
}

View File

@@ -28,6 +28,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
@@ -53,6 +54,7 @@ import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.profile.Capabilities
import me.weishu.kernelsu.profile.Groups
import me.weishu.kernelsu.ui.component.rememberCustomDialog
import me.weishu.kernelsu.ui.util.isSepolicyValid
@OptIn(ExperimentalMaterial3Api::class)
@@ -187,10 +189,7 @@ fun RootProfileConfig(
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun GroupsPanel(selected: List<Groups>, closeSelection: (selection: Set<Groups>) -> Unit) {
var showDialog by remember { mutableStateOf(false) }
if (showDialog) {
val selectGroupsDialog = rememberCustomDialog { dismiss: () -> Unit ->
val groups = Groups.values().sortedWith(
compareBy<Groups> { if (selected.contains(it)) 0 else 1 }
.then(compareBy {
@@ -217,7 +216,7 @@ fun GroupsPanel(selected: List<Groups>, closeSelection: (selection: Set<Groups>)
state = rememberUseCaseState(visible = true, onFinishedRequest = {
closeSelection(selection)
}, onCloseRequest = {
showDialog = false
dismiss()
}),
header = Header.Default(
title = stringResource(R.string.profile_groups),
@@ -241,7 +240,7 @@ fun GroupsPanel(selected: List<Groups>, closeSelection: (selection: Set<Groups>)
.fillMaxWidth()
.padding(16.dp)
.clickable {
showDialog = true
selectGroupsDialog.show()
}) {
Column(modifier = Modifier.padding(16.dp)) {
@@ -265,10 +264,7 @@ fun CapsPanel(
selected: Collection<Capabilities>,
closeSelection: (selection: Set<Capabilities>) -> Unit
) {
var showDialog by remember { mutableStateOf(false) }
if (showDialog) {
val selectCapabilitiesDialog = rememberCustomDialog { dismiss ->
val caps = Capabilities.values().sortedWith(
compareBy<Capabilities> { if (selected.contains(it)) 0 else 1 }
.then(compareBy { it.name })
@@ -286,7 +282,7 @@ fun CapsPanel(
state = rememberUseCaseState(visible = true, onFinishedRequest = {
closeSelection(selection)
}, onCloseRequest = {
showDialog = false
dismiss()
}),
header = Header.Default(
title = stringResource(R.string.profile_capabilities),
@@ -309,7 +305,7 @@ fun CapsPanel(
.fillMaxWidth()
.padding(16.dp)
.clickable {
showDialog = true
selectCapabilitiesDialog.show()
}) {
Column(modifier = Modifier.padding(16.dp)) {
@@ -377,8 +373,7 @@ private fun SELinuxPanel(
profile: Natives.Profile,
onSELinuxChange: (domain: String, rules: String) -> Unit
) {
var showDialog by remember { mutableStateOf(false) }
if (showDialog) {
val editSELinuxDialog = rememberCustomDialog { dismiss ->
var domain by remember { mutableStateOf(profile.context) }
var rules by remember { mutableStateOf(profile.rules) }
@@ -430,7 +425,7 @@ private fun SELinuxPanel(
onSELinuxChange(domain, rules)
},
onCloseRequest = {
showDialog = false
dismiss()
}),
header = Header.Default(
title = stringResource(R.string.profile_selinux_context),
@@ -449,7 +444,7 @@ private fun SELinuxPanel(
modifier = Modifier
.fillMaxWidth()
.clickable {
showDialog = true
editSELinuxDialog.show()
},
enabled = false,
colors = TextFieldDefaults.outlinedTextFieldColors(

View File

@@ -183,7 +183,7 @@ private fun AppProfileInner(
} else {
Mode.Custom
}
var mode by remember {
var mode by rememberSaveable {
mutableStateOf(initialMode)
}
ProfileBox(mode, true) {

View File

@@ -0,0 +1,192 @@
package me.weishu.kernelsu.ui.screen
import android.net.Uri
import android.os.Environment
import android.os.Parcelable
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.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.Save
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.key
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.parcelize.Parcelize
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.KeyEventBlocker
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.installBoot
import me.weishu.kernelsu.ui.util.installModule
import me.weishu.kernelsu.ui.util.reboot
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
/**
* @author weishu
* @date 2023/1/1.
*/
@OptIn(ExperimentalComposeUiApi::class)
@Composable
@Destination
fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
var text by rememberSaveable { mutableStateOf("") }
val logContent = rememberSaveable { StringBuilder() }
var showFloatAction by rememberSaveable { mutableStateOf(false) }
val snackBarHost = LocalSnackbarHost.current
val scope = rememberCoroutineScope()
val scrollState = rememberScrollState()
LaunchedEffect(Unit) {
if (text.isNotEmpty()) {
return@LaunchedEffect
}
withContext(Dispatchers.IO) {
flashIt(flashIt, onFinish = { showReboot ->
if (showReboot) {
for (i in 0..2) {
text += "\n"
}
showFloatAction = true
}
}, onStdout = {
text += "$it\n"
logContent.append(it).append("\n")
}, onStderr = {
logContent.append(it).append("\n")
});
}
}
Scaffold(
topBar = {
TopBar(
onBack = {
navigator.popBackStack()
},
onSave = {
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_install_log_${date}.log"
)
file.writeText(logContent.toString())
snackBarHost.showSnackbar("Log saved to ${file.absolutePath}")
}
}
)
},
floatingActionButton = {
if (showFloatAction) {
val reboot = stringResource(id = R.string.reboot)
ExtendedFloatingActionButton(
onClick = {
scope.launch {
withContext(Dispatchers.IO) {
reboot()
}
}
},
icon = { Icon(Icons.Filled.Refresh, reboot) },
text = { Text(text = reboot) },
)
}
}
) { 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 = text,
fontSize = MaterialTheme.typography.bodySmall.fontSize,
fontFamily = FontFamily.Monospace,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
)
}
}
}
@Parcelize
sealed class FlashIt : Parcelable {
data class FlashBoot(val bootUri: Uri? = null, val lkmUri: Uri? = null, val ota: Boolean) : FlashIt()
data class FlashModule(val uri: Uri) : FlashIt()
}
fun flashIt(
flashIt: FlashIt, onFinish: (Boolean) -> Unit,
onStdout: (String) -> Unit,
onStderr: (String) -> Unit
) {
when (flashIt) {
is FlashIt.FlashBoot -> installBoot(
flashIt.bootUri,
flashIt.lkmUri,
flashIt.ota,
onFinish,
onStdout,
onStderr
)
is FlashIt.FlashModule -> installModule(flashIt.uri, onFinish, onStdout, onStderr)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar(onBack: () -> Unit = {}, onSave: () -> Unit = {}) {
TopAppBar(
title = { Text(stringResource(R.string.install)) },
navigationIcon = {
IconButton(
onClick = onBack
) { Icon(Icons.Filled.ArrowBack, contentDescription = null) }
},
actions = {
IconButton(onClick = onSave) {
Icon(
imageVector = Icons.Filled.Save,
contentDescription = "Localized description"
)
}
}
)
}
@Preview
@Composable
fun InstallPreview() {
// InstallScreen(DestinationsNavigator(), uri = Uri.EMPTY)
}

View File

@@ -5,11 +5,13 @@ import android.os.Build
import android.os.PowerManager
import android.system.Os
import androidx.annotation.StringRes
import androidx.compose.animation.*
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Archive
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.outlined.Block
@@ -29,12 +31,11 @@ import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootNavGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import me.weishu.kernelsu.*
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.ConfirmDialog
import me.weishu.kernelsu.ui.component.ConfirmResult
import me.weishu.kernelsu.ui.component.rememberConfirmDialog
import me.weishu.kernelsu.ui.screen.destinations.InstallScreenDestination
import me.weishu.kernelsu.ui.screen.destinations.SettingScreenDestination
import me.weishu.kernelsu.ui.util.*
@@ -42,9 +43,13 @@ import me.weishu.kernelsu.ui.util.*
@Destination
@Composable
fun HomeScreen(navigator: DestinationsNavigator) {
val kernelVersion = getKernelVersion()
Scaffold(topBar = {
TopBar(onSettingsClick = {
TopBar(kernelVersion, onSettingsClick = {
navigator.navigate(SettingScreenDestination)
}, onInstallClick = {
navigator.navigate(InstallScreenDestination)
})
}) { innerPadding ->
Column(
@@ -54,14 +59,18 @@ fun HomeScreen(navigator: DestinationsNavigator) {
.verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
val kernelVersion = getKernelVersion()
val isManager = Natives.becomeManager(ksuApp.packageName)
SideEffect {
if (isManager) install()
}
val ksuVersion = if (isManager) Natives.version else null
val lkmMode = ksuVersion?.let {
if (it >= Natives.MINIMAL_SUPPORTED_KERNEL_LKM && kernelVersion.isGKI()) Natives.isLkmMode else null
}
StatusCard(kernelVersion, ksuVersion)
StatusCard(kernelVersion, ksuVersion, lkmMode) {
navigator.navigate(InstallScreenDestination)
}
if (isManager && Natives.requireNewKernel()) {
WarningCard(
stringResource(id = R.string.require_kernel_version).format(
@@ -69,12 +78,21 @@ fun HomeScreen(navigator: DestinationsNavigator) {
)
)
}
UpdateCard()
if (ksuVersion != null && !rootAvailable()) {
WarningCard(
stringResource(id = R.string.grant_root_failed)
)
}
val checkUpdate =
LocalContext.current.getSharedPreferences("settings", Context.MODE_PRIVATE)
.getBoolean("check_update", true)
if (checkUpdate) {
UpdateCard()
}
InfoCard()
DonateCard()
LearnMoreCard()
Spacer(Modifier)
ConfirmDialog()
}
}
}
@@ -89,28 +107,28 @@ fun UpdateCard() {
val newVersionCode = newVersion.first
val newVersionUrl = newVersion.second
val changelog = newVersion.third
if (newVersionCode <= currentVersionCode) {
return
}
val uriHandler = LocalUriHandler.current
val dialogHost = LocalDialogHost.current
val title = stringResource(id = R.string.module_changelog)
val updateText = stringResource(id = R.string.module_update)
val scope = rememberCoroutineScope()
WarningCard(
message = stringResource(id = R.string.new_version_available).format(newVersionCode),
MaterialTheme.colorScheme.outlineVariant
AnimatedVisibility(
visible = newVersionCode > currentVersionCode,
enter = fadeIn() + expandVertically(),
exit = shrinkVertically() + fadeOut()
) {
scope.launch {
if (changelog.isEmpty() || dialogHost.showConfirm(
val updateDialog = rememberConfirmDialog(onConfirm = { uriHandler.openUri(newVersionUrl) })
WarningCard(
message = stringResource(id = R.string.new_version_available).format(newVersionCode),
MaterialTheme.colorScheme.outlineVariant
) {
if (changelog.isNotEmpty()) {
updateDialog.showConfirm(
title = title,
content = changelog,
markdown = true,
confirm = updateText,
) == ConfirmResult.Confirmed
) {
uriHandler.openUri(newVersionUrl)
confirm = updateText
)
}
}
}
@@ -127,8 +145,21 @@ fun RebootDropdownItem(@StringRes id: Int, reason: String = "") {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar(onSettingsClick: () -> Unit) {
private fun TopBar(
kernelVersion: KernelVersion,
onInstallClick: () -> Unit,
onSettingsClick: () -> Unit
) {
TopAppBar(title = { Text(stringResource(R.string.app_name)) }, actions = {
if (kernelVersion.isGKI()) {
IconButton(onClick = onInstallClick) {
Icon(
imageVector = Icons.Filled.Archive,
contentDescription = stringResource(id = R.string.install)
)
}
}
var showDropdown by remember { mutableStateOf(false) }
IconButton(onClick = {
showDropdown = true
@@ -166,33 +197,46 @@ private fun TopBar(onSettingsClick: () -> Unit) {
}
@Composable
private fun StatusCard(kernelVersion: KernelVersion, ksuVersion: Int?) {
private fun StatusCard(
kernelVersion: KernelVersion,
ksuVersion: Int?,
lkmMode: Boolean?,
onClickInstall: () -> Unit = {}
) {
ElevatedCard(
colors = CardDefaults.elevatedCardColors(containerColor = run {
if (ksuVersion != null) MaterialTheme.colorScheme.secondaryContainer
else MaterialTheme.colorScheme.errorContainer
})
) {
val uriHandler = LocalUriHandler.current
Row(modifier = Modifier
.fillMaxWidth()
.clickable {
if (kernelVersion.isGKI() && ksuVersion == null) {
uriHandler.openUri("https://kernelsu.org/guide/installation.html")
if (kernelVersion.isGKI()) {
onClickInstall()
}
}
.padding(24.dp), verticalAlignment = Alignment.CenterVertically) {
when {
ksuVersion != null -> {
val appendText = if (Natives.isSafeMode) {
" [${stringResource(id = R.string.safe_mode)}]"
} else {
""
val safeMode = when {
Natives.isSafeMode -> " [${stringResource(id = R.string.safe_mode)}]"
else -> ""
}
val workingMode = when (lkmMode) {
null -> ""
true -> " <LKM>"
else -> " <GKI>"
}
val workingText =
"${stringResource(id = R.string.home_working)}$workingMode$safeMode"
Icon(Icons.Outlined.CheckCircle, stringResource(R.string.home_working))
Column(Modifier.padding(start = 20.dp)) {
Text(
text = stringResource(R.string.home_working) + appendText,
text = workingText,
style = MaterialTheme.typography.titleMedium
)
Spacer(Modifier.height(4.dp))
@@ -372,9 +416,10 @@ fun getManagerVersion(context: Context): Pair<String, Int> {
@Composable
private fun StatusCardPreview() {
Column {
StatusCard(KernelVersion(5, 10, 101), 1)
StatusCard(KernelVersion(5, 10, 101), null)
StatusCard(KernelVersion(4, 10, 101), null)
StatusCard(KernelVersion(5, 10, 101), 1, null)
StatusCard(KernelVersion(5, 10, 101), 20000, true)
StatusCard(KernelVersion(5, 10, 101), null, true)
StatusCard(KernelVersion(4, 10, 101), null, false)
}
}

View File

@@ -1,140 +1,250 @@
package me.weishu.kernelsu.ui.screen
import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Environment
import android.util.Log
import android.webkit.DownloadListener
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.StringRes
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.Save
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.material.icons.filled.FileUpload
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.key
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.net.toFile
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.KeyEventBlocker
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.installModule
import me.weishu.kernelsu.ui.util.reboot
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import me.weishu.kernelsu.ui.component.rememberConfirmDialog
import me.weishu.kernelsu.ui.component.rememberLoadingDialog
import me.weishu.kernelsu.ui.screen.destinations.FlashScreenDestination
import me.weishu.kernelsu.ui.util.DownloadListener
import me.weishu.kernelsu.ui.util.download
import me.weishu.kernelsu.ui.util.getLKMUrl
import me.weishu.kernelsu.ui.util.isAbDevice
import me.weishu.kernelsu.ui.util.isInitBoot
import me.weishu.kernelsu.ui.util.rootAvailable
/**
* @author weishu
* @date 2023/1/1.
* @date 2024/3/12.
*/
@OptIn(ExperimentalComposeUiApi::class)
@Composable
@Destination
fun InstallScreen(navigator: DestinationsNavigator, uri: Uri) {
@Composable
fun InstallScreen(navigator: DestinationsNavigator) {
var installMethod by remember {
mutableStateOf<InstallMethod?>(null)
}
var text by rememberSaveable { mutableStateOf("") }
val logContent = StringBuilder()
var showFloatAction by rememberSaveable { mutableStateOf(false) }
var lkmFileUri = null as Uri?
val snackBarHost = LocalSnackbarHost.current
val scope = rememberCoroutineScope()
val scrollState = rememberScrollState()
LaunchedEffect(Unit) {
if (text.isNotEmpty()) {
return@LaunchedEffect
}
withContext(Dispatchers.IO) {
installModule(uri, onFinish = { success ->
if (success) {
showFloatAction = true
}
}, onStdout = {
text += "$it\n"
scope.launch {
scrollState.animateScrollTo(scrollState.maxValue)
}
logContent.append(it).append("\n")
}, onStderr = {
logContent.append(it).append("\n")
});
val onClickInstall = {
installMethod?.let { method ->
val flashIt = FlashIt.FlashBoot(
bootUri = if (method is InstallMethod.SelectFile) method.uri else null,
lkmUri = lkmFileUri,
ota = method is InstallMethod.DirectInstallToInactiveSlot
)
navigator.navigate(FlashScreenDestination(flashIt))
}
}
Scaffold(
topBar = {
TopBar(
onBack = {
navigator.popBackStack()
},
onSave = {
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_install_log_${date}.log"
)
file.writeText(logContent.toString())
snackBarHost.showSnackbar("Log saved to ${file.absolutePath}")
}
val selectLkmLauncher =
rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_OK) {
it.data?.data?.let { uri ->
lkmFileUri = uri
}
)
},
floatingActionButton = {
if (showFloatAction) {
val reboot = stringResource(id = R.string.reboot)
ExtendedFloatingActionButton(
}
}
val onLkmUpload = {
selectLkmLauncher.launch(
Intent(Intent.ACTION_GET_CONTENT).apply {
type = "application/octet-stream"
}
)
}
Scaffold(topBar = {
TopBar(
onBack = { navigator.popBackStack() },
onLkmUpload = onLkmUpload
)
}) {
Column(modifier = Modifier.padding(it)) {
SelectInstallMethod { method ->
installMethod = method
}
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Button(
modifier = Modifier.fillMaxWidth(),
enabled = installMethod != null,
onClick = {
scope.launch {
withContext(Dispatchers.IO) {
reboot()
}
}
},
icon = { Icon(Icons.Filled.Refresh, reboot) },
text = { Text(text = reboot) },
onClickInstall()
}) {
Text(
stringResource(id = R.string.install_next),
fontSize = MaterialTheme.typography.bodyMedium.fontSize
)
}
}
}
}
}
sealed class InstallMethod {
data class SelectFile(
val uri: Uri? = null,
@StringRes override val label: Int = R.string.select_file,
override val summary: String?
) : InstallMethod()
object DirectInstall : InstallMethod() {
override val label: Int
get() = R.string.direct_install
}
object DirectInstallToInactiveSlot : InstallMethod() {
override val label: Int
get() = R.string.install_inactive_slot
}
abstract val label: Int
open val summary: String? = null
}
@Composable
private fun SelectInstallMethod(onSelected: (InstallMethod) -> Unit = {}) {
val rootAvailable = rootAvailable()
val isAbDevice = isAbDevice()
val selectFileTip = stringResource(
id = R.string.select_file_tip,
if (isInitBoot()) "init_boot" else "boot"
)
val radioOptions =
mutableListOf<InstallMethod>(InstallMethod.SelectFile(summary = selectFileTip))
if (rootAvailable) {
radioOptions.add(InstallMethod.DirectInstall)
if (isAbDevice) {
radioOptions.add(InstallMethod.DirectInstallToInactiveSlot)
}
}
var selectedOption by remember { mutableStateOf<InstallMethod?>(null) }
val selectImageLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult()
) {
if (it.resultCode == Activity.RESULT_OK) {
it.data?.data?.let { uri ->
val option = InstallMethod.SelectFile(uri, summary = selectFileTip)
selectedOption = option
onSelected(option)
}
}
}
val confirmDialog = rememberConfirmDialog(onConfirm = {
selectedOption = InstallMethod.DirectInstallToInactiveSlot
onSelected(InstallMethod.DirectInstallToInactiveSlot)
}, onDismiss = null)
val dialogTitle = stringResource(id = android.R.string.dialog_alert_title)
val dialogContent = stringResource(id = R.string.install_inactive_slot_warning)
val onClick = { option: InstallMethod ->
when (option) {
is InstallMethod.SelectFile -> {
selectImageLauncher.launch(
Intent(Intent.ACTION_GET_CONTENT).apply {
type = "application/octet-stream"
}
)
}
is InstallMethod.DirectInstall -> {
selectedOption = option
onSelected(option)
}
is InstallMethod.DirectInstallToInactiveSlot -> {
confirmDialog.showConfirm(dialogTitle, dialogContent)
}
}
) { innerPadding ->
KeyEventBlocker {
it.key == Key.VolumeDown || it.key == Key.VolumeUp
}
Column(
modifier = Modifier
.fillMaxSize(1f)
.padding(innerPadding)
.verticalScroll(scrollState),
) {
Text(
modifier = Modifier.padding(8.dp),
text = text,
fontSize = MaterialTheme.typography.bodySmall.fontSize,
fontFamily = FontFamily.Monospace,
lineHeight = MaterialTheme.typography.bodySmall.lineHeight,
)
}
Column {
radioOptions.forEach { option ->
Row(verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clickable {
onClick(option)
}) {
RadioButton(selected = option.javaClass == selectedOption?.javaClass, onClick = {
onClick(option)
})
Column {
Text(
text = stringResource(id = option.label),
fontSize = MaterialTheme.typography.titleMedium.fontSize,
fontFamily = MaterialTheme.typography.titleMedium.fontFamily,
fontStyle = MaterialTheme.typography.titleMedium.fontStyle
)
option.summary?.let {
Text(
text = it,
fontSize = MaterialTheme.typography.bodySmall.fontSize,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
fontStyle = MaterialTheme.typography.bodySmall.fontStyle
)
}
}
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar(onBack: () -> Unit = {}, onSave: () -> Unit = {}) {
private fun TopBar(onBack: () -> Unit = {}, onLkmUpload: () -> Unit = {}) {
TopAppBar(
title = { Text(stringResource(R.string.install)) },
navigationIcon = {
@@ -143,18 +253,15 @@ private fun TopBar(onBack: () -> Unit = {}, onSave: () -> Unit = {}) {
) { Icon(Icons.Filled.ArrowBack, contentDescription = null) }
},
actions = {
IconButton(onClick = onSave) {
Icon(
imageVector = Icons.Filled.Save,
contentDescription = "Localized description"
)
IconButton(onClick = onLkmUpload) {
Icon(Icons.Filled.FileUpload, contentDescription = null)
}
}
)
}
@Preview
@Composable
fun InstallPreview() {
// InstallScreen(DestinationsNavigator(), uri = Uri.EMPTY)
@Preview
fun SelectInstall_Preview() {
// InstallScreen(DestinationsNavigator())
}

View File

@@ -7,6 +7,7 @@ import android.util.Log
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
@@ -39,10 +40,11 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.ConfirmDialog
import me.weishu.kernelsu.ui.component.ConfirmResult
import me.weishu.kernelsu.ui.component.LoadingDialog
import me.weishu.kernelsu.ui.screen.destinations.InstallScreenDestination
import me.weishu.kernelsu.ui.component.rememberConfirmDialog
import me.weishu.kernelsu.ui.component.rememberLoadingDialog
import me.weishu.kernelsu.ui.screen.destinations.FlashScreenDestination
import me.weishu.kernelsu.ui.screen.destinations.WebScreenDestination
import me.weishu.kernelsu.ui.util.*
import me.weishu.kernelsu.ui.viewmodel.ModuleViewModel
import okhttp3.OkHttpClient
@@ -79,7 +81,7 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
val data = it.data ?: return@rememberLauncherForActivityResult
val uri = data.data ?: return@rememberLauncherForActivityResult
navigator.navigate(InstallScreenDestination(uri))
navigator.navigate(FlashScreenDestination(FlashIt.FlashModule(uri)))
viewModel.markNeedRefresh()
@@ -99,10 +101,6 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
}
}) { innerPadding ->
ConfirmDialog()
LoadingDialog()
when {
hasMagisk -> {
Box(
@@ -122,10 +120,15 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
ModuleList(
viewModel = viewModel, modifier = Modifier
.padding(innerPadding)
.fillMaxSize()
) {
navigator.navigate(InstallScreenDestination(it))
}
.fillMaxSize(),
onInstallModule =
{
navigator.navigate(FlashScreenDestination(FlashIt.FlashModule(it)))
}, onClickModule = { id, name, hasWebUi ->
if (hasWebUi) {
navigator.navigate(WebScreenDestination(id, name))
}
})
}
}
}
@@ -134,7 +137,10 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
@OptIn(ExperimentalMaterialApi::class)
@Composable
private fun ModuleList(
viewModel: ModuleViewModel, modifier: Modifier = Modifier, onInstallModule: (Uri) -> Unit
viewModel: ModuleViewModel,
modifier: Modifier = Modifier,
onInstallModule: (Uri) -> Unit,
onClickModule: (id: String, name: String, hasWebUi: Boolean) -> Unit
) {
val failedEnable = stringResource(R.string.module_failed_to_enable)
val failedDisable = stringResource(R.string.module_failed_to_disable)
@@ -152,17 +158,19 @@ private fun ModuleList(
val startDownloadingText = stringResource(R.string.module_start_downloading)
val fetchChangeLogFailed = stringResource(R.string.module_changelog_failed)
val dialogHost = LocalDialogHost.current
val snackBarHost = LocalSnackbarHost.current
val context = LocalContext.current
val loadingDialog = rememberLoadingDialog()
val confirmDialog = rememberConfirmDialog()
suspend fun onModuleUpdate(
module: ModuleViewModel.ModuleInfo,
changelogUrl: String,
downloadUrl: String,
fileName: String
) {
val changelogResult = dialogHost.withLoading {
val changelogResult = loadingDialog.withLoading {
withContext(Dispatchers.IO) {
runCatching {
OkHttpClient().newCall(
@@ -172,7 +180,7 @@ private fun ModuleList(
}
}
val showToast: suspend (String) -> Unit = {msg->
val showToast: suspend (String) -> Unit = { msg ->
withContext(Dispatchers.Main) {
Toast.makeText(
context,
@@ -191,7 +199,7 @@ private fun ModuleList(
}
// changelog is not empty, show it and wait for confirm
val confirmResult = dialogHost.showConfirm(
val confirmResult = confirmDialog.awaitConfirm(
changelogText,
content = changelog,
markdown = true,
@@ -222,7 +230,7 @@ private fun ModuleList(
}
suspend fun onModuleUninstall(module: ModuleViewModel.ModuleInfo) {
val confirmResult = dialogHost.showConfirm(
val confirmResult = confirmDialog.awaitConfirm(
moduleStr,
content = moduleUninstallConfirm.format(module.name),
confirm = uninstall,
@@ -232,7 +240,7 @@ private fun ModuleList(
return
}
val success = dialogHost.withLoading {
val success = loadingDialog.withLoading {
withContext(Dispatchers.IO) {
uninstallModule(module.id)
}
@@ -317,7 +325,7 @@ private fun ModuleList(
scope.launch { onModuleUninstall(module) }
}, onCheckChanged = {
scope.launch {
val success = dialogHost.withLoading {
val success = loadingDialog.withLoading {
withContext(Dispatchers.IO) {
toggleModule(module.id, !isChecked)
}
@@ -346,6 +354,8 @@ private fun ModuleList(
"${module.name}-${updatedModule.second}.zip"
)
}
}, onClick = {
onClickModule(it.id, it.name, it.hasWebUi)
})
// fix last item shadow incomplete in LazyColumn
@@ -379,9 +389,12 @@ private fun ModuleItem(
onUninstall: (ModuleViewModel.ModuleInfo) -> Unit,
onCheckChanged: (Boolean) -> Unit,
onUpdate: (ModuleViewModel.ModuleInfo) -> Unit,
onClick: (ModuleViewModel.ModuleInfo) -> Unit
) {
ElevatedCard(
modifier = Modifier.fillMaxWidth(),
modifier = Modifier
.fillMaxWidth()
.clickable { onClick(module) },
colors = CardDefaults.elevatedCardColors(containerColor = MaterialTheme.colorScheme.surface)
) {
@@ -487,6 +500,18 @@ private fun ModuleItem(
text = stringResource(R.string.uninstall),
)
}
if (module.hasWebUi) {
TextButton(
onClick = { onClick(module) },
) {
Text(
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
fontSize = MaterialTheme.typography.labelMedium.fontSize,
text = stringResource(R.string.open),
)
}
}
}
}
}
@@ -505,7 +530,8 @@ fun ModuleItemPreview() {
enabled = true,
update = true,
remove = true,
updateJson = ""
updateJson = "",
hasWebUi = false,
)
ModuleItem(module, true, "", {}, {}, {})
ModuleItem(module, true, "", {}, {}, {}, {})
}

View File

@@ -1,15 +1,13 @@
package me.weishu.kernelsu.ui.screen
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.BugReport
import androidx.compose.material.icons.filled.ContactPage
import androidx.compose.material.icons.filled.Fence
import androidx.compose.material.icons.filled.RemoveModerator
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
@@ -26,10 +24,10 @@ import me.weishu.kernelsu.BuildConfig
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.AboutDialog
import me.weishu.kernelsu.ui.component.LoadingDialog
import me.weishu.kernelsu.ui.component.SwitchItem
import me.weishu.kernelsu.ui.component.rememberCustomDialog
import me.weishu.kernelsu.ui.component.rememberLoadingDialog
import me.weishu.kernelsu.ui.screen.destinations.AppProfileTemplateScreenDestination
import me.weishu.kernelsu.ui.util.LocalDialogHost
import me.weishu.kernelsu.ui.util.getBugreportFile
/**
@@ -39,7 +37,6 @@ import me.weishu.kernelsu.ui.util.getBugreportFile
@Destination
@Composable
fun SettingScreen(navigator: DestinationsNavigator) {
Scaffold(
topBar = {
TopBar(onBack = {
@@ -47,24 +44,23 @@ fun SettingScreen(navigator: DestinationsNavigator) {
})
}
) { paddingValues ->
LoadingDialog()
val showAboutDialog = remember { mutableStateOf(false) }
AboutDialog(showAboutDialog)
val aboutDialog = rememberCustomDialog {
AboutDialog(it)
}
val loadingDialog = rememberLoadingDialog()
Column(modifier = Modifier.padding(paddingValues)) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val dialogHost = LocalDialogHost.current
val profileTemplate = stringResource(id = R.string.settings_profile_template)
ListItem(
leadingContent = { Icon(Icons.Filled.Fence, profileTemplate) },
headlineContent = { Text(profileTemplate) },
supportingContent = { Text(stringResource(id = R.string.settings_profile_template_summary))},
supportingContent = { Text(stringResource(id = R.string.settings_profile_template_summary)) },
modifier = Modifier.clickable {
navigator.navigate(AppProfileTemplateScreenDestination)
navigator.navigate(AppProfileTemplateScreenDestination)
}
)
@@ -82,12 +78,49 @@ fun SettingScreen(navigator: DestinationsNavigator) {
}
}
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
var checkUpdate by rememberSaveable {
mutableStateOf(
prefs.getBoolean("check_update", true)
)
}
SwitchItem(
icon = Icons.Filled.Update,
title = stringResource(id = R.string.settings_check_update),
summary = stringResource(id = R.string.settings_check_update_summary),
checked = checkUpdate
) {
prefs.edit().putBoolean("check_update", it).apply()
checkUpdate = it
}
var enableWebDebugging by rememberSaveable {
mutableStateOf(
prefs.getBoolean("enable_web_debugging", false)
)
}
SwitchItem(
icon = Icons.Filled.DeveloperMode,
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
}
ListItem(
leadingContent = { Icon(Icons.Filled.BugReport, stringResource(id = R.string.send_log)) },
leadingContent = {
Icon(
Icons.Filled.BugReport,
stringResource(id = R.string.send_log)
)
},
headlineContent = { Text(stringResource(id = R.string.send_log)) },
modifier = Modifier.clickable {
scope.launch {
val bugreport = dialogHost.withLoading {
val bugreport = loadingDialog.withLoading {
withContext(Dispatchers.IO) {
getBugreportFile(context)
}
@@ -117,10 +150,15 @@ fun SettingScreen(navigator: DestinationsNavigator) {
val about = stringResource(id = R.string.about)
ListItem(
leadingContent = { Icon(Icons.Filled.ContactPage, stringResource(id = R.string.about)) },
leadingContent = {
Icon(
Icons.Filled.ContactPage,
stringResource(id = R.string.about)
)
},
headlineContent = { Text(about) },
modifier = Modifier.clickable {
showAboutDialog.value = true
aboutDialog.show()
}
)
}

View File

@@ -30,7 +30,6 @@ import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.launch
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.ConfirmDialog
import me.weishu.kernelsu.ui.component.SearchAppBar
import me.weishu.kernelsu.ui.screen.destinations.AppProfileScreenDestination
import me.weishu.kernelsu.ui.viewmodel.SuperUserViewModel
@@ -95,9 +94,6 @@ fun SuperUserScreen(navigator: DestinationsNavigator) {
)
}
) { innerPadding ->
ConfirmDialog()
val refreshState = rememberPullRefreshState(
refreshing = viewModel.isRefreshing,
onRefresh = { scope.launch { viewModel.fetchAppList() } },

View File

@@ -0,0 +1,77 @@
package me.weishu.kernelsu.ui.screen
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.util.Log
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.webkit.WebViewAssetLoader
import com.google.accompanist.web.AccompanistWebViewClient
import com.google.accompanist.web.WebView
import com.google.accompanist.web.rememberWebViewState
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import me.weishu.kernelsu.ui.webui.SuFilePathHandler
import me.weishu.kernelsu.ui.webui.WebViewInterface
import me.weishu.kernelsu.ui.webui.showSystemUI
import java.io.File
@SuppressLint("SetJavaScriptEnabled")
@Destination
@Composable
fun WebScreen(navigator: DestinationsNavigator, moduleId: String, moduleName: String) {
val context = LocalContext.current
DisposableEffect(Unit) {
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
WebView.setWebContentsDebuggingEnabled(prefs.getBoolean("enable_web_debugging", false))
onDispose {
if (WebViewInterface.isHideSystemUI && context is Activity) {
showSystemUI(context.window)
}
}
}
Scaffold { innerPadding ->
val webRoot = File("/data/adb/modules/${moduleId}/webroot")
val webViewAssetLoader = WebViewAssetLoader.Builder()
.setDomain("mui.kernelsu.org")
.addPathHandler("/",
SuFilePathHandler(context, webRoot)
)
.build()
val webViewClient = object : AccompanistWebViewClient() {
override fun shouldInterceptRequest(
view: WebView,
request: WebResourceRequest
): WebResourceResponse? {
return webViewAssetLoader.shouldInterceptRequest(request.url)
}
}
WebView(
state = rememberWebViewState(url = "https://mui.kernelsu.org/index.html"),
Modifier
.fillMaxSize()
.padding(innerPadding),
client = webViewClient,
factory = { context ->
WebView(context).apply {
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
settings.allowFileAccess = false
addJavascriptInterface(WebViewInterface(context, this), "ksu")
}
})
}
}

View File

@@ -2,12 +2,7 @@ package me.weishu.kernelsu.ui.util
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.compositionLocalOf
import me.weishu.kernelsu.ui.component.DialogHostState
val LocalSnackbarHost = compositionLocalOf<SnackbarHostState> {
error("CompositionLocal LocalSnackbarController not present")
}
val LocalDialogHost = compositionLocalOf<DialogHostState> {
error("CompositionLocal LocalDialogController not present")
}

View File

@@ -10,6 +10,7 @@ import android.net.Uri
import android.os.Environment
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import me.weishu.kernelsu.getKMI
/**
* @author weishu
@@ -94,6 +95,38 @@ fun checkNewVersion(): Triple<Int, String, String> {
}
return defaultValue
}
fun getLKMUrl(): Result<Pair<String, String>> {
val url = "https://api.github.com/repos/tiann/KernelSU/releases/latest"
val kmi = getKMI() ?: return Result.failure(RuntimeException("Get KMI failed"))
runCatching {
okhttp3.OkHttpClient().newCall(okhttp3.Request.Builder().url(url).build()).execute()
.use { response ->
val body = response.body?.string() ?: return Result.failure(RuntimeException("request body failed"))
if (!response.isSuccessful) {
return Result.failure(RuntimeException("Request failed, code: ${response.code}, message: $body"))
}
val json = org.json.JSONObject(body)
val assets = json.getJSONArray("assets")
for (i in 0 until assets.length()) {
val asset = assets.getJSONObject(i)
val name = asset.getString("name")
if (!name.endsWith(".ko")) {
continue
}
if (name.contains(kmi)) {
return Result.success(Pair(name, asset.getString("browser_download_url")))
}
}
}
}.onFailure {
return Result.failure(it)
}
return Result.failure(RuntimeException("Cannot find LKM for $kmi"))
}
@Composable
fun DownloadListener(context: Context, onDownloaded: (Uri) -> Unit) {

View File

@@ -1,11 +1,14 @@
package me.weishu.kernelsu.ui.util
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.SystemClock
import android.util.Log
import com.topjohnwu.superuser.CallbackList
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils
import com.topjohnwu.superuser.io.SuFile
import me.weishu.kernelsu.BuildConfig
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.ksuApp
@@ -25,17 +28,24 @@ private fun getKsuDaemonPath(): String {
object KsuCli {
val SHELL: Shell = createRootShell()
val GLOBAL_MNT_SHELL: Shell = createRootShell(true)
}
fun getRootShell(): Shell {
return KsuCli.SHELL
fun getRootShell(globalMnt: Boolean = false): Shell {
return if (globalMnt) KsuCli.GLOBAL_MNT_SHELL else {
KsuCli.SHELL
}
}
fun createRootShell(): Shell {
fun createRootShell(globalMnt: Boolean = false): Shell {
Shell.enableVerboseLogging = BuildConfig.DEBUG
val builder = Shell.Builder.create()
return try {
builder.build(getKsuDaemonPath(), "debug", "su")
if (globalMnt) {
builder.build(getKsuDaemonPath(), "debug", "su", "-g")
} else {
builder.build(getKsuDaemonPath(), "debug", "su")
}
} catch (e: Throwable) {
Log.e(TAG, "su failed: ", e)
builder.build("sh")
@@ -105,7 +115,7 @@ fun installModule(
}
val cmd = "module install ${file.absolutePath}"
val shell = getRootShell()
val shell = createRootShell()
val stdoutCallback: CallbackList<String?> = object : CallbackList<String?>() {
override fun onAddElement(s: String?) {
@@ -131,6 +141,88 @@ fun installModule(
}
}
fun installBoot(
bootUri: Uri?,
lkmUri: Uri?,
ota: Boolean,
onFinish: (Boolean) -> Unit,
onStdout: (String) -> Unit,
onStderr: (String) -> Unit,
): Boolean {
val resolver = ksuApp.contentResolver
val bootFile = bootUri?.let { uri ->
with(resolver.openInputStream(uri)) {
val bootFile = File(ksuApp.cacheDir, "boot.img")
bootFile.outputStream().use { output ->
this?.copyTo(output)
}
bootFile
}
}
val lkmFile = lkmUri?.let { uri ->
with(resolver.openInputStream(uri)) {
val lkmFile = File(ksuApp.cacheDir, "kernelsu-tmp-lkm.ko")
lkmFile.outputStream().use { output ->
this?.copyTo(output)
}
lkmFile
}
}
val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libmagiskboot.so")
var cmd = "boot-patch --magiskboot ${magiskboot.absolutePath}"
cmd += if (bootFile == null) {
// no boot.img, use -f to force install
" -f"
} else {
" -b ${bootFile.absolutePath}"
}
if (ota) {
cmd += " -u"
}
lkmFile?.let {
cmd += " -m ${it.absolutePath}"
}
// output dir
val downloadsDir =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
cmd += " -o $downloadsDir"
val shell = createRootShell()
val stdoutCallback: CallbackList<String?> = object : CallbackList<String?>() {
override fun onAddElement(s: String?) {
onStdout(s ?: "")
}
}
val stderrCallback: CallbackList<String?> = object : CallbackList<String?>() {
override fun onAddElement(s: String?) {
onStderr(s ?: "")
}
}
val result =
shell.newJob().add("${getKsuDaemonPath()} $cmd").to(stdoutCallback, stderrCallback)
.exec()
Log.i("KernelSU", "install boot result: ${result.isSuccess}")
bootFile?.delete()
lkmFile?.delete()
// if boot uri is empty, it is direct install, when success, we should show reboot button
onFinish(bootUri == null && result.isSuccess)
return result.isSuccess
}
fun reboot(reason: String = "") {
val shell = getRootShell()
if (reason == "recovery") {
@@ -140,6 +232,31 @@ fun reboot(reason: String = "") {
ShellUtils.fastCmd(shell, "/system/bin/svc power reboot $reason || /system/bin/reboot $reason")
}
fun rootAvailable(): Boolean {
val shell = getRootShell()
return shell.isRoot
}
fun isAbDevice(): Boolean {
val shell = getRootShell()
return ShellUtils.fastCmd(shell, "getprop ro.build.ab_update").trim().toBoolean()
}
fun isInitBoot(): Boolean {
val shell = getRootShell()
if (shell.isRoot) {
// if we have root, use /dev/block/by-name/init_boot to check
val abDevice = isAbDevice()
val initBootBlock = "/dev/block/by-name/init_boot${if (abDevice) "_a" else ""}"
val file = SuFile(initBootBlock)
file.shell = shell
return file.exists()
}
// https://source.android.com/docs/core/architecture/partitions/generic-boot
return ShellUtils.fastCmd(shell, "getprop ro.product.first_api_level").trim()
.toInt() >= Build.VERSION_CODES.TIRAMISU
}
fun overlayFsAvailable(): Boolean {
val shell = getRootShell()
// check /proc/filesystems
@@ -147,8 +264,8 @@ fun overlayFsAvailable(): Boolean {
}
fun hasMagisk(): Boolean {
val shell = getRootShell()
val result = shell.newJob().add("nsenter --mount=/proc/1/ns/mnt which magisk").exec()
val shell = getRootShell(true)
val result = shell.newJob().add("which magisk").exec()
Log.i(TAG, "has magisk: ${result.isSuccess}")
return result.isSuccess
}

View File

@@ -22,11 +22,15 @@ fun getBugreportFile(context: Context): File {
val tombstonesFile = File(bugreportDir, "tombstones.tar.gz")
val dropboxFile = File(bugreportDir, "dropbox.tar.gz")
val pstoreFile = File(bugreportDir, "pstore.tar.gz")
// Xiaomi/Readmi devices have diag in /data/vendor/diag
val diagFile = File(bugreportDir, "diag.tar.gz")
val opulsFile = File(bugreportDir, "opuls.tar.gz")
val bootlogFile = File(bugreportDir, "bootlog.tar.gz")
val mountsFile = File(bugreportDir, "mounts.txt")
val fileSystemsFile = File(bugreportDir, "filesystems.txt")
val ksuFileTree = File(bugreportDir, "ksu_tree.txt")
val adbFileTree = File(bugreportDir, "adb_tree.txt")
val adbFileDetails = File(bugreportDir, "adb_details.txt")
val ksuFileSize = File(bugreportDir, "ksu_size.txt")
val appListFile = File(bugreportDir, "packages.txt")
val propFile = File(bugreportDir, "props.txt")
val allowListFile = File(bugreportDir, "allowlist.bin")
@@ -34,7 +38,7 @@ fun getBugreportFile(context: Context): File {
val bootConfig = File(bugreportDir, "boot_config.txt")
val kernelConfig = File(bugreportDir, "defconfig.gz")
val shell = getRootShell()
val shell = getRootShell(true)
shell.newJob().add("dmesg > ${dmesgFile.absolutePath}").exec()
shell.newJob().add("logcat -d > ${logcatFile.absolutePath}").exec()
@@ -42,11 +46,14 @@ fun getBugreportFile(context: Context): File {
shell.newJob().add("tar -czf ${dropboxFile.absolutePath} -C /data/system/dropbox .").exec()
shell.newJob().add("tar -czf ${pstoreFile.absolutePath} -C /sys/fs/pstore .").exec()
shell.newJob().add("tar -czf ${diagFile.absolutePath} -C /data/vendor/diag .").exec()
shell.newJob().add("tar -czf ${opulsFile.absolutePath} -C /mnt/oplus/op2/media/log/boot_log/ .").exec()
shell.newJob().add("tar -czf ${bootlogFile.absolutePath} -C /data/adb/ksu/log .").exec()
shell.newJob().add("cat /proc/1/mountinfo > ${mountsFile.absolutePath}").exec()
shell.newJob().add("cat /proc/filesystems > ${fileSystemsFile.absolutePath}").exec()
shell.newJob().add("ls -alRZ /data/adb > ${ksuFileTree.absolutePath}").exec()
shell.newJob().add("busybox tree /data/adb > ${adbFileTree.absolutePath}").exec()
shell.newJob().add("ls -alRZ /data/adb > ${adbFileDetails.absolutePath}").exec()
shell.newJob().add("du -sh /data/adb/ksu/* > ${ksuFileSize.absolutePath}").exec()
shell.newJob().add("cp /data/system/packages.list ${appListFile.absolutePath}").exec()
shell.newJob().add("getprop > ${propFile.absolutePath}").exec()
shell.newJob().add("cp /data/adb/ksu/.allowlist ${allowListFile.absolutePath}").exec()
@@ -82,6 +89,8 @@ fun getBugreportFile(context: Context): File {
pw.println("KernelSU: $ksuKernel")
val safeMode = Natives.isSafeMode
pw.println("SafeMode: $safeMode")
val lkmMode = Natives.isLkmMode
pw.println("LKM: $lkmMode")
}
// modules

View File

@@ -36,6 +36,7 @@ class ModuleViewModel : ViewModel() {
val update: Boolean,
val remove: Boolean,
val updateJson: String,
val hasWebUi: Boolean,
)
data class ModuleUpdateInfo(
@@ -96,7 +97,8 @@ class ModuleViewModel : ViewModel() {
obj.getBoolean("enabled"),
obj.getBoolean("update"),
obj.getBoolean("remove"),
obj.optString("updateJson")
obj.optString("updateJson"),
obj.optBoolean("web")
)
}.toList()
isNeedRefresh = false

View File

@@ -83,8 +83,11 @@ class SuperUserViewModel : ViewModel() {
val appList by derivedStateOf {
sortedList.filter {
it.label.contains(search) || it.packageName.contains(search) || HanziToPinyin.getInstance()
.toPinyinString(it.label).contains(search)
it.label.contains(search, true) || it.packageName.contains(
search,
true
) || HanziToPinyin.getInstance()
.toPinyinString(it.label).contains(search, true)
}.filter {
it.uid == 2000 // Always show shell
|| showSystemApps || it.packageInfo.applicationInfo.flags.and(ApplicationInfo.FLAG_SYSTEM) == 0

View File

@@ -209,9 +209,14 @@ private fun getLocaleString(json: JSONObject, key: String): String {
val locale = Locale.getDefault()
val localeKey = "${locale.language}_${locale.country}"
json.optJSONObject("locales")?.let {
// check locale first
it.optJSONObject(localeKey)?.let { json->
return json.optString(key, fallback)
}
// fallback to language
it.optJSONObject(locale.language)?.let { json->
return json.optString(key, fallback)
}
}
return fallback
}

View File

@@ -0,0 +1,139 @@
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.weishu.kernelsu.ui.webui;
import java.net.URLConnection;
class MimeUtil {
public static String getMimeFromFileName(String fileName) {
if (fileName == null) {
return null;
}
// Copying the logic and mapping that Chromium follows.
// First we check against the OS (this is a limited list by default)
// but app developers can extend this.
// We then check against a list of hardcoded mime types above if the
// OS didn't provide a result.
String mimeType = URLConnection.guessContentTypeFromName(fileName);
if (mimeType != null) {
return mimeType;
}
return guessHardcodedMime(fileName);
}
// We should keep this map in sync with the lists under
// //net/base/mime_util.cc in Chromium.
// A bunch of the mime types don't really apply to Android land
// like word docs so feel free to filter out where necessary.
private static String guessHardcodedMime(String fileName) {
int finalFullStop = fileName.lastIndexOf('.');
if (finalFullStop == -1) {
return null;
}
final String extension = fileName.substring(finalFullStop + 1).toLowerCase();
switch (extension) {
case "webm":
return "video/webm";
case "mpeg":
case "mpg":
return "video/mpeg";
case "mp3":
return "audio/mpeg";
case "wasm":
return "application/wasm";
case "xhtml":
case "xht":
case "xhtm":
return "application/xhtml+xml";
case "flac":
return "audio/flac";
case "ogg":
case "oga":
case "opus":
return "audio/ogg";
case "wav":
return "audio/wav";
case "m4a":
return "audio/x-m4a";
case "gif":
return "image/gif";
case "jpeg":
case "jpg":
case "jfif":
case "pjpeg":
case "pjp":
return "image/jpeg";
case "png":
return "image/png";
case "apng":
return "image/apng";
case "svg":
case "svgz":
return "image/svg+xml";
case "webp":
return "image/webp";
case "mht":
case "mhtml":
return "multipart/related";
case "css":
return "text/css";
case "html":
case "htm":
case "shtml":
case "shtm":
case "ehtml":
return "text/html";
case "js":
case "mjs":
return "application/javascript";
case "xml":
return "text/xml";
case "mp4":
case "m4v":
return "video/mp4";
case "ogv":
case "ogm":
return "video/ogg";
case "ico":
return "image/x-icon";
case "woff":
return "application/font-woff";
case "gz":
case "tgz":
return "application/gzip";
case "json":
return "application/json";
case "pdf":
return "application/pdf";
case "zip":
return "application/zip";
case "bmp":
return "image/bmp";
case "tiff":
case "tif":
return "image/tiff";
default:
return null;
}
}
}

View File

@@ -0,0 +1,195 @@
package me.weishu.kernelsu.ui.webui;
import android.content.Context;
import android.util.Log;
import android.webkit.WebResourceResponse;
import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
import androidx.webkit.WebViewAssetLoader;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.io.SuFile;
import com.topjohnwu.superuser.io.SuFileInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.GZIPInputStream;
import me.weishu.kernelsu.ui.util.KsuCliKt;
/**
* Handler class to open files from file system by root access
* For more information about android storage please refer to
* <a href="https://developer.android.com/guide/topics/data/data-storage">Android Developers
* Docs: Data and file storage overview</a>.
* <p class="note">
* To avoid leaking user or app data to the web, make sure to choose {@code directory}
* carefully, and assume any file under this directory could be accessed by any web page subject
* to same-origin rules.
* <p>
* A typical usage would be like:
* <pre class="prettyprint">
* File publicDir = new File(context.getFilesDir(), "public");
* // Host "files/public/" in app's data directory under:
* // http://appassets.androidplatform.net/public/...
* WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
* .addPathHandler("/public/", new InternalStoragePathHandler(context, publicDir))
* .build();
* </pre>
*/
public final class SuFilePathHandler implements WebViewAssetLoader.PathHandler {
private static final String TAG = "SuFilePathHandler";
/**
* Default value to be used as MIME type if guessing MIME type failed.
*/
public static final String DEFAULT_MIME_TYPE = "text/plain";
/**
* Forbidden subdirectories of {@link Context#getDataDir} that cannot be exposed by this
* handler. They are forbidden as they often contain sensitive information.
* <p class="note">
* Note: Any future addition to this list will be considered breaking changes to the API.
*/
private static final String[] FORBIDDEN_DATA_DIRS =
new String[] {"/data/data", "/data/system"};
@NonNull
private final File mDirectory;
private final Shell mShell;
/**
* Creates PathHandler for app's internal storage.
* The directory to be exposed must be inside either the application's internal data
* directory {@link Context#getDataDir} or cache directory {@link Context#getCacheDir}.
* External storage is not supported for security reasons, as other apps with
* {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} may be able to modify the
* files.
* <p>
* Exposing the entire data or cache directory is not permitted, to avoid accidentally
* exposing sensitive application files to the web. Certain existing subdirectories of
* {@link Context#getDataDir} are also not permitted as they are often sensitive.
* These files are ({@code "app_webview/"}, {@code "databases/"}, {@code "lib/"},
* {@code "shared_prefs/"} and {@code "code_cache/"}).
* <p>
* The application should typically use a dedicated subdirectory for the files it intends to
* expose and keep them separate from other files.
*
* @param context {@link Context} that is used to access app's internal storage.
* @param directory the absolute path of the exposed app internal storage directory from
* which files can be loaded.
* @throws IllegalArgumentException if the directory is not allowed.
*/
public SuFilePathHandler(@NonNull Context context, @NonNull File directory) {
try {
mDirectory = new File(getCanonicalDirPath(directory));
if (!isAllowedInternalStorageDir(context)) {
throw new IllegalArgumentException("The given directory \"" + directory
+ "\" doesn't exist under an allowed app internal storage directory");
}
mShell = KsuCliKt.createRootShell(true);
} catch (IOException e) {
throw new IllegalArgumentException(
"Failed to resolve the canonical path for the given directory: "
+ directory.getPath(), e);
}
}
private boolean isAllowedInternalStorageDir(@NonNull Context context) throws IOException {
String dir = getCanonicalDirPath(mDirectory);
for (String forbiddenPath : FORBIDDEN_DATA_DIRS) {
if (dir.startsWith(forbiddenPath)) {
return false;
}
}
return true;
}
/**
* Opens the requested file from the exposed data directory.
* <p>
* The matched prefix path used shouldn't be a prefix of a real web path. Thus, if the
* requested file cannot be found or is outside the mounted directory a
* {@link WebResourceResponse} object with a {@code null} {@link InputStream} will be
* returned instead of {@code null}. This saves the time of falling back to network and
* trying to resolve a path that doesn't exist. A {@link WebResourceResponse} with
* {@code null} {@link InputStream} will be received as an HTTP response with status code
* {@code 404} and no body.
* <p class="note">
* The MIME type for the file will be determined from the file's extension using
* {@link java.net.URLConnection#guessContentTypeFromName}. Developers should ensure that
* files are named using standard file extensions. If the file does not have a
* recognised extension, {@code "text/plain"} will be used by default.
*
* @param path the suffix path to be handled.
* @return {@link WebResourceResponse} for the requested file.
*/
@Override
@WorkerThread
@NonNull
public WebResourceResponse handle(@NonNull String path) {
try {
File file = getCanonicalFileIfChild(mDirectory, path);
if (file != null) {
InputStream is = openFile(file, mShell);
String mimeType = guessMimeType(path);
return new WebResourceResponse(mimeType, null, is);
} else {
Log.e(TAG, String.format(
"The requested file: %s is outside the mounted directory: %s", path,
mDirectory));
}
} catch (IOException e) {
Log.e(TAG, "Error opening the requested path: " + path, e);
}
return new WebResourceResponse(null, null, null);
}
public static String getCanonicalDirPath(@NonNull File file) throws IOException {
String canonicalPath = file.getCanonicalPath();
if (!canonicalPath.endsWith("/")) canonicalPath += "/";
return canonicalPath;
}
public static File getCanonicalFileIfChild(@NonNull File parent, @NonNull String child)
throws IOException {
String parentCanonicalPath = getCanonicalDirPath(parent);
String childCanonicalPath = new File(parent, child).getCanonicalPath();
if (childCanonicalPath.startsWith(parentCanonicalPath)) {
return new File(childCanonicalPath);
}
return null;
}
@NonNull
private static InputStream handleSvgzStream(@NonNull String path,
@NonNull InputStream stream) throws IOException {
return path.endsWith(".svgz") ? new GZIPInputStream(stream) : stream;
}
public static InputStream openFile(@NonNull File file, @NonNull Shell shell) throws FileNotFoundException,
IOException {
SuFile suFile = new SuFile(file.getAbsolutePath());
suFile.setShell(shell);
InputStream fis = SuFileInputStream.open(suFile);
return handleSvgzStream(file.getPath(), fis);
}
/**
* Use {@link MimeUtil#getMimeFromFileName} to guess MIME type or return the
* {@link #DEFAULT_MIME_TYPE} if it can't guess.
*
* @param filePath path of the file to guess its MIME type.
* @return MIME type guessed from file extension or {@link #DEFAULT_MIME_TYPE}.
*/
@NonNull
public static String guessMimeType(@NonNull String filePath) {
String mimeType = MimeUtil.getMimeFromFileName(filePath);
return mimeType == null ? DEFAULT_MIME_TYPE : mimeType;
}
}

View File

@@ -0,0 +1,192 @@
package me.weishu.kernelsu.ui.webui
import android.app.Activity
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.text.TextUtils
import android.view.Window
import android.webkit.JavascriptInterface
import android.webkit.WebView
import android.widget.Toast
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import com.topjohnwu.superuser.CallbackList
import com.topjohnwu.superuser.ShellUtils
import me.weishu.kernelsu.ui.util.createRootShell
import org.json.JSONArray
import org.json.JSONObject
import java.util.concurrent.CompletableFuture
class WebViewInterface(val context: Context, private val webView: WebView) {
companion object {
var isHideSystemUI: Boolean = false
}
@JavascriptInterface
fun exec(cmd: String): String {
val shell = createRootShell(true)
return ShellUtils.fastCmd(shell, cmd)
}
@JavascriptInterface
fun exec(cmd: String, callbackFunc: String) {
exec(cmd, null, callbackFunc)
}
private fun processOptions(sb: StringBuilder, options: String?) {
val opts = if (options == null) JSONObject() else {
JSONObject(options)
}
val cwd = opts.optString("cwd")
if (!TextUtils.isEmpty(cwd)) {
sb.append("cd ${cwd};")
}
opts.optJSONObject("env")?.let { env ->
env.keys().forEach { key ->
sb.append("export ${key}=${env.getString(key)};")
}
}
}
@JavascriptInterface
fun exec(
cmd: String,
options: String?,
callbackFunc: String
) {
val finalCommand = StringBuilder()
processOptions(finalCommand, options)
finalCommand.append(cmd)
val shell = createRootShell(true)
val result = shell.newJob().add(finalCommand.toString()).to(ArrayList(), ArrayList()).exec()
val stdout = result.out.joinToString(separator = "\n")
val stderr = result.err.joinToString(separator = "\n")
val jsCode =
"javascript: (function() { try { ${callbackFunc}(${result.code}, ${
JSONObject.quote(
stdout
)
}, ${JSONObject.quote(stderr)}); } catch(e) { console.error(e); } })();"
webView.post {
webView.loadUrl(jsCode)
}
}
@JavascriptInterface
fun spawn(command: String, args: String, options: String?, callbackFunc: String) {
val finalCommand = StringBuilder()
processOptions(finalCommand, options)
if (!TextUtils.isEmpty(args)) {
finalCommand.append(command).append(" ")
JSONArray(args).let { argsArray ->
for (i in 0 until argsArray.length()) {
finalCommand.append(argsArray.getString(i))
finalCommand.append(" ")
}
}
} else {
finalCommand.append(command)
}
val shell = createRootShell(true)
val emitData = fun(name: String, data: String) {
val jsCode =
"javascript: (function() { try { ${callbackFunc}.${name}.emit('data', ${
JSONObject.quote(
data
)
}); } catch(e) { console.error('emitData', e); } })();"
webView.post {
webView.loadUrl(jsCode)
}
}
val stdout = object : CallbackList<String>() {
override fun onAddElement(s: String) {
emitData("stdout", s)
}
}
val stderr = object : CallbackList<String>() {
override fun onAddElement(s: String) {
emitData("stderr", s)
}
}
val future = shell.newJob().add(finalCommand.toString()).to(stdout, stderr).enqueue()
val completableFuture = CompletableFuture.supplyAsync {
future.get()
}
completableFuture.thenAccept { result ->
val emitExitCode =
"javascript: (function() { try { ${callbackFunc}.emit('exit', ${result.code}); } catch(e) { console.error(`emitExit error: \${e}`); } })();"
webView.post {
webView.loadUrl(emitExitCode)
}
if (result.code != 0) {
val emitErrCode =
"javascript: (function() { try { var err = new Error(); err.exitCode = ${result.code}; err.message = ${
JSONObject.quote(
result.err.joinToString(
"\n"
)
)
};${callbackFunc}.emit('error', err); } catch(e) { console.error('emitErr', e); } })();"
webView.post {
webView.loadUrl(emitErrCode)
}
}
}
}
@JavascriptInterface
fun toast(msg: String) {
webView.post {
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
}
}
@JavascriptInterface
fun fullScreen(enable: Boolean) {
if (context is Activity) {
Handler(Looper.getMainLooper()).post {
if (enable) {
hideSystemUI(context.window)
} else {
showSystemUI(context.window)
}
isHideSystemUI = enable
}
}
}
}
fun hideSystemUI(window: Window) {
WindowCompat.setDecorFitsSystemWindows(window, false)
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
controller.hide(WindowInsetsCompat.Type.systemBars())
controller.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
}
}
fun showSystemUI(window: Window) {
WindowCompat.setDecorFitsSystemWindows(window, true)
WindowInsetsControllerCompat(
window,
window.decorView
).show(WindowInsetsCompat.Type.systemBars())
}

View File

@@ -102,4 +102,17 @@
<string name="app_profile_template_delete">حذف</string>
<string name="app_profile_template_import_empty">الحافظة فارغة!</string>
<string name="app_profile_template_view">عرض القالب</string>
<string name="grant_root_failed">فشل في منح صلاحية الجذر!</string>
<string name="open">فتح</string>
<string name="settings_check_update_summary">التحقق تلقائيًا من وجود تحديثات عند فتح التطبيق</string>
<string name="settings_check_update">التحقق من التحديث</string>
<string name="enable_web_debugging">تمكين تصحيح أخطاء WebView</string>
<string name="enable_web_debugging_summary">يمكن استخدامه لتصحيح أخطاء WebUI، يرجى تمكينه فقط عند الحاجة.</string>
<string name="install_next">التالي</string>
<string name="select_file">اختيار ملف</string>
<string name="direct_install">تثبيت مباشر (موصى به)</string>
<string name="install_inactive_slot">التثبيت على فتحة غير نشطة (بعد OTA)</string>
<string name="install_inactive_slot_warning">سيتم **إجبار** جهازك على التمهيد إلى الفتحة غير النشطة الحالية بعد إعادة التشغيل!
\nاستخدم هذا الخيار فقط بعد انتهاء التحديث.
\nأستمرار؟</string>
</resources>

View File

@@ -102,4 +102,10 @@
<string name="profile_umount_modules_summary">Selle valiku lubamine lubab KernelSU-l taastada selle rakenduse moodulite poolt mistahes muudetud faile.</string>
<string name="app_profile_template_export_empty">Eksportimiseks kohalikku malli ei leitud!</string>
<string name="settings_umount_modules_default_summary">Globaalne vaikeväärtus \"Lahtihaagitud moodulitele\" rakenduseprofiilides. Lubamisel eemaldab see kõik moodulite süsteemimuudatused rakendustele, millel ei ole profiili määratud.</string>
<string name="enable_web_debugging_summary">Saab kasutada WebUI silumiseks, palun luba ainult vajadusel.</string>
<string name="grant_root_failed">Juurkasutaja andmine ebaõnnestus!</string>
<string name="settings_check_update">Kontrolli uuendusi</string>
<string name="settings_check_update_summary">Rakenduse avamisel kontrolli automaatselt uuendusi</string>
<string name="open">Ava</string>
<string name="enable_web_debugging">Luba WebView silumine</string>
</resources>

View File

@@ -8,7 +8,7 @@
<string name="home_unsupported_reason">Actuellement, KernelSU ne supporte que les noyaux GKI</string>
<string name="home_kernel">Noyau</string>
<string name="home_fingerprint">Empreinte digitale</string>
<string name="home_selinux_status">Statut de SELinux</string>
<string name="home_selinux_status">Mode SELinux</string>
<string name="selinux_status_disabled">Désactivé</string>
<string name="selinux_status_permissive">Permissive</string>
<string name="selinux_status_unknown">Inconnu</string>
@@ -29,17 +29,17 @@
<string name="reboot">Redémarrer</string>
<string name="install">Installer</string>
<string name="settings">Paramètres</string>
<string name="reboot_bootloader">Redémarrer vers le bootloader</string>
<string name="reboot_userspace">Redémarrage logiciel</string>
<string name="reboot_recovery">Redémarrer en mode récupération</string>
<string name="reboot_bootloader">Redémarrer en mode bootloader</string>
<string name="reboot_userspace">Redémarrage progressif</string>
<string name="reboot_recovery">Redémarrer en mode de récupération</string>
<string name="reboot_edl">Redémarrer en mode EDL</string>
<string name="about">À propos</string>
<string name="module_uninstall_success">%s est désinstallé</string>
<string name="reboot_download">Redémarrer en mode téléchargement</string>
<string name="module_uninstall_success">%s a été désinstallé</string>
<string name="reboot_download">Redémarrer en mode de téléchargement</string>
<string name="module_author">Auteur</string>
<string name="module_uninstall_confirm">Êtes-vous sûr(e) de vouloir désinstaller le module %s\?</string>
<string name="home_learn_kernelsu">Découvrir KernelSU</string>
<string name="module_overlay_fs_not_available">OverlayFS n\'est pas disponible, impossible de faire fonctionner le module !</string>
<string name="module_overlay_fs_not_available">OverlayFS est indisponible, impossible de faire fonctionner les modules!</string>
<string name="refresh">Rafraîchir</string>
<string name="show_system_apps">Afficher les applications système</string>
<string name="hide_system_apps">Masquer les applications système</string>
@@ -50,9 +50,9 @@
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_support_title">Soutenez-nous</string>
<string name="home_click_to_learn_kernelsu">Découvrez comment installer KernelSU et utiliser les modules</string>
<string name="home_support_content">KernelSU est et restera toujours gratuit et open source. Vous pouvez cependant nous témoigner de votre soutien en nous faisant un don.</string>
<string name="about_source_code">Voir le code source sur %1$s<br/>
\nRejoindre notre canal %2$s</string>
<string name="home_support_content">KernelSU est, et restera toujours, gratuit et open source. Vous pouvez cependant nous témoigner de votre soutien en nous faisant un don.</string>
<string name="about_source_code">Voir le code source sur %1$s<br/>
\nRejoindre notre canal %2$s</string>
<string name="profile_template">Modèle</string>
<string name="profile_default">Par défaut</string>
<string name="profile_custom">Personnalisé</string>
@@ -68,7 +68,7 @@
<string name="failed_to_update_app_profile">Échec de la modification du profil d\'application de %s</string>
<string name="profile_umount_modules_summary">L\'activation de cette option permettra à KernelSU de restaurer tous les fichiers modifiés par les modules de cette application.</string>
<string name="settings_umount_modules_default">Démonter les modules par défaut</string>
<string name="settings_umount_modules_default_summary">Valeur globale par défaut pour « Démonter les modules » dans les profils d\'application. Si l\'option est activée, les modifications apportées au système par les modules seront supprimées pour les applications qui n\'ont pas de profil défini.</string>
<string name="settings_umount_modules_default_summary">Valeur globale par défaut pour l\'option « Démonter les modules » dans les profils d\'application. Lorsqu\'elle est activée, les modifications apportées au système par les modules seront supprimées pour les applications qui n\'ont pas de profil défini.</string>
<string name="profile_selinux_domain">Domaine</string>
<string name="profile_selinux_rules">Règles</string>
<string name="module_update">Mettre à jour</string>
@@ -78,8 +78,8 @@
<string name="module_start_downloading">Début du téléchargement de : %s</string>
<string name="force_stop_app">Forcer l\'arrêt</string>
<string name="restart_app">Relancer l\'application</string>
<string name="failed_to_update_sepolicy">Échec de la mise à jour des règles de SELinux pour : %s</string>
<string name="require_kernel_version">La version actuelle (%d) de KernelSU est trop ancienne pour que le gestionnaire fonctionne correctement. Veuillez passer à la version %d ou à une version supérieure !</string>
<string name="failed_to_update_sepolicy">Échec de la mise à jour des règles SELinux pour: %s</string>
<string name="require_kernel_version">La version actuelle de KernelSU (%d) est trop ancienne pour que le gestionnaire fonctionne correctement. Veuillez passer à la version %d ou à une version supérieure!</string>
<string name="app_profile_template_import_success">Importation réussie</string>
<string name="app_profile_export_to_clipboard">Exporter vers le presse-papiers</string>
<string name="app_profile_template_export_empty">Impossible de trouver un modèle local à exporter !</string>
@@ -91,7 +91,7 @@
<string name="app_profile_template_id_invalid">id de modèle invalide</string>
<string name="app_profile_template_sync">Synchroniser les modèles en ligne</string>
<string name="app_profile_template_create">Créer un modèle</string>
<string name="app_profile_template_readonly">en lecture seule</string>
<string name="app_profile_template_readonly">lecture seule</string>
<string name="app_profile_import_export">Importer/exporter</string>
<string name="app_profile_template_save_failed">Échec de l\'enregistrement du modèle</string>
<string name="app_profile_template_edit">Modifier le modèle</string>
@@ -103,4 +103,17 @@
<string name="app_profile_template_delete">Supprimer</string>
<string name="app_profile_template_import_empty">Le presse-papiers est vide !</string>
<string name="app_profile_template_view">Voir le modèle</string>
<string name="settings_check_update_summary">Vérifier automatiquement les mises à jour à l\'ouverture de l\'application</string>
<string name="settings_check_update">Vérifier les mises à jour</string>
<string name="enable_web_debugging">Activer le débogage de WebView</string>
<string name="enable_web_debugging_summary">Peut être utilisé pour déboguer WebUI, n\'activez cette option que si nécessaire.</string>
<string name="grant_root_failed">Échec de l\'octroi des privilèges root!</string>
<string name="open">Ouvert</string>
<string name="direct_install">Installation directe (recommandé)</string>
<string name="select_file">Sélectionner un fichier</string>
<string name="install_inactive_slot">Installer dans l\'emplacement inactif (après OTA)</string>
<string name="install_inactive_slot_warning">Votre appareil sera **FORCÉ** à démarrer sur l\'emplacement inactif actuel après un redémarrage!
\nN\'utilisez cette option qu\'une fois la mise à jour OTA terminée.
\nContinuer?</string>
<string name="install_next">Suivant</string>
</resources>

View File

@@ -80,4 +80,30 @@
<string name="settings_umount_modules_default_summary">Il valore predefinito per \"Scollega moduli\" in Profili App. Se attivato, rimuoverà tutte le modifiche al sistema da parte dei moduli per le applicazioni che non hanno un profilo impostato.</string>
<string name="require_kernel_version">La versione attualmente installata di KernelSU (%d) è troppo vecchia ed il gestore non può funzionare correttamente. Si prega di aggiornare alla versione %d o successiva!</string>
<string name="module_changelog">Registro aggiornamenti</string>
<string name="app_profile_template_create">Crea modello</string>
<string name="app_profile_template_edit">Modifica Modello</string>
<string name="app_profile_template_id">identificativo</string>
<string name="app_profile_template_id_invalid">Identificativo modello non valido</string>
<string name="app_profile_template_name">Nome</string>
<string name="app_profile_template_view">Visualizza modello</string>
<string name="app_profile_template_readonly">Sola lettura</string>
<string name="app_profile_template_id_exist">Esiste già l\'identificativo del modello!</string>
<string name="app_profile_import_export">Importa/Esporta</string>
<string name="app_profile_import_from_clipboard">Importa dagli appunti</string>
<string name="app_profile_export_to_clipboard">Esporta negli appunti</string>
<string name="app_profile_template_export_empty">Impossibile trovare profilo locale da esportare!</string>
<string name="app_profile_template_import_success">Importato con successo</string>
<string name="app_profile_template_sync">Sincronizza i modelli remoti</string>
<string name="app_profile_template_import_empty">Gli appunti sono vuoti!</string>
<string name="grant_root_failed">Impossibile ottenere l\'accesso root!</string>
<string name="settings_profile_template">Modelli Profili App</string>
<string name="settings_profile_template_summary">Gestisci i modelli locali e remoti dei Profili App</string>
<string name="app_profile_template_delete">Elimina</string>
<string name="app_profile_template_description">Descrizione</string>
<string name="app_profile_template_save">Salva</string>
<string name="app_profile_template_save_failed">Impossibile salvare profilo</string>
<string name="open">Apri</string>
<string name="module_changelog_failed">Impossibile reperire il changelog: %s</string>
<string name="settings_check_update">Controlla aggiornamenti</string>
<string name="settings_check_update_summary">Controlla automaticamente la disponibilità di aggiornamenti all\'apertura dell\'applicazione</string>
</resources>

View File

@@ -10,7 +10,7 @@
<string name="home_unsupported">非対応</string>
<string name="home_unsupported_reason">現在、 KernelSU は GKI カーネルにのみ対応しています</string>
<string name="home_kernel">カーネル</string>
<string name="home_manager_version">バージョン</string>
<string name="home_manager_version">アプリのバージョン</string>
<string name="home_fingerprint">Fingerprint</string>
<string name="home_selinux_status">SELinux の状態</string>
<string name="selinux_status_disabled">Disabled</string>
@@ -46,7 +46,7 @@
<string name="safe_mode">セーフモード</string>
<string name="reboot_to_apply">再起動すると有効化されます</string>
<string name="module_magisk_conflict">Magisk と競合しているためモジュールは無効になっています!</string>
<string name="home_learn_kernelsu">KernelSU の詳細</string>
<string name="home_learn_kernelsu">KernelSU について</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/ja_JP/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">KernelSU のインストール方法やモジュールの使い方はこちら</string>
<string name="home_support_title">支援する</string>
@@ -103,4 +103,10 @@
<string name="app_profile_template_delete">消去</string>
<string name="app_profile_template_import_empty">クリップボードが空です!</string>
<string name="app_profile_template_view">テンプレートを表示</string>
<string name="settings_check_update">アップデートを確認</string>
<string name="settings_check_update_summary">アプリを開いたときにアップデートを自動的に確認する</string>
<string name="grant_root_failed">root の付与に失敗しました!</string>
<string name="open">開く</string>
<string name="enable_web_debugging">WebView デバッグを有効にする</string>
<string name="enable_web_debugging_summary">WebUI のデバッグに使用できます。必要な場合にのみ有効にしてください。</string>
</resources>

View File

@@ -82,4 +82,30 @@
<string name="require_kernel_version">De huidige KernelSU-versie %d is te laag om de manager correct te laten functioneren. Upgrade naar versie %d of hoger!</string>
<string name="module_changelog">wijzigings logboek</string>
<string name="settings_profile_template">App-profiel Sjabloon</string>
<string name="app_profile_template_create">Maken Sjabloon</string>
<string name="app_profile_template_edit">Bewerkin Sjabloon</string>
<string name="app_profile_template_id">id</string>
<string name="app_profile_template_id_invalid">Ongeldige sjabloon id</string>
<string name="app_profile_template_name">Naam</string>
<string name="app_profile_template_save">Redde</string>
<string name="app_profile_template_view">Bekijken Sjabloon</string>
<string name="app_profile_template_description">Beschrijving</string>
<string name="settings_profile_template_summary">Beheer lokale en online sjabloon van app-profiel</string>
<string name="app_profile_template_delete">Verwijderen</string>
<string name="app_profile_template_readonly">alleen lezen</string>
<string name="app_profile_template_id_exist">sjabloon id bestaat al!</string>
<string name="app_profile_template_sync">Synchroniseer online-sjablonen</string>
<string name="app_profile_template_save_failed">Mislukt naar opslaan sjabloon</string>
<string name="app_profile_template_import_empty">Klembord is leeg!</string>
<string name="app_profile_import_export">Importeren/Exporteren</string>
<string name="app_profile_import_from_clipboard">Importeren vanaf klembord</string>
<string name="module_changelog_failed">Ophalen van wijzigingslogboek mislukt: %s</string>
<string name="app_profile_export_to_clipboard">Exporteren naar klembord</string>
<string name="settings_check_update">Controleer update</string>
<string name="enable_web_debugging">Schakel WebView-foutopsporing</string>
<string name="enable_web_debugging_summary">Kan worden gebruikt om WebUI te debuggen. Schakel dit alleen in als dat nodig is.</string>
<string name="app_profile_template_export_empty">Kan geen lokale sjabloon vinden om te exporteren!</string>
<string name="app_profile_template_import_success">Succesvol geïmporteerd</string>
<string name="open">Open</string>
<string name="settings_check_update_summary">Controleer automatisch op updates bij het openen van de app</string>
</resources>

View File

@@ -5,7 +5,7 @@
<string name="home_click_to_install">Clique para instalar</string>
<string name="home_working">Em execução</string>
<string name="home_working_version">Versão: %d</string>
<string name="home_superuser_count">Superusuários: %d</string>
<string name="home_superuser_count">SuperUsuários: %d</string>
<string name="home_module_count">Módulos: %d</string>
<string name="home_unsupported">Sem suporte</string>
<string name="home_unsupported_reason">KernelSU suporta apenas kernels GKI agora</string>
@@ -18,8 +18,8 @@
<string name="selinux_status_permissive">Permissivo</string>
<string name="selinux_status_unknown">Desconhecido</string>
<string name="superuser">SuperUsuário</string>
<string name="module_failed_to_enable">Falha ao ativar o módulo: %s</string>
<string name="module_failed_to_disable">Falha ao desativar o módulo: %s</string>
<string name="module_failed_to_enable">Falha ao ativar o módulo %s</string>
<string name="module_failed_to_disable">Falha ao desativar o módulo %s</string>
<string name="module_empty">Nenhum módulo instalado</string>
<string name="module">Módulo</string>
<string name="uninstall">Desinstalar</string>
@@ -33,24 +33,24 @@
<string name="reboot_download">Reiniciar em modo Download</string>
<string name="reboot_edl">Reiniciar em modo EDL</string>
<string name="about">Sobre</string>
<string name="module_uninstall_confirm">Tem certeza de que deseja desinstalar o módulo %s?</string>
<string name="module_uninstall_success">%s foi desinstalado</string>
<string name="module_uninstall_failed">Falha ao desinstalar: %s</string>
<string name="module_uninstall_confirm">Tem certeza que deseja desinstalar o módulo %s?</string>
<string name="module_uninstall_success">%s desinstalado</string>
<string name="module_uninstall_failed">Falha ao desinstalar %s</string>
<string name="module_version">Versão</string>
<string name="module_author">Autor</string>
<string name="module_overlay_fs_not_available">overlayfs não está disponível, o módulo não pode funcionar!</string>
<string name="module_overlay_fs_not_available">Os módulos estão indisponíveis porque OverlayFS está desabilitado pelo kernel!</string>
<string name="refresh">Atualizar</string>
<string name="show_system_apps">Mostrar apps do sistema</string>
<string name="hide_system_apps">Ocultar apps do sistema</string>
<string name="send_log">Reportar registrto</string>
<string name="send_log">Reportar registro</string>
<string name="safe_mode">Modo de segurança</string>
<string name="reboot_to_apply">Reinicie para entrar em vigor</string>
<string name="module_magisk_conflict">Os módulos estão desativados porque estão em conflito com os do Magisk!</string>
<string name="home_learn_kernelsu">Leia mais sobre o KernelSU</string>
<string name="module_magisk_conflict">Os módulos estão indisponíveis devido a um conflito com Magisk!</string>
<string name="home_learn_kernelsu">Saiba mais sobre o KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/pt_BR/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">Aprenda como instalar o KernelSU e usar módulos</string>
<string name="home_click_to_learn_kernelsu">Saiba como instalar o KernelSU e usar os módulos</string>
<string name="home_support_title">Apoie-nos</string>
<string name="home_support_content">KernelSU sempre foi e sempre será, gratuito e de código aberto. No entanto, você pode agradecer enviando uma pequena doação.</string>
<string name="home_support_content">KernelSU sempre foi e sempre será, gratuito e de código aberto. No entanto, você pode nos ajudar enviando uma pequena doação.</string>
<string name="about_source_code"><![CDATA[Veja o código-fonte no %1$s<br/>Junte-se ao nosso canal do %2$s]]></string>
<string name="profile" translatable="false">Perfil do Aplicativo</string>
<string name="profile_default">Padrão</string>
@@ -67,14 +67,14 @@
<string name="profile_umount_modules">Desmontar módulos</string>
<string name="failed_to_update_app_profile">Falha ao atualizar o Perfil do Aplicativo para %s</string>
<string name="settings_umount_modules_default">Desmontar módulos por padrão</string>
<string name="settings_umount_modules_default_summary">O valor padrão global para \"Desmontar módulos\" em Perfis de Aplicativos. Se ativado, ele removerá todas as modificações do módulo no sistema para apps que não possuem um Perfil definido.</string>
<string name="settings_umount_modules_default_summary">O valor padrão global para \"Desmontar módulos\" em Perfil do Aplicativo. Se ativado, ele removerá todas as modificações do módulo no sistema para apps que não possuem um perfil definido.</string>
<string name="profile_umount_modules_summary">Ativar esta opção permitirá que o KernelSU restaure quaisquer arquivos modificados pelos módulos para este app.</string>
<string name="profile_selinux_domain">Domínio</string>
<string name="profile_selinux_rules">Regras</string>
<string name="module_update">Atualizar</string>
<string name="module_downloading">Baixando módulo: %s</string>
<string name="module_start_downloading">Iniciar download: %s</string>
<string name="new_version_available">Nova versão: %s está disponível, clique para atualizar</string>
<string name="module_downloading">Baixando módulo %s</string>
<string name="module_start_downloading">Iniciando download: %s</string>
<string name="new_version_available">Nova versão %s está disponível, clique para atualizar.</string>
<string name="launch_app">Iniciar</string>
<string name="force_stop_app">Forçar parada</string>
<string name="restart_app">Reiniciar</string>
@@ -84,14 +84,14 @@
<string name="app_profile_template_import_success">Importado com sucesso</string>
<string name="app_profile_export_to_clipboard">Exportar para a área de transferência</string>
<string name="app_profile_template_export_empty">Não foi possível encontrar o modelo local para exportar!</string>
<string name="app_profile_template_id_exist">o ID do modelo já existe!</string>
<string name="app_profile_template_id_exist">O ID do modelo já existe!</string>
<string name="app_profile_import_from_clipboard">Importar da área de transferência</string>
<string name="module_changelog_failed">Falha ao buscar o registro de alterações: %s</string>
<string name="app_profile_template_name">Nome</string>
<string name="app_profile_template_id_invalid">ID do modelo inválido</string>
<string name="app_profile_template_sync">Sincronizar modelos online</string>
<string name="app_profile_template_create">Criar modelo</string>
<string name="app_profile_template_readonly">somente leitura</string>
<string name="app_profile_template_readonly">Somente leitura</string>
<string name="app_profile_import_export">Importar/Exportar</string>
<string name="app_profile_template_save_failed">Falha ao salvar o modelo</string>
<string name="app_profile_template_edit">Editar modelo</string>
@@ -99,8 +99,21 @@
<string name="settings_profile_template">Modelo do Perfil do Aplicativo</string>
<string name="app_profile_template_description">Descrição</string>
<string name="app_profile_template_save">Salvar</string>
<string name="settings_profile_template_summary">Gerenciar modelo local e online do Perfil do Aplicativo</string>
<string name="settings_profile_template_summary">Gerencie o modelo local e online do Perfil do Aplicativo</string>
<string name="app_profile_template_delete">Excluir</string>
<string name="app_profile_template_import_empty">A área de transferência está vazia!</string>
<string name="app_profile_template_view">Ver modelo</string>
<string name="settings_check_update">Verificar por atualização</string>
<string name="settings_check_update_summary">Verifique automaticamente se há atualizações ao abrir o app</string>
<string name="grant_root_failed">Falha ao conceder acesso root!</string>
<string name="open">Abrir</string>
<string name="enable_web_debugging">Ativar depuração do WebView</string>
<string name="enable_web_debugging_summary">Pode ser usado para depurar o WebUI. Por favor, ative somente quando necessário.</string>
<string name="select_file">Selecione um arquivo</string>
<string name="direct_install">Instalação direta (recomendada)</string>
<string name="install_inactive_slot">Instalar no slot inativo (após o OTA)</string>
<string name="install_inactive_slot_warning">Seu dispositivo será FORÇADO a inicializar no slot inativo atual após uma reinicialização!
\nSó use esta opção após a conclusão do OTA.
\nDeseja continuar?</string>
<string name="install_next">Próximo</string>
</resources>

View File

@@ -102,4 +102,10 @@
<string name="app_profile_template_delete">Șterge</string>
<string name="app_profile_template_import_empty">Clipboard-ul este gol!</string>
<string name="app_profile_template_view">Vizualizare șablon</string>
<string name="settings_check_update">Verifică actualizarea</string>
<string name="settings_check_update_summary">Se verifică automat actualizările când deschizi aplicația</string>
<string name="enable_web_debugging">Activează depanarea WebView</string>
<string name="enable_web_debugging_summary">Poate fi folosit pentru a depana WebUI, activează numai când este necesar.</string>
<string name="grant_root_failed">Nu s-a acordat acces root!</string>
<string name="open">Deschide</string>
</resources>

View File

@@ -18,7 +18,7 @@
<string name="selinux_status_enforcing">Принудительный</string>
<string name="selinux_status_permissive">Разрешающий</string>
<string name="selinux_status_unknown">Неизвестно</string>
<string name="superuser">Суперпользователь</string>
<string name="superuser">SU пользователь</string>
<!--Don't translate this string!-->
<string name="module_failed_to_enable">Не удалось включить модуль: %s</string>
<string name="module_failed_to_disable">Не удалось отключить модуль: %s</string>
@@ -106,4 +106,17 @@
<string name="app_profile_template_delete">Удалить</string>
<string name="app_profile_template_import_empty">Буфер обмена пуст!</string>
<string name="app_profile_template_view">Просмотр шаблона</string>
<string name="settings_check_update">Проверка обновлений</string>
<string name="settings_check_update_summary">Автоматическая проверка обновлений при открытии приложения</string>
<string name="grant_root_failed">Не удалось выдать root!</string>
<string name="open">Открыть</string>
<string name="enable_web_debugging">Включить отладку WebView</string>
<string name="enable_web_debugging_summary">Используется для отладки веб-интерфейса. Пожалуйста, включайте только при необходимости.</string>
<string name="direct_install">Прямая установка (Рекомендуется)</string>
<string name="install_inactive_slot">Установка в неактивный слот (После OTA)</string>
<string name="install_next">Далее</string>
<string name="select_file">Выбрать файл</string>
<string name="install_inactive_slot_warning">Ваше устройство будет **ПРИНУДИТЕЛЬНО** загружено в текущий неактивный слот после перезагрузки!
\n Используйте эту опцию только после завершения OTA.
\n Продолжать?</string>
</resources>

View File

@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="home_click_to_install">Klikni za namestitev</string>
<string name="home_working">V obdelavi</string>
<string name="home_working_version">Verzija: %d</string>
<string name="home_superuser_count">Superuporabniki: %d</string>
<string name="home_unsupported_reason">KernelSU podpira samo GKI kernele</string>
<string name="home_kernel">Kernel</string>
<string name="home_manager_version">Verzija upravitelja</string>
<string name="home_fingerprint">Prstni odtis</string>
<string name="home_selinux_status">SELinux status</string>
<string name="selinux_status_disabled">Onemogočeno</string>
<string name="selinux_status_unknown">Neznano</string>
<string name="module_failed_to_disable">Napaka pri onemogočanju modula: %s</string>
<string name="module_empty">Ni nameščenih modulov</string>
<string name="module">Modul</string>
<string name="uninstall">Odmesti</string>
<string name="module_install">Namesti</string>
<string name="install">Namesti</string>
<string name="reboot_userspace">Mehki ponovni zagon</string>
<string name="reboot_recovery">Ponovni zagon v Recovery</string>
<string name="reboot_bootloader">Ponovni zagon v Bootloader</string>
<string name="reboot_edl">Ponovni zagon v EDL</string>
<string name="module_uninstall_confirm">Ste prepričani, da želite odstraniti modul %s?</string>
<string name="module_uninstall_success">%s je odmeščen</string>
<string name="module_author">Avtor</string>
<string name="module_overlay_fs_not_available">overlayfs ni na voljo, modul ne more delovati!</string>
<string name="hide_system_apps">Skrij prikaz sistemskih aplikacij</string>
<string name="send_log">Prijavite dnevnik</string>
<string name="home_learn_kernelsu">Naučite se KernelSU</string>
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">Naučite se, kako namestiti KernelSU in uporabiti module</string>
<string name="about_source_code">Glej odprto kodo na %1$s<br/>Pridružite se našem %2$s kanalu</string>
<string name="profile_default">Privzeto</string>
<string name="profile_template">Predloga</string>
<string name="profile_namespace">Imenski prostor vmestitve</string>
<string name="profile_namespace_inherited">Podedovano</string>
<string name="profile_namespace_global">Globalno</string>
<string name="profile_namespace_individual">Pozameznik</string>
<string name="profile_capabilities">Zmožnosti</string>
<string name="profile_umount_modules">Izvrzi module</string>
<string name="settings_umount_modules_default">Po privzetem izvrzi module</string>
<string name="profile_selinux_domain">Domena</string>
<string name="module_update">Posodobitev</string>
<string name="module_downloading">Nalaganje modula: %s</string>
<string name="launch_app">Zaženi</string>
<string name="restart_app">Ponovni zagon</string>
<string name="module_changelog">Dnevnik sprememb</string>
<string name="settings_profile_template">Predloga za aplikacijski profil</string>
<string name="home">Domov</string>
<string name="home_module_count">Moduli: %d</string>
<string name="home_unsupported">Ne podpira</string>
<string name="superuser">SuperUporabnik</string>
<string name="module_failed_to_enable">Napaka pri omogočanju modula: %s</string>
<string name="reboot">Znova zaženi</string>
<string name="settings">Nastavitve</string>
<string name="reboot_download">Ponovni zagon v Download</string>
<string name="about">O nas</string>
<string name="module_version">Verzija</string>
<string name="module_uninstall_failed">Napaka pri odmeščanju: %s</string>
<string name="refresh">Osveži</string>
<string name="safe_mode">Varni način</string>
<string name="reboot_to_apply">Za uveljavitev je potreben ponovni zagon</string>
<string name="show_system_apps">Prikaz sistemskih aplikacij</string>
<string name="module_magisk_conflict">Moduli so onemogočeni, ker so v konfliktu z Magiskovimi!</string>
<string name="home_support_title">Podprite nas</string>
<string name="profile_custom">Po meri</string>
<string name="profile_name">Ime profila</string>
<string name="profile_groups">Skupine</string>
<string name="profile_selinux_context">SELinux kontekst</string>
<string name="home_support_content">KernelSU je, in bo vedno brezplačen in odprtokoden. Kljub temu, nam lahko z donacijo pokažete, da vam je mar.</string>
<string name="failed_to_update_app_profile">Napaka pri posodobitvi aplikacijskega profila za %s</string>
<string name="require_kernel_version">Za pravilno funkionalnost upravitelja je trenutna KernelSU verzija %d prenizka. Potrebna je nadgradnja na verzijo %d ali več!</string>
<string name="settings_umount_modules_default_summary">Globalno privzeta vrednost za \"Izvrzi module\" v aplikacijskih profilih. Če je omogočena, bo to odstranilo vse sistemske modifikacije modulov za aplikacije, ki nimajo nastavljenega profila.</string>
<string name="profile_umount_modules_summary">Omogočanje te opcije bo dovolilo KernelSU, da obnovi vse zaradi modulov spremenjene datoteke za to aplikacijo.</string>
<string name="force_stop_app">Prisilna ustavitev</string>
<string name="profile_selinux_rules">Pravila</string>
<string name="module_start_downloading">Začni z nalaganjem: %s</string>
<string name="new_version_available">Na voljo je nova verzija: %s, kliknite za nadgradnjo</string>
<string name="failed_to_update_sepolicy">Napaka pri posodobitvi SELinux pravil za: %s</string>
<string name="home_not_installed">Ni nameščeno</string>
<string name="selinux_status_enforcing">Enforcing</string>
<string name="selinux_status_permissive">Permissive</string>
<string name="app_profile_template_create">Ustvari predlogo</string>
<string name="app_profile_template_edit">Uredi predlogo</string>
<string name="app_profile_template_id_invalid">Neveljaven id predloge</string>
<string name="app_profile_template_description">Opis</string>
<string name="app_profile_template_save">Shrani</string>
<string name="app_profile_template_delete">Odstrani</string>
<string name="app_profile_template_readonly">le za branje</string>
<string name="app_profile_template_id_exist">id predloge že obstaja!</string>
<string name="app_profile_import_from_clipboard">Uvoz iz odložišča</string>
<string name="app_profile_export_to_clipboard">Izvoz v odložišče</string>
<string name="app_profile_template_export_empty">Lokalna predloga za izvoz ni bila najdena!</string>
<string name="app_profile_template_save_failed">Napaka pri shranjevanju predloge</string>
<string name="app_profile_template_import_empty">Odložišče je prazno!</string>
<string name="settings_profile_template_summary">Upravljaj z lokalnimi in spletnimi predlogami za aplikacijski profil</string>
<string name="app_profile_template_id">id</string>
<string name="app_profile_template_name">Ime</string>
<string name="app_profile_template_view">Ogled predloge</string>
<string name="app_profile_template_import_success">Uvoz uspešen</string>
<string name="app_profile_template_sync">Sinhroniziraj predloge iz spleta</string>
<string name="app_profile_import_export">Uvoz/Izvoz</string>
<string name="module_changelog_failed">Napaka pri pridobivanju dnevnika sprememb: %s</string>
</resources>

View File

@@ -12,4 +12,9 @@
<string name="module_failed_to_disable">మాడ్యూల్‌ని నిలిపివేయడంలో విఫలమైంది: %s</string>
<string name="module_empty">మాడ్యూల్ ఏదీ ఇన్‌స్టాల్ చేయబడలేదు</string>
<string name="home_not_installed">ఇన్‌స్టాల్ చేయలేదు</string>
<string name="home_click_to_install">ఇన్‌స్టాల్ చేయడానికి క్లిక్ చేయండి</string>
<string name="home_working">పని చేస్తోంది</string>
<string name="home_working_version">వెర్షన్: %d</string>
<string name="home_superuser_count">సూపర్‌యూజర్‌లు: %d</string>
<string name="home_module_count">మాడ్యూల్స్: %d</string>
</resources>

View File

@@ -102,4 +102,8 @@
<string name="app_profile_template_import_empty">คลิปบอร์ดว่างเปล่า!</string>
<string name="app_profile_template_view">ดูเทมเพลต</string>
<string name="module_changelog_failed">ดึงข้อมูลบันทึกการเปลี่ยนแปลงล้มเหลว: %s</string>
<string name="open">เปิด</string>
<string name="grant_root_failed">ไม่สามารถให้สิทธิ์รูทได้!</string>
<string name="settings_check_update">ตรวจสอบการอัปเดต</string>
<string name="settings_check_update_summary">ตรวจสอบการอัปเดตโดยอัตโนมัติเมื่อเปิดแอป</string>
</resources>

View File

@@ -2,8 +2,8 @@
<resources>
<string name="app_name" translatable="false">KernelSU</string>
<string name="home">Ana Sayfa</string>
<string name="home_not_installed">Yüklenmedi</string>
<string name="home_click_to_install">Yüklemek için tıklayın</string>
<string name="home_not_installed">Kurulmadı</string>
<string name="home_click_to_install">Kurmak için tıklayın</string>
<string name="home_working">Çalışıyor</string>
<string name="home_working_version">Sürüm: %d</string>
<string name="home_superuser_count">Süper kullanıcılar: %d</string>
@@ -21,11 +21,11 @@
<string name="superuser">Süper kullanıcı</string>
<string name="module_failed_to_enable">Modül etkinleştirilemedi: %s</string>
<string name="module_failed_to_disable">Modül devre dışı bırakılamadı: %s</string>
<string name="module_empty">Yüklü modül yok</string>
<string name="module_empty">Kurulu modül yok</string>
<string name="module">Modül</string>
<string name="uninstall">Kaldır</string>
<string name="module_install">Yükle</string>
<string name="install">Yükle</string>
<string name="module_install">Kur</string>
<string name="install">Kur</string>
<string name="reboot">Cihazı yeniden başlat</string>
<string name="settings">Ayarlar</string>
<string name="reboot_userspace">Hızlı yeniden başlat</string>
@@ -52,7 +52,7 @@
<string name="home_click_to_learn_kernelsu">KernelSU\'nun nasıl kurulacağını ve modüllerin nasıl kullanılacağını öğrenin</string>
<string name="home_support_title">Bizi destekleyin</string>
<string name="home_support_content">KernelSU ücretsiz ve açık kaynaklı bir yazılımdır ve her zaman öyle kalacaktır. Ancak bağış yaparak bize destek olduğunuzu gösterebilirsiniz.</string>
<string name="about_source_code">Kaynak kodunu görüntüleyin: %1$s<br/>%2$s kanalımıza katılın</string>
<string name="about_source_code">%1$s adresinde kaynak kodunu görüntüleyin<br/>%2$s kanalımıza katılın</string>
<string name="profile" translatable="false">Uygulama profili</string>
<string name="profile_default">Varsayılan</string>
<string name="profile_template">Şablon</string>
@@ -104,4 +104,17 @@
<string name="app_profile_template_save_failed">Şablon kaydedilemedi</string>
<string name="app_profile_template_import_empty">Pano boş!</string>
<string name="module_changelog_failed">Değişiklik geçmişi alınamadı: %s</string>
<string name="settings_check_update">Güncellemeleri denetle</string>
<string name="settings_check_update_summary">Uygulamayı açarken güncellemeleri otomatik denetle</string>
<string name="grant_root_failed">Root izni verilemedi!</string>
<string name="open"></string>
<string name="enable_web_debugging">Web Görünümü Hata Ayıklamasını Etkinleştir</string>
<string name="enable_web_debugging_summary">Web kullanıcı arayüzünde hata ayıklamak için kullanılabilir, lütfen yalnızca gerektiğinde etkinleştirin.</string>
<string name="direct_install">Doğrudan Kur (Tavsiye Edilen)</string>
<string name="select_file">Bir Dosya Seçin</string>
<string name="install_inactive_slot">Etkin Olmayan Yuvaya Kur (OTA\'dan Sonra)</string>
<string name="install_inactive_slot_warning">Aygıtınız yeniden başlatıldıktan sonra geçerli etkin olmayan yuvaya **ZORLA** önyükleme yapılacaktır!
\nBu seçeneği yalnızca OTA tamamlandıktan sonra kullanın.
\nDevam edilsin mi?</string>
<string name="install_next">Sonraki</string>
</resources>

View File

@@ -21,10 +21,10 @@
<string name="about_source_code"><![CDATA[Xem mã nguồn tại %1$s<br/>Tham gia kênh %2$s của chúng tôi]]></string>
<string name="module_magisk_conflict">Các mô-đun bị vô hiệu hóa vì chúng xung đột với Magisk!</string>
<string name="module_uninstall_confirm">Bạn có muốn gỡ cài đặt mô-đun %s không\?</string>
<string name="send_log">báo cáo nhật ký</string>
<string name="send_log">Nhật ký báo cáo</string>
<string name="home">Trang chủ</string>
<string name="home_not_installed">Chưa cài đặt</string>
<string name="home_click_to_install">Nhấn để cài dặt</string>
<string name="home_click_to_install">Nhấn để cài đặt</string>
<string name="home_working">Đang hoạt động</string>
<string name="home_working_version">Phiên bản: %d</string>
<string name="home_unsupported">Không được hỗ trợ</string>
@@ -40,19 +40,19 @@
<string name="superuser">SuperUser</string>
<string name="module_failed_to_enable">Không thể kích hoạt mô-đun: %s</string>
<string name="module_failed_to_disable">Không thể vô hiệu hóa mô-đun: %s</string>
<string name="module_empty">Chưa có mô-đun nào được cài đặt</string>
<string name="module_empty">Chưa cài đặt mô-đun nào</string>
<string name="module">Mô-đun</string>
<string name="uninstall">Gỡ cài đặt</string>
<string name="module_install">Cài đặt</string>
<string name="install">Cài đặt</string>
<string name="reboot">Khởi động lại</string>
<string name="settings">Cài đặt</string>
<string name="settings">Thiết đặt</string>
<string name="reboot_userspace">Khởi động mềm</string>
<string name="reboot_recovery">Khởi động lại vào Recovery</string>
<string name="reboot_bootloader">Khởi động lại vào Bootloader</string>
<string name="reboot_download">Khởi động lại vào Download Mode</string>
<string name="reboot_edl">Khởi động lại vào EDL</string>
<string name="about">Về ứng dụng</string>
<string name="about">Giới thiệu</string>
<string name="module_uninstall_success">%s được gỡ cài đặt</string>
<string name="module_uninstall_failed">Lỗi khi gỡ cài đặt: %s</string>
<string name="module_version">Phiên bản</string>
@@ -68,16 +68,16 @@
<string name="home_module_count">Số mô-đun: %d</string>
<string name="profile_selinux_domain">Phạm vi</string>
<string name="profile_selinux_rules">Quy định</string>
<string name="launch_app">Mở</string>
<string name="launch_app">Khởi chạy</string>
<string name="restart_app">Khởi động lại</string>
<string name="profile_namespace">Danh sách mount</string>
<string name="profile_namespace">Gắn namespace</string>
<string name="profile_capabilities">Quyền</string>
<string name="failed_to_update_sepolicy">Không thể cập nhật quy định SELinux cho: %s</string>
<string name="force_stop_app">Buộc dừng</string>
<string name="profile_namespace_inherited">Thừa hưởng</string>
<string name="profile_namespace_global">Chung</string>
<string name="profile_namespace_individual">Riêng</string>
<string name="profile_selinux_context">SELinux context</string>
<string name="profile_selinux_context">Bối cảnh SELinux</string>
<string name="profile_umount_modules">Ngắt mô-đun</string>
<string name="require_kernel_version">KernelSU phiên bản %d quá thấp để trình quản lý hoạt động, hãy cập nhật lên %d hoặc mới hơn!</string>
<string name="app_profile_template_import_success">Đã nhập thành công</string>
@@ -86,7 +86,7 @@
<string name="app_profile_template_id_exist">id bản mẫu đã tồn tại!</string>
<string name="module_changelog">Nhật ký thay đổi</string>
<string name="app_profile_import_from_clipboard">Nhập từ khay nhớ tạm</string>
<string name="module_changelog_failed">Tìm nạp nhật ký thay đổi không thành công: %s</string>
<string name="module_changelog_failed">Không nạp được nhật ký thay đổi: %s</string>
<string name="app_profile_template_name">Tên</string>
<string name="app_profile_template_id_invalid">Id mẫu không hợp lệ</string>
<string name="app_profile_template_sync">Đồng bộ hóa các mẫu trực tuyến</string>
@@ -99,8 +99,14 @@
<string name="app_profile_template_save">Lưu</string>
<string name="settings_profile_template_summary">Quản lý mẫu Hồ sơ Ứng dụng cục bộ và trực tuyến</string>
<string name="app_profile_template_delete">Xóa</string>
<string name="app_profile_template_import_empty">Bảng tạm trống!</string>
<string name="app_profile_template_import_empty">Clipboard trống!</string>
<string name="app_profile_template_view">Xem Bản Mẫu</string>
<string name="app_profile_template_readonly">chỉ đọc</string>
<string name="app_profile_template_id">id</string>
<string name="enable_web_debugging">Bật gỡ lỗi WebView</string>
<string name="enable_web_debugging_summary">Có thể được sử dụng để gỡ lỗi WebUI, vui lòng chỉ bật khi cần.</string>
<string name="grant_root_failed">Không cấp được quyền root!</string>
<string name="settings_check_update">Kiểm tra cập nhật</string>
<string name="settings_check_update_summary">Tự động kiểm tra cập nhật khi mở ứng dụng</string>
<string name="open">Mở</string>
</resources>

View File

@@ -50,7 +50,7 @@
<string name="home_learn_kernelsu_url">https://kernelsu.org/zh_CN/guide/what-is-kernelsu.html</string>
<string name="home_click_to_learn_kernelsu">了解如何安装 KernelSU 以及如何开发模块</string>
<string name="home_support_title">支持开发</string>
<string name="home_support_content">KernelSU 将保持免费开源,向开发者捐赠以表示支持。</string>
<string name="home_support_content">KernelSU 将保持免费开源,向开发者捐赠以表示支持。</string>
<string name="about_source_code"><![CDATA[在 %1$s 查看源码<br/>加入我们的 %2$s 频道<br/>加入我们的 <b><a href="https://pd.qq.com/s/8lipl1brp">QQ 频道</a></b>]]></string>
<string name="profile_default">默认</string>
<string name="profile_template">模版</string>
@@ -102,4 +102,16 @@
<string name="app_profile_template_save_failed">模版保存失败!</string>
<string name="app_profile_template_import_empty">剪切板为空!</string>
<string name="module_changelog_failed">获取更新日志失败:%s</string>
<string name="settings_check_update">检查更新</string>
<string name="settings_check_update_summary">在应用启动后自动检查是否有最新版</string>
<string name="grant_root_failed">获取 root 失败!</string>
<string name="open">打开</string>
<string name="enable_web_debugging">启用 WebView 调试</string>
<string name="enable_web_debugging_summary">可用于调试 WebUI ,请仅在需要时启用。</string>
<string name="direct_install">直接安装(推荐)</string>
<string name="select_file">选择一个文件</string>
<string name="install_inactive_slot">安装到未使用的槽位OTA 后)</string>
<string name="install_inactive_slot_warning">将在重启后强制切换到另一个槽位!\n注意只能在 OTA 更新完成后的重启之前使用。\n确认</string>
<string name="install_next">下一步</string>
<string name="select_file_tip">建议选择 %1$s 分区镜像</string>
</resources>

Some files were not shown because too many files have changed in this diff Show More