Compare commits

...

118 Commits
v24.0 ... v24.3

Author SHA1 Message Date
topjohnwu
2c092ffdef Release Magisk v24.3 2022-03-10 00:32:07 -08:00
topjohnwu
66406227d6 Add v24.3 release notes 2022-03-10 00:24:02 -08:00
topjohnwu
a11d25bb44 Update libsu 2022-03-10 00:00:11 -08:00
VD $ VD171 @ Priv8
2e58d902b7 Update Portuguese Portugal Translation & Fix Portuguese Brazilian Translation by VD171 2022-03-09 20:44:33 -08:00
vvb2060
237794b05c Add root install back 2022-03-09 20:44:11 -08:00
topjohnwu
563a587882 Initialize local variables
Fix #5542
2022-03-09 20:43:42 -08:00
canyie
24505cd111 Prevent destroyed activities from being reused
The adapter will cache a LayoutInflater which refers the current activity, and the ViewModel object will keep alive until activity finished. After activity recreates (e.g. split-screen), it will use the cached LayoutInflater which refers a destroyed activity and crashes. This also is a memory-leak, according to Google's official document, ViewModel shouldn't refer activity. See https://developer.android.com/topic/libraries/architecture/viewmodel

Fix topjohnwu#5413
2022-03-07 01:54:02 -08:00
topjohnwu
0c681cdab4 Check null before dereferencing fds_to_ignore 2022-03-03 21:34:53 -08:00
VD $ VD171 @ Priv8
13ef3058c6 Update Portuguese Brazilian Translation by VD171
Update Portuguese Brazilian Translation by VD171
2022-03-03 10:36:45 -08:00
vvb2060
50b159b43d Add init_boot parition 2022-03-02 22:50:05 -08:00
Rom
8c6c328730 Update French translation 2022-03-02 22:48:24 -08:00
sn-o-w
c9812ddf08 Update Romanian 2022-03-02 22:48:07 -08:00
owen151128
2ef0449c2c Update Korean translation 2022-03-02 22:33:52 -08:00
Ilya Kushnir
5edc750c47 Update RU strings 2022-03-02 22:33:21 -08:00
vvb2060
2f0e396d7f Update gradle 2022-03-02 22:32:35 -08:00
vvb2060
000a163beb Match components which are direct boot unaware 2022-03-02 22:32:35 -08:00
topjohnwu
80dd37ee31 Add missing specialize arguments 2022-03-02 22:01:35 -08:00
topjohnwu
e0b5645064 Revert "Directly use getrandom system call if possible"
This reverts commit e7c82f20e3.
Fix #5516
2022-03-02 19:50:47 -08:00
topjohnwu
e51aacb0b7 Update README 2022-03-01 23:54:39 -08:00
topjohnwu
2d6af94aa0 Release new canary build 2022-03-01 23:53:39 -08:00
topjohnwu
7cfce9ff7a Release Magisk v24.2 2022-03-01 23:35:56 -08:00
topjohnwu
7f088d6241 Add v24.2 release notes 2022-03-01 23:26:44 -08:00
vvb2060
d11038f3de Directly stream apk into install session 2022-03-01 23:05:06 -08:00
vvb2060
6df42a4be7 Handle install failure 2022-03-01 23:05:06 -08:00
Francesco Saltori
7fd111b91f Bring English strings changes to Italian translation 2022-03-01 22:51:07 -08:00
Sirichai Chulee
dd7dc2ec5a Fix typo in thai translation 2022-03-01 22:50:37 -08:00
Vladimír Kubala
86c586d882 Update Slovak translation 2022-03-01 22:50:12 -08:00
Arbri çoçka
66ac6f72fc update Albania translator 2022-03-01 22:49:44 -08:00
CDzungx
f21f448099 Update Vietnamese Translation
Fix, added some translations.
Added note for technicality word in case user don't know the word mean in English like "boot image", "image" is translated to "đĩa ảnh", I can't really understand it if I use Vietnamese lang 😂.
2022-03-01 22:49:29 -08:00
topjohnwu
548d70f30c Mount with original option
Fix #5481, close #5486
2022-03-01 20:09:59 -08:00
topjohnwu
39e714c6d8 Release new canary build 2022-03-01 03:44:21 -08:00
topjohnwu
9968af0785 Move all permission check into daemon.cpp 2022-03-01 03:15:38 -08:00
topjohnwu
be7586137c Reduce C++ wizardry 2022-03-01 03:15:38 -08:00
LoveSy
7999b66c3c Refactor daemon connection 2022-03-01 03:15:38 -08:00
vvb2060
c82a46c1ee Check property before switch mem cgroup 2022-02-28 23:27:23 -08:00
vvb2060
666ab1941f Fix app request fifo wait 2022-02-28 23:26:59 -08:00
topjohnwu
71e37345b4 Update libsu 2022-02-28 20:14:58 -08:00
topjohnwu
e7c82f20e3 Directly use getrandom system call if possible 2022-02-16 23:57:28 -08:00
LoveSy
afa771a980 Set dlopen reserved size to unlimited 2022-02-16 23:05:17 -08:00
vvb2060
0d1de98cca Update zh-rCN translation 2022-02-16 23:04:57 -08:00
vvb2060
02bf7dca01 Check apk before patch 2022-02-16 23:04:39 -08:00
vvb2060
8cc76b1d86 Fix restore dialog 2022-02-16 23:04:19 -08:00
vvb2060
77a275cbcd Show notification when stub is updated to full 2022-02-16 23:04:03 -08:00
vvb2060
3956cbe2d2 ActivityTracker ignore SuRequestActivity 2022-02-16 23:03:42 -08:00
vvb2060
945de8d9a0 Directly stream APK into install session 2022-02-16 23:03:32 -08:00
vvb2060
6dabd3bb2d Abandon unsuccessful session 2022-02-16 23:03:01 -08:00
topjohnwu
4c80808997 Check packages.xml inode to trigger app rescan 2022-02-14 02:57:33 -08:00
topjohnwu
5a39f7cdde Reduce duplicate initialization 2022-02-14 02:28:48 -08:00
topjohnwu
5d400fbe90 Check REQUEST_INSTALL_PACKAGES before actions 2022-02-14 02:15:50 -08:00
topjohnwu
e36596470c Minor adjustments 2022-02-13 20:16:23 -08:00
topjohnwu
668e549208 Refactor APKInstall 2022-02-13 19:54:59 -08:00
topjohnwu
256ff31d11 Show notification after app upgrade 2022-02-13 18:35:35 -08:00
topjohnwu
2414d5d7f5 Minor changes 2022-02-13 14:23:06 -08:00
topjohnwu
b7fc15d399 Code refactoring 2022-02-13 07:24:34 -08:00
topjohnwu
c09b4dabc4 Generate class mapping at runtime 2022-02-13 06:22:42 -08:00
topjohnwu
a4aa4a91a3 Refactor DynLoad 2022-02-13 03:32:11 -08:00
topjohnwu
8f0ea5925a Relaunch process without second process 2022-02-13 02:58:55 -08:00
南宫雪珊
936ad1aa20 Handle download fail
Co-authored-by: topjohnwu <topjohnwu@gmail.com>
2022-02-13 02:30:09 -08:00
topjohnwu
d021bca6ef Prevent app_process from setting umask
Fix #5435
2022-02-11 01:26:24 -08:00
topjohnwu
55ed6109c1 Use dynamic_bitset.emplace_back() 2022-02-11 01:10:26 -08:00
vvb2060
f6d765bf81 Su request activity has no affinity for any task 2022-02-11 01:08:04 -08:00
LoveSy
88e8f2bf83 Proper escape : and \ when binding intent 2022-02-11 01:07:28 -08:00
LoveSy
c849759682 Use magiskboot to patch avd
Fix #5421
2022-02-11 00:25:07 -08:00
topjohnwu
605eae21bc Remove unnecessary read/write
Close #5425
2022-02-11 00:24:12 -08:00
topjohnwu
93eb277a88 Update error messages 2022-02-11 00:01:51 -08:00
LoveSy
8edf556c9e Fix lz4_lg compress 2022-02-10 23:50:19 -08:00
topjohnwu
7fcb63230f Support lz4_legacy archive with multiple magic
Multiple lz4_legacy archives can be directly concatenated
2022-02-10 23:49:17 -08:00
LoveSy
12093a3dad Update elf-cleaner 2022-02-08 00:53:02 -08:00
canyie
ebb0ec6c42 Make xmmap() returns nullptr when fails
In the constructor of mmap_data, there are two possible values when fails: nullptr if fstat() fails, and MAP_FAILED if mmap() fails, but mmap_data treated MAP_FAILED as valid address and crashes.
2022-02-08 00:49:47 -08:00
LoveSy
188546515c Fix UID tracking 2022-02-08 00:49:22 -08:00
topjohnwu
c8990b0f68 Rewrite UID tracking 2022-02-07 02:46:47 -08:00
topjohnwu
7dced4b9d9 Update AGP 2022-02-07 00:19:36 -08:00
topjohnwu
3145e67feb Update data structure 2022-02-07 00:17:07 -08:00
topjohnwu
e9348d9b6a Release new canary build 2022-02-06 07:19:27 -08:00
topjohnwu
1a1b346c05 Fix #5377 2022-02-06 07:12:26 -08:00
Donatello
920d059837 Update italian translation
Added missing string.

Co-authored-by: Madis Otenurm <Madis0@users.noreply.github.com>
2022-02-06 06:51:49 -08:00
xDonatello
bef5c3bd1b Update italian translation 2022-02-06 06:51:49 -08:00
Madis Otenurm
97037f7d03 Update strings.xml 2022-02-06 06:51:11 -08:00
topjohnwu
a7392ed3d7 Fix MULTIUSER_MODE_OWNER_MANAGED 2022-02-06 06:46:09 -08:00
Madis Otenurm
3eb1a7e384 Update Estonian 2022-02-06 05:59:09 -08:00
Arbri çoçka
1ecdc78c2f fix translante in Albania language 2022-02-06 05:58:39 -08:00
孟武.尼德霍格.龍
d279dba37e Update Traditional Chinese Strings
Co-authored-by: LoveSy <631499712@qq.com>
2022-02-06 05:58:03 -08:00
topjohnwu
a4f97fa151 Fix buffer overflow in connect.cpp 2022-02-06 05:52:11 -08:00
LoveSy
ff7ac582f0 Refactor Zygisk loading
Co-authored-by: topjohnwu <topjohnwu@gmail.com>
2022-02-06 00:27:31 -08:00
LoveSy
d2c2456fbe Don't use getmntent_r from system's libc
Fix #5354

Co-authored-by: topjohnwu <topjohnwu@gmail.com>
2022-02-04 23:19:12 -08:00
LoveSy
e9f562a8b7 Fix abuse of fdopendir
After `fdopendir`, the fd is no longer usable. Should dup and
make use of RAII

Co-authored-by: 残页 <31466456+canyie@users.noreply.github.com>
2022-02-04 22:54:34 -08:00
topjohnwu
084e0a73dc Cleanup DownloadService 2022-02-03 03:50:52 -08:00
topjohnwu
10f991b8d0 Directly stream APK into install session 2022-02-03 03:50:52 -08:00
残页
79620c97d1 Invalidate Samsung's persist.sys.zygote.early
Samsung FDE devices with the "persist.sys.zygote.early=true" property will cause Zygote to start before post-fs-data. According to Magisk's document, the post-fs-data phase should always happen before Zygote is started. Features assuming this behavior (like Zygisk and modules that need to control zygote) will not work. To avoid breaking existing modules, we simply invalidate this property to prevent this non-standard behavior from happening

Fix #5299, fix #5328, fix #5308

Co-authored-by: LoveSy <shana@zju.edu.cn>
2022-02-03 00:46:52 -08:00
topjohnwu
ffec9a4ddd Minor changes 2022-02-02 05:06:12 -08:00
topjohnwu
9b18960bbd Getting APK doesn't need ContentProvider 2022-02-02 04:58:31 -08:00
topjohnwu
a009fdbdc3 Fix root service on stub 2022-02-02 04:49:23 -08:00
topjohnwu
c1fc3f373c Proper app relaunch for stub 2022-02-02 04:44:22 -08:00
topjohnwu
f4cf5dc0cd Rename class 2022-02-02 02:50:27 -08:00
topjohnwu
355341f0ab Use AppComponentFactory to replace ClassLoader 2022-02-01 22:43:44 -08:00
topjohnwu
7f65f7d3ca Separate libc.a hacks into its own component 2022-01-31 02:09:08 -08:00
topjohnwu
9fa096c6f4 Add runtime FORTIFY support
Gingerbread libc.a missing symbols
2022-01-31 01:49:37 -08:00
LoveSy
70415a396a Do not filter uid == 1000 for process info 2022-01-30 08:25:24 -08:00
canyie
c921964938 Make sure busybox can be executed recursively
Busybox will execute itself. On some older Samsung devices, when it is located in /data, it will not have rights to execute other programs including itself. We should also relocate busybox in this case to workaround Samsung bullshit.
See topjohnwu/ndk-busybox@bdc8655
Fix the "app doesn't detect installed Magisk" issue in topjohnwu#4174
2022-01-30 08:24:32 -08:00
topjohnwu
3bf47a6838 Update selinux 2022-01-30 08:18:04 -08:00
topjohnwu
d3d28f0623 Update to NDK r23b
Credits: @yujincheng08

Close #5193
2022-01-30 07:11:51 -08:00
topjohnwu
f880b57544 Update README 2022-01-28 04:02:57 -08:00
topjohnwu
32b7a26fa6 Release new canary build 2022-01-28 03:58:53 -08:00
topjohnwu
32fc34f922 Release Magisk v24.1 2022-01-28 03:43:42 -08:00
topjohnwu
b82a393692 Add v24.1 release notes 2022-01-28 03:37:00 -08:00
LoveSy
3c7e792167 Catch PendingIntent.CanceledException thrown from send 2022-01-27 05:29:32 -08:00
LoveSy
0ad66875ab Fix crash when zip is malformat
Co-authored-by: 南宫雪珊 <vvb2060@gmail.com>
Co-authored-by: 残页 <31466456+canyie@users.noreply.github.com>
2022-01-27 05:26:31 -08:00
Arbri çoçka
1191ac2671 update Albania translation 2022-01-27 05:25:13 -08:00
topjohnwu
928b3425e3 Embed module installer in APK 2022-01-27 05:24:05 -08:00
topjohnwu
0726a00e3b Fix download notifications 2022-01-27 05:17:52 -08:00
LoveSy
5a88984d34 Guard synchronizedList's iteration
It's needed to guard a synchronizedList when iterating it
2022-01-27 02:01:30 -08:00
LoveSy
18de60f68c Fix NPE of SuRequestViewModel
countdown timer may have not initialized when backpressed
2022-01-27 02:01:04 -08:00
LoveSy
1893359142 Fix crash when fragment is detached from activity 2022-01-27 01:54:24 -08:00
topjohnwu
f5e5ab2436 Update Android Studio 2022-01-27 01:46:00 -08:00
topjohnwu
ff5ea1a70d Clarify what 64-bit only means 2022-01-26 04:39:14 -08:00
topjohnwu
54ee63a409 Minor install guide changes 2022-01-26 02:55:25 -08:00
topjohnwu
f095606b50 Release new canary build 2022-01-26 02:41:46 -08:00
topjohnwu
e8f31c78d7 Update README 2022-01-26 02:33:22 -08:00
156 changed files with 2934 additions and 1906 deletions

View File

@@ -12,19 +12,19 @@ Some highlight features:
- **MagiskSU**: Provide root access for applications
- **Magisk Modules**: Modify read-only partitions by installing modules
- **MagiskBoot**: The most complete tool for unpacking and repacking Android boot images
- **Zygisk**: Run code in every Android applications' processes
## Downloads
[Github](https://github.com/topjohnwu/Magisk/) is the only source where you can get official Magisk information and downloads.
[![](https://img.shields.io/badge/Magisk-v23.0-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v23.0)
[![](https://img.shields.io/badge/Magisk%20Beta-v23.0-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v23.0)
[![](https://img.shields.io/badge/Magisk-v24.1-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v24.1)
[![](https://img.shields.io/badge/Magisk%20Beta-v24.2-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v24.2)
[![](https://img.shields.io/badge/Magisk-Canary-red)](https://raw.githubusercontent.com/topjohnwu/magisk-files/canary/app-debug.apk)
## Useful Links
- [Installation Instruction](https://topjohnwu.github.io/Magisk/install.html)
- [Frequently Asked Questions](https://topjohnwu.github.io/Magisk/faq.html)
- [Magisk Documentation](https://topjohnwu.github.io/Magisk/)
- [Magisk Troubleshoot Wiki](https://www.didgeridoohan.com/magisk/HomePage) (by [@Didgeridoohan](https://github.com/Didgeridoohan))
@@ -41,15 +41,15 @@ For Magisk app crashes, record and upload the logcat when the crash occurs.
- Magisk builds on any OS Android Studio supports. Install Android Studio and do the initial setups.
- Clone sources: `git clone --recurse-submodules https://github.com/topjohnwu/Magisk.git`
- Install Python 3.6+ \
(Windows only: select **'Add Python to PATH'** in installer, and run `pip install colorama` after install)
(Windows only: select **'Add Python to PATH'** in installer, and run `pip install colorama` after install)
- Configure to use the JDK bundled in Android Studio:
- macOS: `export JAVA_HOME="/Applications/Android Studio.app/Contents/jre/Contents/Home"`
- Linux: `export PATH="/path/to/androidstudio/jre/bin:$PATH"`
- Windows: Add `C:\Path\To\Android Studio\jre\bin` to environment variable `PATH`
- macOS: `export JAVA_HOME="/Applications/Android Studio.app/Contents/jre/Contents/Home"`
- Linux: `export PATH="/path/to/androidstudio/jre/bin:$PATH"`
- Windows: Add `C:\Path\To\Android Studio\jre\bin` to environment variable `PATH`
- Set environment variable `ANDROID_SDK_ROOT` to the Android SDK folder (can be found in Android Studio settings)
- Run `./build.py ndk` to let the script download and install NDK for you
- To start building, run `build.py` to see your options. \
For each action, use `-h` to access help (e.g. `./build.py all -h`)
For each action, use `-h` to access help (e.g. `./build.py all -h`)
- To start development, open the project with Android Studio. The IDE can be used for both app (Kotlin/Java) and native (C++/C) sources.
- Optionally, set custom configs with `config.prop`. A sample `config.prop.sample` is provided.
- To sign APKs and zips with your own private keys, set signing configs in `config.prop`. For more info, check [Google's Documentation](https://developer.android.com/studio/publish/app-signing.html#generate-key).

View File

@@ -57,6 +57,7 @@ android {
kotlinOptions {
jvmTarget = "11"
freeCompilerArgs = listOf("-Xjvm-default=enable")
}
}
@@ -85,7 +86,7 @@ dependencies {
implementation("${bindingAdapter}:${vBAdapt}")
implementation("${bindingAdapter}-recyclerview:${vBAdapt}")
val vLibsu = "3.2.1"
val vLibsu = "4.0.2"
implementation("com.github.topjohnwu.libsu:core:${vLibsu}")
implementation("com.github.topjohnwu.libsu:io:${vLibsu}")
implementation("com.github.topjohnwu.libsu:service:${vLibsu}")
@@ -109,19 +110,19 @@ dependencies {
implementation("androidx.room:room-ktx:${vRoom}")
kapt("androidx.room:room-compiler:${vRoom}")
val vNav = "2.4.0-rc01"
val vNav = "2.5.0-alpha01"
implementation("androidx.navigation:navigation-fragment-ktx:${vNav}")
implementation("androidx.navigation:navigation-ui-ktx:${vNav}")
implementation("androidx.biometric:biometric:1.1.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.2")
implementation("androidx.constraintlayout:constraintlayout:2.1.3")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation("androidx.appcompat:appcompat:1.4.1")
implementation("androidx.preference:preference:1.1.1")
implementation("androidx.preference:preference:1.2.0")
implementation("androidx.recyclerview:recyclerview:1.2.1")
implementation("androidx.fragment:fragment-ktx:1.4.0")
implementation("androidx.fragment:fragment-ktx:1.4.1")
implementation("androidx.transition:transition:1.4.1")
implementation("androidx.core:core-ktx:1.7.0")
implementation("androidx.core:core-splashscreen:1.0.0-beta01")
implementation("com.google.android.material:material:1.4.0")
implementation("com.google.android.material:material:1.5.0")
}

View File

@@ -2,7 +2,10 @@ package com.topjohnwu.magisk;
import static android.os.Build.VERSION.SDK_INT;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.res.AssetManager;
import java.io.File;
@@ -12,28 +15,39 @@ import java.util.Map;
import io.michaelrocks.paranoid.Obfuscate;
@Obfuscate
public class DynAPK {
public class StubApk {
private static File dynDir;
private static Method addAssetPath;
private static File getDynDir(Context c) {
private static File getDynDir(ApplicationInfo info) {
if (dynDir == null) {
final String dataDir;
if (SDK_INT >= 24) {
// Use protected context to allow directBootAware
c = c.createDeviceProtectedStorageContext();
// Use device protected path to allow directBootAware
dataDir = info.deviceProtectedDataDir;
} else {
dataDir = info.dataDir;
}
dynDir = new File(c.getFilesDir().getParent(), "dyn");
dynDir.mkdir();
dynDir = new File(dataDir, "dyn");
dynDir.mkdirs();
}
return dynDir;
}
public static File current(Context c) {
return new File(getDynDir(c), "current.apk");
return new File(getDynDir(c.getApplicationInfo()), "current.apk");
}
public static File current(ApplicationInfo info) {
return new File(getDynDir(info), "current.apk");
}
public static File update(Context c) {
return new File(getDynDir(c), "update.apk");
return new File(getDynDir(c.getApplicationInfo()), "update.apk");
}
public static File update(ApplicationInfo info) {
return new File(getDynDir(info), "update.apk");
}
public static void addAssetPath(AssetManager asset, String path) {
@@ -44,6 +58,14 @@ public class DynAPK {
} catch (Exception ignored) {}
}
public static void restartProcess(Activity activity) {
Intent intent = activity.getPackageManager()
.getLaunchIntentForPackage(activity.getPackageName());
activity.finishAffinity();
activity.startActivity(intent);
Runtime.getRuntime().exit(0);
}
public static class Data {
// Indices of the object array
private static final int STUB_VERSION = 0;

View File

@@ -1,5 +1,6 @@
package com.topjohnwu.magisk.utils;
import static android.content.pm.PackageInstaller.EXTRA_SESSION_ID;
import static android.content.pm.PackageInstaller.EXTRA_STATUS;
import static android.content.pm.PackageInstaller.STATUS_FAILURE_INVALID;
import static android.content.pm.PackageInstaller.STATUS_PENDING_USER_ACTION;
@@ -10,17 +11,17 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInstaller.Session;
import android.content.pm.PackageInstaller.SessionParams;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -28,29 +29,6 @@ import io.michaelrocks.paranoid.Obfuscate;
@Obfuscate
public final class APKInstall {
// @WorkerThread
public static void installapk(Context context, File apk) {
//noinspection InlinedApi
var flag = PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE;
var action = APKInstall.class.getName();
var intent = new Intent(action).setPackage(context.getPackageName());
var pending = PendingIntent.getBroadcast(context, 0, intent, flag);
var installer = context.getPackageManager().getPackageInstaller();
var params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
params.setRequireUserAction(SessionParams.USER_ACTION_NOT_REQUIRED);
}
try (Session session = installer.openSession(installer.createSession(params))) {
OutputStream out = session.openWrite(apk.getName(), 0, apk.length());
try (var in = new FileInputStream(apk); out) {
transfer(in, out);
}
session.commit(pending.getIntentSender());
} catch (IOException e) {
Log.e(APKInstall.class.getSimpleName(), "", e);
}
}
public static void transfer(InputStream in, OutputStream out) throws IOException {
int size = 8192;
@@ -61,61 +39,136 @@ public final class APKInstall {
}
}
public static InstallReceiver register(Context context, String packageName, Runnable onSuccess) {
var receiver = new InstallReceiver(context, packageName, onSuccess);
var filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addDataScheme("package");
context.registerReceiver(receiver, filter);
context.registerReceiver(receiver, new IntentFilter(APKInstall.class.getName()));
public static Session startSession(Context context) {
return startSession(context, null, null, null);
}
public static Session startSession(Context context, String pkg,
Runnable onFailure, Runnable onSuccess) {
var receiver = new InstallReceiver(pkg, onSuccess, onFailure);
context = context.getApplicationContext();
if (pkg != null) {
// If pkg is not null, look for package added event
var filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addDataScheme("package");
context.registerReceiver(receiver, filter);
}
context.registerReceiver(receiver, new IntentFilter(receiver.sessionId));
return receiver;
}
public static class InstallReceiver extends BroadcastReceiver {
private final Context context;
public interface Session {
// @WorkerThread
OutputStream openStream(Context context) throws IOException;
// @WorkerThread
void install(Context context, File apk) throws IOException;
// @WorkerThread @Nullable
Intent waitIntent();
}
private static class InstallReceiver extends BroadcastReceiver implements Session {
private final String packageName;
private final Runnable onSuccess;
private final Runnable onFailure;
private final CountDownLatch latch = new CountDownLatch(1);
private Intent intent = null;
private Intent userAction = null;
private InstallReceiver(Context context, String packageName, Runnable onSuccess) {
this.context = context;
final String sessionId = UUID.randomUUID().toString();
private InstallReceiver(String packageName, Runnable onSuccess, Runnable onFailure) {
this.packageName = packageName;
this.onSuccess = onSuccess;
this.onFailure = onFailure;
}
@Override
public void onReceive(Context c, Intent i) {
if (Intent.ACTION_PACKAGE_ADDED.equals(i.getAction())) {
Uri data = i.getData();
if (data == null || onSuccess == null) return;
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Uri data = intent.getData();
if (data == null)
return;
String pkg = data.getSchemeSpecificPart();
if (pkg.equals(packageName)) {
onSuccess.run();
context.unregisterReceiver(this);
onSuccess(context);
}
return;
} else if (sessionId.equals(intent.getAction())) {
int status = intent.getIntExtra(EXTRA_STATUS, STATUS_FAILURE_INVALID);
switch (status) {
case STATUS_PENDING_USER_ACTION:
userAction = intent.getParcelableExtra(Intent.EXTRA_INTENT);
break;
case STATUS_SUCCESS:
if (packageName == null) {
onSuccess(context);
}
break;
default:
int id = intent.getIntExtra(EXTRA_SESSION_ID, 0);
if (id > 0) {
var installer = context.getPackageManager().getPackageInstaller();
var info = installer.getSessionInfo(id);
if (info != null) {
installer.abandonSession(info.getSessionId());
}
}
if (onFailure != null) {
onFailure.run();
}
context.getApplicationContext().unregisterReceiver(this);
}
latch.countDown();
}
int status = i.getIntExtra(EXTRA_STATUS, STATUS_FAILURE_INVALID);
switch (status) {
case STATUS_PENDING_USER_ACTION:
intent = i.getParcelableExtra(Intent.EXTRA_INTENT);
break;
case STATUS_SUCCESS:
if (onSuccess != null) onSuccess.run();
default:
context.unregisterReceiver(this);
}
latch.countDown();
}
// @WorkerThread @Nullable
private void onSuccess(Context context) {
if (onSuccess != null)
onSuccess.run();
context.getApplicationContext().unregisterReceiver(this);
}
@Override
public Intent waitIntent() {
try {
//noinspection ResultOfMethodCallIgnored
// noinspection ResultOfMethodCallIgnored
latch.await(5, TimeUnit.SECONDS);
} catch (Exception ignored) {
} catch (Exception ignored) {}
return userAction;
}
@Override
public OutputStream openStream(Context context) throws IOException {
// noinspection InlinedApi
var flag = PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE;
var intent = new Intent(sessionId).setPackage(context.getPackageName());
var pending = PendingIntent.getBroadcast(context, 0, intent, flag);
var installer = context.getPackageManager().getPackageInstaller();
var params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
params.setRequireUserAction(SessionParams.USER_ACTION_NOT_REQUIRED);
}
var session = installer.openSession(installer.createSession(params));
var out = session.openWrite(sessionId, 0, -1);
return new FilterOutputStream(out) {
@Override
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
}
@Override
public void close() throws IOException {
super.close();
session.commit(pending.getIntentSender());
session.close();
}
};
}
@Override
public void install(Context context, File apk) throws IOException {
try (var src = new FileInputStream(apk);
var out = openStream(context)) {
transfer(src, out);
}
return intent;
}
}
}

View File

@@ -31,6 +31,7 @@
android:directBootAware="true"
android:excludeFromRecents="true"
android:exported="false"
android:taskAffinity=""
tools:ignore="AppLinkUrlError">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@@ -45,6 +46,7 @@
<intent-filter>
<action android:name="android.intent.action.LOCALE_CHANGED" />
<action android:name="android.intent.action.UID_REMOVED" />
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REPLACED" />

View File

@@ -15,11 +15,11 @@ import com.topjohnwu.magisk.ktx.startAnimations
abstract class BaseFragment<Binding : ViewDataBinding> : Fragment(), ViewModelHolder {
val activity get() = requireActivity() as NavigationActivity<*>
val activity get() = getActivity() as? NavigationActivity<*>
protected lateinit var binding: Binding
protected abstract val layoutRes: Int
private val navigation get() = activity.navigation
private val navigation get() = activity?.navigation
open val snackbarAnchorView: View? get() = null
override fun onCreate(savedInstanceState: Bundle?) {
@@ -41,12 +41,12 @@ abstract class BaseFragment<Binding : ViewDataBinding> : Fragment(), ViewModelHo
override fun onStart() {
super.onStart()
activity.supportActionBar?.subtitle = null
activity?.supportActionBar?.subtitle = null
}
override fun onEventDispatched(event: ViewEvent) = when(event) {
is ContextExecutor -> event(requireContext())
is ActivityExecutor -> event(activity)
is ActivityExecutor -> activity?.let { event(it) } ?: Unit
is FragmentExecutor -> event(this)
else -> Unit
}

View File

@@ -1,23 +1,27 @@
package com.topjohnwu.magisk.arch
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.Manifest.permission.REQUEST_INSTALL_PACKAGES
import android.annotation.SuppressLint
import android.os.Bundle
import androidx.activity.result.contract.ActivityResultContract
import android.widget.Toast
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.databinding.ViewDataBinding
import androidx.lifecycle.lifecycleScope
import com.topjohnwu.magisk.BuildConfig.APPLICATION_ID
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.*
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.JobService
import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.core.tasks.HideAPK
import com.topjohnwu.magisk.di.ServiceLocator
import com.topjohnwu.magisk.ui.theme.Theme
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.superuser.Shell
import java.util.concurrent.CountDownLatch
import kotlinx.coroutines.launch
abstract class BaseMainActivity<Binding : ViewDataBinding> : NavigationActivity<Binding>() {
@@ -25,9 +29,6 @@ abstract class BaseMainActivity<Binding : ViewDataBinding> : NavigationActivity<
private var doPreload = true
}
private val latch = CountDownLatch(1)
private val uninstallPkg = registerForActivityResult(UninstallPackage) { latch.countDown() }
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(Theme.selected.themeRes)
@@ -67,18 +68,28 @@ abstract class BaseMainActivity<Binding : ViewDataBinding> : NavigationActivity<
abstract fun showMainUI(savedInstanceState: Bundle?)
private fun showInvalidStateMessage() {
runOnUiThread {
MagiskDialog(this).apply {
setTitle(R.string.unsupport_nonroot_stub_title)
setMessage(R.string.unsupport_nonroot_stub_msg)
setButton(MagiskDialog.ButtonType.POSITIVE) {
text = R.string.install
onClick { HideAPK.restore(this@BaseMainActivity) }
@SuppressLint("InlinedApi")
private fun showInvalidStateMessage(): Unit = runOnUiThread {
MagiskDialog(this).apply {
setTitle(R.string.unsupport_nonroot_stub_title)
setMessage(R.string.unsupport_nonroot_stub_msg)
setButton(MagiskDialog.ButtonType.POSITIVE) {
text = R.string.install
onClick {
withPermission(REQUEST_INSTALL_PACKAGES) {
if (!it) {
Utils.toast(R.string.install_unknown_denied, Toast.LENGTH_SHORT)
showInvalidStateMessage()
} else {
lifecycleScope.launch {
HideAPK.restore(this@BaseMainActivity)
}
}
}
}
setCancelable(false)
show()
}
setCancelable(false)
show()
}
}
@@ -100,30 +111,17 @@ abstract class BaseMainActivity<Binding : ViewDataBinding> : NavigationActivity<
runCatching {
// Hidden, remove com.topjohnwu.magisk if exist as it could be malware
packageManager.getApplicationInfo(APPLICATION_ID, 0)
Shell.su("(pm uninstall $APPLICATION_ID)& >/dev/null 2>&1").exec()
Shell.cmd("(pm uninstall $APPLICATION_ID)& >/dev/null 2>&1").exec()
}
} else {
if (Config.suManager.isNotEmpty())
Config.suManager = ""
pkg ?: return
if (!Shell.su("(pm uninstall $pkg)& >/dev/null 2>&1").exec().isSuccess) {
uninstallPkg.launch(pkg)
// Wait for the uninstallation to finish
latch.await()
if (!Shell.cmd("(pm uninstall $pkg)& >/dev/null 2>&1").exec().isSuccess) {
// Uninstall through Android API
uninstallAndWait(pkg)
}
}
}
object UninstallPackage : ActivityResultContract<String, Boolean>() {
@Suppress("DEPRECATION")
override fun createIntent(context: Context, input: String): Intent {
val uri = Uri.Builder().scheme("package").opaquePart(input).build()
val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE, uri)
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true)
return intent
}
override fun parseResult(resultCode: Int, intent: Intent?) = resultCode == RESULT_OK
}
}

View File

@@ -1,6 +1,8 @@
package com.topjohnwu.magisk.arch
import android.Manifest
import android.Manifest.permission.REQUEST_INSTALL_PACKAGES
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
import android.annotation.SuppressLint
import androidx.annotation.CallSuper
import androidx.databinding.Bindable
import androidx.databinding.Observable
@@ -78,7 +80,7 @@ abstract class BaseViewModel(
}
inline fun withExternalRW(crossinline callback: () -> Unit) {
withPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) {
withPermission(WRITE_EXTERNAL_STORAGE) {
if (!it) {
SnackbarEvent(R.string.external_rw_permission_denied).publish()
} else {
@@ -87,6 +89,17 @@ abstract class BaseViewModel(
}
}
@SuppressLint("InlinedApi")
inline fun withInstallPermission(crossinline callback: () -> Unit) {
withPermission(REQUEST_INSTALL_PACKAGES) {
if (!it) {
SnackbarEvent(R.string.install_unknown_denied).publish()
} else {
callback()
}
}
}
fun back() = BackPressEvent().publish()
fun <Event : ViewEvent> Event.publish() {

View File

@@ -10,6 +10,7 @@ import androidx.core.content.res.use
import androidx.core.view.WindowCompat
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import com.google.android.material.snackbar.Snackbar
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.base.BaseActivity
@@ -74,6 +75,13 @@ abstract class UIActivity<Binding : ViewDataBinding> : BaseActivity(), ViewModel
binding.root.rootView.accessibilityDelegate = delegate
}
fun showSnackbar(
message: CharSequence,
length: Int = Snackbar.LENGTH_SHORT,
builder: Snackbar.() -> Unit = {}
) = Snackbar.make(snackbarView, message, length)
.setAnchorView(snackbarAnchorView).apply(builder).show()
override fun onResume() {
super.onResume()
viewModel.requestRefresh()

View File

@@ -6,9 +6,10 @@ import android.app.Application
import android.content.Context
import android.content.res.Configuration
import android.os.Bundle
import com.topjohnwu.magisk.DynAPK
import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.core.utils.*
import com.topjohnwu.magisk.di.ServiceLocator
import com.topjohnwu.magisk.ui.surequest.SuRequestActivity
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.internal.UiThreadHandler
import com.topjohnwu.superuser.ipc.RootService
@@ -19,7 +20,7 @@ import kotlin.system.exitProcess
open class App() : Application() {
constructor(o: Any) : this() {
val data = DynAPK.Data(o)
val data = StubApk.Data(o)
// Add the root service name mapping
data.classToComponent[RootRegistry::class.java.name] = data.rootService.name
// Send back the actual root service class
@@ -58,18 +59,18 @@ open class App() : Application() {
refreshLocale()
AppApkPath = if (isRunningAsStub) {
DynAPK.current(base).path
StubApk.current(base).path
} else {
base.packageResourcePath
}
base.resources.patch()
app.registerActivityLifecycleCallbacks(ForegroundTracker)
app.registerActivityLifecycleCallbacks(ActivityTracker)
}
override fun onCreate() {
super.onCreate()
RootRegistry.bindTask = RootService.createBindTask(
RootRegistry.bindTask = RootService.bindOrTask(
intent<RootRegistry>(),
UiThreadHandler.executor,
RootRegistry.Connection
@@ -86,18 +87,18 @@ open class App() : Application() {
}
@SuppressLint("StaticFieldLeak")
object ForegroundTracker : Application.ActivityLifecycleCallbacks {
object ActivityTracker : Application.ActivityLifecycleCallbacks {
@Volatile
var foreground: Activity? = null
val hasForeground get() = foreground != null
override fun onActivityResumed(activity: Activity) {
if (activity is SuRequestActivity) return
foreground = activity
}
override fun onActivityPaused(activity: Activity) {
if (activity is SuRequestActivity) return
foreground = null
}

View File

@@ -37,8 +37,6 @@ object Const {
object ID {
const val JOB_SERVICE_ID = 7
const val UPDATE_NOTIFICATION_CHANNEL = "update"
const val PROGRESS_NOTIFICATION_CHANNEL = "progress"
}
object Url {

View File

@@ -11,14 +11,14 @@ import android.content.res.AssetManager
import android.content.res.Configuration
import android.content.res.Resources
import android.util.DisplayMetrics
import com.topjohnwu.magisk.DynAPK
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.core.utils.syncLocale
import com.topjohnwu.magisk.di.AppContext
lateinit var AppApkPath: String
fun AssetManager.addAssetPath(path: String) = DynAPK.addAssetPath(this, path)
fun AssetManager.addAssetPath(path: String) = StubApk.addAssetPath(this, path)
fun Context.wrap(): Context = if (this is PatchedContext) this else PatchedContext(this)

View File

@@ -2,7 +2,7 @@ package com.topjohnwu.magisk.core
import android.os.Build
import androidx.databinding.ObservableBoolean
import com.topjohnwu.magisk.DynAPK
import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.core.model.UpdateInfo
import com.topjohnwu.magisk.core.utils.net.NetworkObserver
import com.topjohnwu.magisk.data.repository.NetworkService
@@ -16,7 +16,7 @@ val isRunningAsStub get() = Info.stub != null
object Info {
var stub: DynAPK.Data? = null
var stub: StubApk.Data? = null
val EMPTY_REMOTE = UpdateInfo()
var remote = EMPTY_REMOTE

View File

@@ -23,16 +23,20 @@ class JobService : BaseJobService() {
override fun onStartJob(params: JobParameters): Boolean {
val coroutineScope = CoroutineScope(Dispatchers.IO + job)
coroutineScope.launch {
svc.fetchUpdate()?.run {
Info.remote = this
if (Info.env.isActive && BuildConfig.VERSION_CODE < magisk.versionCode)
Notifications.managerUpdate(this@JobService)
}
doWork()
jobFinished(params, false)
}
return false
}
private suspend fun doWork() {
svc.fetchUpdate()?.let {
Info.remote = it
if (Info.env.isActive && BuildConfig.VERSION_CODE < it.magisk.versionCode)
Notifications.updateAvailable(this)
}
}
override fun onStopJob(params: JobParameters): Boolean {
job.cancel()
return false

View File

@@ -5,6 +5,7 @@ import android.content.ContextWrapper
import android.content.Intent
import com.topjohnwu.magisk.core.base.BaseReceiver
import com.topjohnwu.magisk.di.ServiceLocator
import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.GlobalScope
@@ -42,9 +43,16 @@ open class Receiver : BaseReceiver() {
getUid(intent)?.let { rmPolicy(it) }
}
Intent.ACTION_PACKAGE_FULLY_REMOVED -> {
getPkg(intent)?.let { Shell.su("magisk --denylist rm $it").submit() }
getPkg(intent)?.let { Shell.cmd("magisk --denylist rm $it").submit() }
}
Intent.ACTION_LOCALE_CHANGED -> Shortcuts.setupDynamic(context)
Intent.ACTION_MY_PACKAGE_REPLACED -> {
@Suppress("DEPRECATION")
val installer = context.packageManager.getInstallerPackageName(context.packageName)
if (installer == context.packageName) {
Notifications.updateDone(context)
}
}
}
}
}

View File

@@ -1,5 +1,6 @@
package com.topjohnwu.magisk.core.base
import android.Manifest.permission.REQUEST_INSTALL_PACKAGES
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
import android.content.Context
import android.content.Intent
@@ -9,11 +10,16 @@ import android.os.Build
import android.os.Bundle
import androidx.activity.result.contract.ActivityResultContracts.GetContent
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission
import androidx.annotation.WorkerThread
import androidx.appcompat.app.AppCompatActivity
import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.core.utils.RequestInstall
import com.topjohnwu.magisk.core.utils.UninstallPackage
import com.topjohnwu.magisk.core.utils.currentLocale
import com.topjohnwu.magisk.core.wrap
import com.topjohnwu.magisk.ktx.reflectField
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
abstract class BaseActivity : AppCompatActivity() {
@@ -22,6 +28,10 @@ abstract class BaseActivity : AppCompatActivity() {
permissionCallback?.invoke(it)
permissionCallback = null
}
private val requestInstall = registerForActivityResult(RequestInstall()) {
permissionCallback?.invoke(it)
permissionCallback = null
}
private var contentCallback: ((Uri) -> Unit)? = null
private val getContent = registerForActivityResult(GetContent()) {
@@ -29,6 +39,11 @@ abstract class BaseActivity : AppCompatActivity() {
contentCallback = null
}
private var uninstallLatch = CountDownLatch(1)
private val uninstallPkg = registerForActivityResult(UninstallPackage()) {
uninstallLatch.countDown()
}
override fun applyOverrideConfiguration(config: Configuration?) {
// Force applying our preferred local
config?.setLocale(currentLocale)
@@ -57,7 +72,11 @@ abstract class BaseActivity : AppCompatActivity() {
return
}
permissionCallback = callback
requestPermission.launch(permission)
if (permission == REQUEST_INSTALL_PACKAGES) {
requestInstall.launch(Unit)
} else {
requestPermission.launch(permission)
}
}
fun getContent(type: String, callback: (Uri) -> Unit) {
@@ -65,6 +84,13 @@ abstract class BaseActivity : AppCompatActivity() {
getContent.launch(type)
}
@WorkerThread
fun uninstallAndWait(pkg: String) {
uninstallLatch = CountDownLatch(1)
uninstallPkg.launch(pkg)
uninstallLatch.await(3, TimeUnit.SECONDS)
}
override fun recreate() {
startActivity(Intent().setComponent(intent.component))
finish()

View File

@@ -1,170 +1,186 @@
package com.topjohnwu.magisk.core.download
import android.annotation.SuppressLint
import android.app.Notification
import android.app.PendingIntent
import android.app.PendingIntent.*
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.IBinder
import androidx.core.net.toFile
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.ForegroundTracker
import com.topjohnwu.magisk.core.base.BaseService
import com.topjohnwu.magisk.core.intent
import com.topjohnwu.magisk.core.utils.ProgressInputStream
import com.topjohnwu.magisk.di.ServiceLocator
import com.topjohnwu.magisk.ktx.synchronized
import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.core.*
import com.topjohnwu.magisk.core.tasks.HideAPK
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
import com.topjohnwu.magisk.ktx.copyAndClose
import com.topjohnwu.magisk.ktx.forEach
import com.topjohnwu.magisk.ktx.withStreams
import com.topjohnwu.magisk.ktx.writeTo
import com.topjohnwu.magisk.utils.APKInstall
import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.magisk.view.Notifications.mgr
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import okhttp3.ResponseBody
import timber.log.Timber
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream
class DownloadService : BaseService() {
class DownloadService : NotificationService() {
private val hasNotifications get() = notifications.isNotEmpty()
private val notifications = HashMap<Int, Notification.Builder>().synchronized()
private val job = Job()
val service get() = ServiceLocator.networkService
// -- Service overrides
override fun onBind(intent: Intent?): IBinder? = null
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
intent.getParcelableExtra<Subject>(SUBJECT_KEY)?.let { doDownload(it) }
intent.getParcelableExtra<Subject>(SUBJECT_KEY)?.let { download(it) }
return START_NOT_STICKY
}
override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
notifications.forEach { mgr.cancel(it.key) }
notifications.clear()
}
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
// -- Download logic
private fun doDownload(subject: Subject) {
private fun download(subject: Subject) {
update(subject.notifyId)
val coroutineScope = CoroutineScope(job + Dispatchers.IO)
coroutineScope.launch {
try {
val stream = service.fetchFile(subject.url).toProgressStream(subject)
when (subject) {
is Subject.Manager -> handleAPK(subject, stream)
else -> stream.toModule(subject.file, service.fetchInstaller().byteStream())
is Subject.App -> handleApp(stream, subject)
is Subject.Module -> handleModule(stream, subject.file)
}
if (ForegroundTracker.hasForeground) {
val activity = ActivityTracker.foreground
if (activity != null && subject.autoLaunch) {
remove(subject.notifyId)
subject.pendingIntent(this@DownloadService)?.send()
subject.pendingIntent(activity)?.send()
} else {
notifyFinish(subject)
}
subject.postDownload?.invoke()
if (!hasNotifications)
stopSelf()
} catch (e: IOException) {
} catch (e: Exception) {
Timber.e(e)
notifyFail(subject)
}
}
}
private fun ResponseBody.toProgressStream(subject: Subject): InputStream {
val max = contentLength()
val total = max.toFloat() / 1048576
val id = subject.notifyId
private suspend fun handleApp(stream: InputStream, subject: Subject.App) {
fun writeTee(output: OutputStream) {
val uri = MediaStoreUtils.getFile("${subject.title}.apk").uri
val external = uri.outputStream()
stream.copyAndClose(TeeOutputStream(external, output))
}
update(id) { it.setContentTitle(subject.title) }
if (isRunningAsStub) {
val updateApk = StubApk.update(this)
try {
// Download full APK to stub update path
writeTee(updateApk.outputStream())
return ProgressInputStream(byteStream()) {
val progress = it.toFloat() / 1048576
update(id) { notification ->
if (max > 0) {
broadcast(progress / total, subject)
notification
.setProgress(max.toInt(), it.toInt(), false)
.setContentText("%.2f / %.2f MB".format(progress, total))
if (Info.stub!!.version < subject.stub.versionCode) {
// Also upgrade stub
update(subject.notifyId) {
it.setProgress(0, 0, true)
.setContentTitle(getString(R.string.hide_app_title))
.setContentText("")
}
// Download
val apk = subject.file.toFile()
service.fetchFile(subject.stub.link).byteStream().writeTo(apk)
// Patch and install
val session = APKInstall.startSession(this)
session.openStream(this).use {
val label = applicationInfo.nonLocalizedLabel
if (!HideAPK.patch(this, apk, it, packageName, label)) {
throw IOException("HideAPK patch error")
}
}
apk.delete()
subject.intent = session.waitIntent()
} else {
broadcast(-1f, subject)
notification.setContentText("%.2f MB / ??".format(progress))
ActivityTracker.foreground?.let {
// Relaunch the process if we are foreground
StubApk.restartProcess(it)
} ?: run {
// Or else kill the current process after posting notification
subject.intent = Notifications.selfLaunchIntent(this)
subject.postDownload = { Runtime.getRuntime().exit(0) }
}
return
}
} catch (e: Exception) {
// If any error occurred, do not let stub load the new APK
updateApk.delete()
throw e
}
} else {
val session = APKInstall.startSession(this)
writeTee(session.openStream(this))
subject.intent = session.waitIntent()
}
}
private fun handleModule(src: InputStream, file: Uri) {
val input = ZipInputStream(src.buffered())
val output = ZipOutputStream(file.outputStream().buffered())
withStreams(input, output) { zin, zout ->
zout.putNextEntry(ZipEntry("META-INF/"))
zout.putNextEntry(ZipEntry("META-INF/com/"))
zout.putNextEntry(ZipEntry("META-INF/com/google/"))
zout.putNextEntry(ZipEntry("META-INF/com/google/android/"))
zout.putNextEntry(ZipEntry("META-INF/com/google/android/update-binary"))
assets.open("module_installer.sh").copyTo(zout)
zout.putNextEntry(ZipEntry("META-INF/com/google/android/updater-script"))
zout.write("#MAGISK\n".toByteArray())
zin.forEach { entry ->
val path = entry.name
if (path.isNotEmpty() && !path.startsWith("META-INF")) {
zout.putNextEntry(ZipEntry(path))
if (!entry.isDirectory) {
zin.copyTo(zout)
}
}
}
}
}
// --- Notification management
private fun notifyFail(subject: Subject) = finalNotify(subject.notifyId) {
broadcast(-2f, subject)
it.setContentText(getString(R.string.download_file_error))
.setSmallIcon(android.R.drawable.stat_notify_error)
.setOngoing(false)
}
private fun notifyFinish(subject: Subject) = finalNotify(subject.notifyId) {
broadcast(1f, subject)
it.setContentIntent(subject.pendingIntent(this))
.setContentTitle(subject.title)
.setContentText(getString(R.string.download_complete))
.setSmallIcon(android.R.drawable.stat_sys_download_done)
.setProgress(0, 0, false)
.setOngoing(false)
.setAutoCancel(true)
}
private fun finalNotify(id: Int, editor: (Notification.Builder) -> Unit): Int {
val notification = remove(id)?.also(editor) ?: return -1
val newId = Notifications.nextId()
mgr.notify(newId, notification.build())
return newId
}
private fun create() = Notifications.progress(this, "")
fun update(id: Int, editor: (Notification.Builder) -> Unit = {}) {
val wasEmpty = !hasNotifications
val notification = notifications.getOrPut(id, ::create).also(editor)
if (wasEmpty)
updateForeground()
else
mgr.notify(id, notification.build())
}
private fun remove(id: Int): Notification.Builder? {
val n = notifications.remove(id)?.also { updateForeground() }
mgr.cancel(id)
return n
}
private fun updateForeground() {
if (hasNotifications) {
val (id, notification) = notifications.entries.first()
startForeground(id, notification.build())
} else {
stopForeground(false)
private class TeeOutputStream(
private val o1: OutputStream,
private val o2: OutputStream
) : OutputStream() {
override fun write(b: Int) {
o1.write(b)
o2.write(b)
}
override fun write(b: ByteArray?, off: Int, len: Int) {
o1.write(b, off, len)
o2.write(b, off, len)
}
override fun close() {
o1.close()
o2.close()
}
}
companion object {
private const val SUBJECT_KEY = "download_subject"
private const val SUBJECT_KEY = "subject"
private const val REQUEST_CODE = 1
private val progressBroadcast = MutableLiveData<Pair<Float, Subject>?>()
fun observeProgress(owner: LifecycleOwner, callback: (Float, Subject) -> Unit) {
progressBroadcast.value = null
progressBroadcast.observe(owner) {
@@ -173,10 +189,6 @@ class DownloadService : BaseService() {
}
}
private fun broadcast(progress: Float, subject: Subject) {
progressBroadcast.postValue(progress to subject)
}
private fun intent(context: Context, subject: Subject) =
context.intent<DownloadService>().putExtra(SUBJECT_KEY, subject)
@@ -200,5 +212,4 @@ class DownloadService : BaseService() {
}
}
}
}

View File

@@ -1,77 +0,0 @@
package com.topjohnwu.magisk.core.download
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Intent
import androidx.core.content.getSystemService
import androidx.core.net.toFile
import com.topjohnwu.magisk.DynAPK
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.ForegroundTracker
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.core.tasks.HideAPK
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
import com.topjohnwu.magisk.ktx.copyAndClose
import com.topjohnwu.magisk.ktx.writeTo
import java.io.File
import java.io.InputStream
import java.io.OutputStream
private class TeeOutputStream(
private val o1: OutputStream,
private val o2: OutputStream
) : OutputStream() {
override fun write(b: Int) {
o1.write(b)
o2.write(b)
}
override fun write(b: ByteArray?, off: Int, len: Int) {
o1.write(b, off, len)
o2.write(b, off, len)
}
override fun close() {
o1.close()
o2.close()
}
}
suspend fun DownloadService.handleAPK(subject: Subject.Manager, stream: InputStream) {
fun write(output: OutputStream) {
val external = subject.externalFile.outputStream()
stream.copyAndClose(TeeOutputStream(external, output))
}
if (isRunningAsStub) {
val apk = subject.file.toFile()
val id = subject.notifyId
write(DynAPK.update(this).outputStream())
if (Info.stub!!.version < subject.stub.versionCode) {
// Also upgrade stub
update(id) {
it.setProgress(0, 0, true)
.setContentTitle(getString(R.string.hide_app_title))
.setContentText("")
}
service.fetchFile(subject.stub.link).byteStream().writeTo(apk)
val patched = File(apk.parent, "patched.apk")
HideAPK.patch(this, apk, patched, packageName, applicationInfo.nonLocalizedLabel)
apk.delete()
patched.renameTo(apk)
} else {
val intent = packageManager.getLaunchIntentForPackage(packageName)
intent!!.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
//noinspection InlinedApi
val flag = PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
val pending = PendingIntent.getActivity(this, id, intent, flag)
if (ForegroundTracker.hasForeground) {
val alarm = getSystemService<AlarmManager>()
alarm!!.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, pending)
}
stopSelf()
Runtime.getRuntime().exit(0)
}
} else {
write(subject.file.outputStream())
}
}

View File

@@ -1,38 +0,0 @@
package com.topjohnwu.magisk.core.download
import android.net.Uri
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
import com.topjohnwu.magisk.ktx.forEach
import com.topjohnwu.magisk.ktx.withStreams
import java.io.InputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream
fun InputStream.toModule(file: Uri, installer: InputStream) {
val input = ZipInputStream(buffered())
val output = ZipOutputStream(file.outputStream().buffered())
withStreams(input, output) { zin, zout ->
zout.putNextEntry(ZipEntry("META-INF/"))
zout.putNextEntry(ZipEntry("META-INF/com/"))
zout.putNextEntry(ZipEntry("META-INF/com/google/"))
zout.putNextEntry(ZipEntry("META-INF/com/google/android/"))
zout.putNextEntry(ZipEntry("META-INF/com/google/android/update-binary"))
installer.copyTo(zout)
zout.putNextEntry(ZipEntry("META-INF/com/google/android/updater-script"))
zout.write("#MAGISK\n".toByteArray(charset("UTF-8")))
zin.forEach { entry ->
val path = entry.name
if (path.isNotEmpty() && !path.startsWith("META-INF")) {
zout.putNextEntry(ZipEntry(path))
if (!entry.isDirectory) {
zin.copyTo(zout)
}
}
}
}
}

View File

@@ -0,0 +1,113 @@
package com.topjohnwu.magisk.core.download
import android.app.Notification
import android.content.Intent
import android.os.IBinder
import androidx.lifecycle.MutableLiveData
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.base.BaseService
import com.topjohnwu.magisk.core.utils.ProgressInputStream
import com.topjohnwu.magisk.di.ServiceLocator
import com.topjohnwu.magisk.ktx.synchronized
import com.topjohnwu.magisk.view.Notifications
import okhttp3.ResponseBody
import java.io.InputStream
open class NotificationService : BaseService() {
private val notifications = HashMap<Int, Notification.Builder>().synchronized()
protected val hasNotifications get() = notifications.isNotEmpty()
protected val service get() = ServiceLocator.networkService
override fun onBind(intent: Intent?): IBinder? = null
override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
notifications.forEach { Notifications.mgr.cancel(it.key) }
notifications.clear()
}
protected fun ResponseBody.toProgressStream(subject: Subject): InputStream {
val max = contentLength()
val total = max.toFloat() / 1048576
val id = subject.notifyId
update(id) { it.setContentTitle(subject.title) }
return ProgressInputStream(byteStream()) {
val progress = it.toFloat() / 1048576
update(id) { notification ->
if (max > 0) {
broadcast(progress / total, subject)
notification
.setProgress(max.toInt(), it.toInt(), false)
.setContentText("%.2f / %.2f MB".format(progress, total))
} else {
broadcast(-1f, subject)
notification.setContentText("%.2f MB / ??".format(progress))
}
}
}
}
private fun finalNotify(id: Int, editor: (Notification.Builder) -> Unit): Int {
val notification = remove(id)?.also(editor) ?: return -1
val newId = Notifications.nextId()
Notifications.mgr.notify(newId, notification.build())
return newId
}
protected fun notifyFail(subject: Subject) = finalNotify(subject.notifyId) {
broadcast(-2f, subject)
it.setContentText(getString(R.string.download_file_error))
.setSmallIcon(android.R.drawable.stat_notify_error)
.setOngoing(false)
}
protected fun notifyFinish(subject: Subject) = finalNotify(subject.notifyId) {
broadcast(1f, subject)
it.setContentTitle(subject.title)
.setContentText(getString(R.string.download_complete))
.setSmallIcon(android.R.drawable.stat_sys_download_done)
.setProgress(0, 0, false)
.setOngoing(false)
.setAutoCancel(true)
subject.pendingIntent(this)?.let { intent -> it.setContentIntent(intent) }
}
private fun create() = Notifications.progress(this, "")
private fun updateForeground() {
if (hasNotifications) {
val (id, notification) = notifications.entries.first()
startForeground(id, notification.build())
} else {
stopForeground(false)
}
}
protected fun update(id: Int, editor: (Notification.Builder) -> Unit = {}) {
val wasEmpty = !hasNotifications
val notification = notifications.getOrPut(id, ::create).also(editor)
if (wasEmpty)
updateForeground()
else
Notifications.mgr.notify(id, notification.build())
}
protected fun remove(id: Int): Notification.Builder? {
val n = notifications.remove(id)?.also { updateForeground() }
Notifications.mgr.cancel(id)
return n
}
companion object {
@JvmStatic
protected val progressBroadcast = MutableLiveData<Pair<Float, Subject>?>()
private fun broadcast(progress: Float, subject: Subject) {
progressBroadcast.postValue(progress to subject)
}
}
}

View File

@@ -6,7 +6,6 @@ import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Parcelable
import androidx.core.net.toFile
import androidx.core.net.toUri
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.model.MagiskJson
@@ -16,7 +15,6 @@ import com.topjohnwu.magisk.core.utils.MediaStoreUtils
import com.topjohnwu.magisk.di.AppContext
import com.topjohnwu.magisk.ktx.cachedFile
import com.topjohnwu.magisk.ui.flash.FlashFragment
import com.topjohnwu.magisk.utils.APKInstall
import com.topjohnwu.magisk.view.Notifications
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize
@@ -34,6 +32,8 @@ sealed class Subject : Parcelable {
abstract val file: Uri
abstract val title: String
abstract val notifyId: Int
open val autoLaunch: Boolean get() = true
open val postDownload: (() -> Unit)? get() = null
abstract fun pendingIntent(context: Context): PendingIntent?
@@ -45,20 +45,19 @@ sealed class Subject : Parcelable {
) : Subject() {
override val url: String get() = module.zipUrl
override val title: String get() = module.downloadFilename
override val autoLaunch: Boolean get() = action == Action.Flash
@IgnoredOnParcel
override val file by lazy {
MediaStoreUtils.getFile(title).uri
}
override fun pendingIntent(context: Context) = when (action) {
Action.Flash -> FlashFragment.installIntent(context, file)
else -> null
}
override fun pendingIntent(context: Context) =
FlashFragment.installIntent(context, file)
}
@Parcelize
class Manager(
class App(
private val json: MagiskJson = Info.remote.magisk,
val stub: StubJson = Info.remote.stub,
override val notifyId: Int = Notifications.nextId()
@@ -71,14 +70,12 @@ sealed class Subject : Parcelable {
cachedFile("manager.apk")
}
val externalFile get() = MediaStoreUtils.getFile("$title.apk").uri
@IgnoredOnParcel
override var postDownload: (() -> Unit)? = null
override fun pendingIntent(context: Context): PendingIntent {
val receiver = APKInstall.register(context, null, null)
APKInstall.installapk(context, file.toFile())
val intent = receiver.waitIntent() ?: Intent()
return intent.toPending(context)
}
@IgnoredOnParcel
var intent: Intent? = null
override fun pendingIntent(context: Context) = intent?.toPending(context)
}
@SuppressLint("InlinedApi")

View File

@@ -18,7 +18,7 @@ class Query(private val _query: String) {
suspend inline fun <R : Any> query(crossinline mapper: (Map<String, String>) -> R?): List<R> =
withContext(Dispatchers.Default) {
Shell.su(query).await().out.map { line ->
Shell.cmd(query).await().out.map { line ->
async {
line.split("\\|".toRegex())
.map { it.split("=", limit = 2) }
@@ -32,7 +32,7 @@ class Query(private val _query: String) {
suspend inline fun query() = query { it }
suspend inline fun commit() = Shell.su(query).to(null).await()
suspend inline fun commit() = Shell.cmd(query).to(null).await()
}
class Delete : Query.Builder {

View File

@@ -46,15 +46,15 @@ data class LocalModule(
if (enable) {
disableFile.delete()
if (Const.Version.atLeast_21_2())
Shell.su("copy_sepolicy_rules").submit()
Shell.cmd("copy_sepolicy_rules").submit()
else
Shell.su("mkdir -p $dir", "cp -af $ruleFile $dir").submit()
Shell.cmd("mkdir -p $dir", "cp -af $ruleFile $dir").submit()
} else {
!disableFile.createNewFile()
if (Const.Version.atLeast_21_2())
Shell.su("copy_sepolicy_rules").submit()
Shell.cmd("copy_sepolicy_rules").submit()
else
Shell.su("rm -rf $dir").submit()
Shell.cmd("rm -rf $dir").submit()
}
}
@@ -65,15 +65,15 @@ data class LocalModule(
if (updateFile.exists()) return
removeFile.createNewFile()
if (Const.Version.atLeast_21_2())
Shell.su("copy_sepolicy_rules").submit()
Shell.cmd("copy_sepolicy_rules").submit()
else
Shell.su("rm -rf $PERSIST/$id").submit()
Shell.cmd("rm -rf $PERSIST/$id").submit()
} else {
removeFile.delete()
if (Const.Version.atLeast_21_2())
Shell.su("copy_sepolicy_rules").submit()
Shell.cmd("copy_sepolicy_rules").submit()
else
Shell.su("cp -af $ruleFile $PERSIST/$id").submit()
Shell.cmd("cp -af $ruleFile $PERSIST/$id").submit()
}
}
@@ -103,7 +103,7 @@ data class LocalModule(
init {
runCatching {
parseProps(Shell.su("dos2unix < $path/module.prop").exec().out)
parseProps(Shell.cmd("dos2unix < $path/module.prop").exec().out)
}
if (id.isEmpty()) {

View File

@@ -36,7 +36,7 @@ class SuRequestHandler(
// Never allow com.topjohnwu.magisk (could be malware)
if (policy.packageName == BuildConfig.APPLICATION_ID) {
Shell.su("(pm uninstall ${BuildConfig.APPLICATION_ID})& >/dev/null 2>&1").exec()
Shell.cmd("(pm uninstall ${BuildConfig.APPLICATION_ID})& >/dev/null 2>&1").exec()
return false
}

View File

@@ -63,7 +63,7 @@ open class FlashZip(
console.add("- Installing ${mUri.displayName}")
return Shell.su("sh $installDir/update-binary dummy 1 \'$zipFile\'")
return Shell.cmd("sh $installDir/update-binary dummy 1 \'$zipFile\'")
.to(console, logs).exec().isSuccess
}
@@ -79,7 +79,7 @@ open class FlashZip(
Timber.e(e)
false
} finally {
Shell.su("cd /", "rm -rf $installDir ${Const.TMPDIR}").submit()
Shell.cmd("cd /", "rm -rf $installDir ${Const.TMPDIR}").submit()
}
}
}

View File

@@ -5,8 +5,8 @@ import android.content.Context
import android.content.Intent
import android.widget.Toast
import com.topjohnwu.magisk.BuildConfig.APPLICATION_ID
import com.topjohnwu.magisk.DynAPK
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Info
@@ -14,6 +14,7 @@ import com.topjohnwu.magisk.core.Provider
import com.topjohnwu.magisk.core.utils.AXML
import com.topjohnwu.magisk.core.utils.Keygen
import com.topjohnwu.magisk.di.ServiceLocator
import com.topjohnwu.magisk.ktx.await
import com.topjohnwu.magisk.ktx.writeTo
import com.topjohnwu.magisk.signing.JarMap
import com.topjohnwu.magisk.signing.SignApk
@@ -21,18 +22,19 @@ import com.topjohnwu.magisk.utils.APKInstall
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Runnable
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.OutputStream
import java.security.SecureRandom
object HideAPK {
private const val ALPHA = "abcdefghijklmnopqrstuvwxyz"
private const val ALPHADOTS = "$ALPHA....."
private const val APP_NAME = "Magisk"
private const val ANDROID_MANIFEST = "AndroidManifest.xml"
// Some arbitrary limit
@@ -65,27 +67,29 @@ object HideAPK {
fun patch(
context: Context,
apk: File, out: File,
apk: File, out: OutputStream,
pkg: String, label: CharSequence
): Boolean {
val info = context.packageManager.getPackageArchiveInfo(apk.path, 0) ?: return false
val name = info.applicationInfo.nonLocalizedLabel.toString()
try {
val jar = JarMap.open(apk, true)
val je = jar.getJarEntry(ANDROID_MANIFEST)
val xml = AXML(jar.getRawData(je))
JarMap.open(apk, true).use { jar ->
val je = jar.getJarEntry(ANDROID_MANIFEST)
val xml = AXML(jar.getRawData(je))
if (!xml.findAndPatch(APPLICATION_ID to pkg, APP_NAME to label.toString()))
return false
if (!xml.findAndPatch(APPLICATION_ID to pkg, name to label.toString()))
return false
// Write apk changes
jar.getOutputStream(je).write(xml.bytes)
val keys = Keygen(context)
SignApk.sign(keys.cert, keys.key, jar, FileOutputStream(out))
// Write apk changes
jar.getOutputStream(je).use { it.write(xml.bytes) }
val keys = Keygen(context)
SignApk.sign(keys.cert, keys.key, jar, out)
return true
}
} catch (e: Exception) {
Timber.e(e)
return false
}
return true
}
private fun launchApp(activity: Activity, pkg: String) {
@@ -100,7 +104,7 @@ object HideAPK {
activity.finish()
}
private suspend fun patchAndHide(activity: Activity, label: String): Boolean {
private suspend fun patchAndHide(activity: Activity, label: String, onFailure: Runnable): Boolean {
val stub = File(activity.cacheDir, "stub.apk")
try {
svc.fetchFile(Info.remote.stub.link).byteStream().writeTo(stub)
@@ -108,7 +112,8 @@ object HideAPK {
Timber.e(e)
stub.createNewFile()
val cmd = "\$MAGISKBIN/magiskinit -x manager ${stub.path}"
if (!Shell.su(cmd).exec().isSuccess) return false
if (!Shell.cmd(cmd).exec().isSuccess)
return false
}
// Generate a new random package name and signature
@@ -116,18 +121,24 @@ object HideAPK {
val pkg = genPackageName()
Config.keyStoreRaw = ""
if (!patch(activity, stub, repack, pkg, label))
if (!patch(activity, stub, FileOutputStream(repack), pkg, label))
return false
// Install and auto launch app
val receiver = APKInstall.register(activity, pkg) {
val session = APKInstall.startSession(activity, pkg, onFailure) {
launchApp(activity, pkg)
}
val cmd = "adb_pm_install $repack ${activity.applicationInfo.uid}"
if (!Shell.su(cmd).exec().isSuccess) {
APKInstall.installapk(activity, repack)
receiver.waitIntent()?.let { activity.startActivity(it) }
if (Shell.su(cmd).exec().isSuccess) return true
try {
session.install(activity, repack)
} catch (e: IOException) {
Timber.e(e)
return false
}
session.waitIntent()?.let { activity.startActivity(it) } ?: return false
return true
}
@@ -139,33 +150,45 @@ object HideAPK {
setCancelable(false)
show()
}
val result = withContext(Dispatchers.IO) {
patchAndHide(activity, label)
}
if (!result) {
val onFailure = Runnable {
dialog.dismiss()
Utils.toast(R.string.failure, Toast.LENGTH_LONG)
}
val success = withContext(Dispatchers.IO) {
patchAndHide(activity, label, onFailure)
}
if (!success) onFailure.run()
}
@Suppress("DEPRECATION")
fun restore(activity: Activity) {
suspend fun restore(activity: Activity) {
val dialog = android.app.ProgressDialog(activity).apply {
setTitle(activity.getString(R.string.restore_img_msg))
isIndeterminate = true
setCancelable(false)
show()
}
val apk = DynAPK.current(activity)
val receiver = APKInstall.register(activity, APPLICATION_ID) {
val onFailure = Runnable {
dialog.dismiss()
Utils.toast(R.string.failure, Toast.LENGTH_LONG)
}
val apk = StubApk.current(activity)
val session = APKInstall.startSession(activity, APPLICATION_ID, onFailure) {
launchApp(activity, APPLICATION_ID)
dialog.dismiss()
}
val cmd = "adb_pm_install $apk ${activity.applicationInfo.uid}"
Shell.su(cmd).submit(Shell.EXECUTOR) { ret ->
if (ret.isSuccess) return@submit
APKInstall.installapk(activity, apk)
receiver.waitIntent()?.let { activity.startActivity(it) }
if (Shell.su(cmd).await().isSuccess) return
val success = withContext(Dispatchers.IO) {
try {
session.install(activity, apk)
} catch (e: IOException) {
Timber.e(e)
return@withContext false
}
session.waitIntent()?.let { activity.startActivity(it) } ?: return@withContext false
return@withContext true
}
if (!success) onFailure.run()
}
}

View File

@@ -6,8 +6,8 @@ import android.widget.Toast
import androidx.annotation.WorkerThread
import androidx.core.os.postDelayed
import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.DynAPK
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.core.*
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.inputStream
@@ -93,7 +93,7 @@ abstract class MagiskInstallImpl protected constructor(
try {
// Extract binaries
if (isRunningAsStub) {
val zf = ZipFile(DynAPK.current(context))
val zf = ZipFile(StubApk.current(context))
// Also extract magisk32 on non 64-bit only 64-bit devices
val is32lib = Const.CPU_ABI_32?.let {
@@ -452,7 +452,7 @@ abstract class MagiskInstaller(
if (success) {
console.add("- All done!")
} else {
Shell.sh("rm -rf $installDir").submit()
Shell.cmd("rm -rf $installDir").submit()
console.add("! Installation failed")
}
return success
@@ -497,7 +497,7 @@ abstract class MagiskInstaller(
val success = super.exec()
if (success) {
UiThreadHandler.handler.postDelayed(3000) {
Shell.su("pm uninstall ${context.packageName}").exec()
Shell.cmd("pm uninstall ${context.packageName}").exec()
}
}
return success

View File

@@ -0,0 +1,34 @@
package com.topjohnwu.magisk.core.utils
import android.annotation.TargetApi
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.provider.Settings
import androidx.activity.result.contract.ActivityResultContract
class RequestInstall : ActivityResultContract<Unit, Boolean>() {
@TargetApi(26)
override fun createIntent(context: Context, input: Unit): Intent {
// This will only be called on API 26+
return Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES)
.setData(Uri.parse("package:${context.packageName}"))
}
override fun parseResult(resultCode: Int, intent: Intent?) =
resultCode == Activity.RESULT_OK
override fun getSynchronousResult(
context: Context,
input: Unit
): SynchronousResult<Boolean>? {
if (Build.VERSION.SDK_INT < 26)
return SynchronousResult(true)
if (context.packageManager.canRequestPackageInstalls())
return SynchronousResult(true)
return null
}
}

View File

@@ -5,6 +5,7 @@ import android.content.Intent
import android.content.ServiceConnection
import android.os.Binder
import android.os.IBinder
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ipc.RootService
import timber.log.Timber
import java.util.concurrent.CountDownLatch
@@ -12,11 +13,7 @@ import kotlin.system.exitProcess
class RootRegistry(stub: Any?) : RootService() {
constructor() : this(null)
private val className: String? = stub?.javaClass?.name
init {
constructor() : this(null) {
// Always log full stack trace with Timber
Timber.plant(Timber.DebugTree())
Thread.setDefaultUncaughtExceptionHandler { _, e ->
@@ -25,6 +22,8 @@ class RootRegistry(stub: Any?) : RootService() {
}
}
private val className: String? = stub?.javaClass?.name
override fun onBind(intent: Intent): IBinder {
// TODO: PLACEHOLDER
return Binder()
@@ -50,6 +49,6 @@ class RootRegistry(stub: Any?) : RootService() {
}
companion object {
var bindTask: Runnable? = null
var bindTask: Shell.Task? = null
}
}

View File

@@ -1,8 +1,8 @@
package com.topjohnwu.magisk.core.utils
import android.content.Context
import com.topjohnwu.magisk.DynAPK
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Info
@@ -19,7 +19,7 @@ import java.util.jar.JarFile
class ShellInit : Shell.Initializer() {
override fun onInit(context: Context, shell: Shell): Boolean {
if (shell.isRoot) {
RootRegistry.bindTask?.run()
RootRegistry.bindTask?.let { shell.execTask(it) }
RootRegistry.bindTask = null
}
shell.newJob().apply {
@@ -29,7 +29,7 @@ class ShellInit : Shell.Initializer() {
if (isRunningAsStub) {
if (!shell.isRoot)
return true
val jar = JarFile(DynAPK.current(context))
val jar = JarFile(StubApk.current(context))
val bb = jar.getJarEntry("lib/${Const.CPU_ABI}/libbusybox.so")
localBB = context.deviceProtectedContext.cachedFile("busybox")
localBB.delete()
@@ -42,7 +42,7 @@ class ShellInit : Shell.Initializer() {
if (shell.isRoot) {
add("export MAGISKTMP=\$(magisk --path)/.magisk")
// Test if we can properly execute stuff in /data
Info.noDataExec = !shell.newJob().add("$localBB true").exec().isSuccess
Info.noDataExec = !shell.newJob().add("$localBB sh -c \"$localBB true\"").exec().isSuccess
}
if (Info.noDataExec) {

View File

@@ -0,0 +1,21 @@
package com.topjohnwu.magisk.core.utils
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.activity.result.contract.ActivityResultContract
class UninstallPackage : ActivityResultContract<String, Boolean>() {
@Suppress("DEPRECATION")
override fun createIntent(context: Context, input: String): Intent {
val uri = Uri.Builder().scheme("package").opaquePart(input).build()
val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE, uri)
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true)
return intent
}
override fun parseResult(resultCode: Int, intent: Intent?) =
resultCode == Activity.RESULT_OK
}

View File

@@ -38,8 +38,7 @@ fun InputStream.unzip(folder: File, path: String, junkPath: Boolean) {
}
SuFileOutputStream.open(dest).use { out -> zin.copyTo(out) }
}
} catch (e: IOException) {
e.printStackTrace()
throw e
} catch (e: IllegalArgumentException) {
throw IOException(e)
}
}

View File

@@ -6,26 +6,16 @@ import com.topjohnwu.magisk.core.model.UpdateInfo
import okhttp3.ResponseBody
import retrofit2.http.*
private const val REVISION = "revision"
private const val BRANCH = "branch"
private const val REPO = "repo"
private const val FILE = "file"
const val MAGISK_MAIN = "topjohnwu/Magisk"
interface GithubPageServices {
@GET("{$FILE}")
suspend fun fetchUpdateJSON(@Path(FILE) file: String): UpdateInfo
}
interface JSDelivrServices {
@GET("$MAGISK_MAIN@{$REVISION}/scripts/module_installer.sh")
@Streaming
suspend fun fetchInstaller(@Path(REVISION) revision: String): ResponseBody
}
interface RawServices {
@GET

View File

@@ -29,9 +29,9 @@ class LogRepository(
}
}
if (Info.env.isActive) {
Shell.su("cat ${Const.MAGISK_LOG} || logcat -d -s Magisk").to(list).await()
Shell.cmd("cat ${Const.MAGISK_LOG} || logcat -d -s Magisk").to(list).await()
} else {
Shell.sh("logcat -d").to(list).await()
Shell.cmd("logcat -d").to(list).await()
}
return list.buf.toString()
}
@@ -39,7 +39,7 @@ class LogRepository(
suspend fun clearLogs() = logDao.deleteAll()
fun clearMagiskLogs(cb: (Shell.Result) -> Unit) =
Shell.su("echo -n > ${Const.MAGISK_LOG}").submit(cb)
Shell.cmd("echo -n > ${Const.MAGISK_LOG}").submit(cb)
suspend fun insert(log: SuLog) = logDao.insert(log)

View File

@@ -7,7 +7,9 @@ import com.topjohnwu.magisk.core.Config.Value.CUSTOM_CHANNEL
import com.topjohnwu.magisk.core.Config.Value.DEFAULT_CHANNEL
import com.topjohnwu.magisk.core.Config.Value.STABLE_CHANNEL
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.data.network.*
import com.topjohnwu.magisk.data.network.GithubApiServices
import com.topjohnwu.magisk.data.network.GithubPageServices
import com.topjohnwu.magisk.data.network.RawServices
import retrofit2.HttpException
import timber.log.Timber
import java.io.IOException
@@ -15,7 +17,6 @@ import java.io.IOException
class NetworkService(
private val pages: GithubPageServices,
private val raw: RawServices,
private val jsd: JSDelivrServices,
private val api: GithubApiServices
) {
suspend fun fetchUpdate() = safe {
@@ -59,13 +60,7 @@ class NetworkService(
}
// Fetch files
suspend fun fetchInstaller() = wrap {
val sha = fetchMainVersion()
jsd.fetchInstaller(sha)
}
suspend fun fetchFile(url: String) = wrap { raw.fetchFile(url) }
suspend fun fetchString(url: String) = wrap { raw.fetchString(url) }
suspend fun fetchModuleJson(url: String) = wrap { raw.fetchModuleJson(url) }
private suspend fun fetchMainVersion() = api.fetchBranch(MAGISK_MAIN, "master").commit.sha
}

View File

@@ -47,21 +47,20 @@ object ServiceLocator {
NetworkService(
createApiService(retrofit, Const.Url.GITHUB_PAGE_URL),
createApiService(retrofit, Const.Url.GITHUB_RAW_URL),
createApiService(retrofit, Const.Url.JS_DELIVR_URL),
createApiService(retrofit, Const.Url.GITHUB_API_URL)
)
}
object VMFactory : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(clz: Class<T>): T {
return when (clz) {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return when (modelClass) {
HomeViewModel::class.java -> HomeViewModel(networkService)
LogViewModel::class.java -> LogViewModel(logRepo)
SuperuserViewModel::class.java -> SuperuserViewModel(policyDB)
InstallViewModel::class.java -> InstallViewModel(networkService)
SuRequestViewModel::class.java -> SuRequestViewModel(policyDB, timeoutPrefs)
else -> clz.newInstance()
else -> modelClass.newInstance()
} as T
}
}
@@ -69,7 +68,7 @@ object ServiceLocator {
inline fun <reified VM : ViewModel> ViewModelStoreOwner.viewModel() =
lazy(LazyThreadSafetyMode.NONE) {
ViewModelProvider(this, ServiceLocator.VMFactory).get(VM::class.java)
ViewModelProvider(this, ServiceLocator.VMFactory)[VM::class.java]
}
private fun createSuLogDatabase(context: Context) =

View File

@@ -20,7 +20,7 @@ object RebootEvent {
R.id.action_reboot_bootloader -> systemReboot("bootloader")
R.id.action_reboot_download -> systemReboot("download")
R.id.action_reboot_edl -> systemReboot("edl")
R.id.action_reboot_recovery -> Shell.su("/system/bin/reboot recovery").submit()
R.id.action_reboot_recovery -> Shell.cmd("/system/bin/reboot recovery").submit()
else -> Unit
}
return true

View File

@@ -1,44 +0,0 @@
package com.topjohnwu.magisk.events
import android.view.View
import androidx.annotation.StringRes
import com.google.android.material.snackbar.Snackbar
import com.topjohnwu.magisk.arch.ActivityExecutor
import com.topjohnwu.magisk.arch.UIActivity
import com.topjohnwu.magisk.arch.ViewEvent
import com.topjohnwu.magisk.utils.TextHolder
import com.topjohnwu.magisk.utils.asText
class SnackbarEvent constructor(
private val msg: TextHolder,
private val length: Int = Snackbar.LENGTH_SHORT,
private val builder: Snackbar.() -> Unit = {}
) : ViewEvent(), ActivityExecutor {
constructor(
@StringRes res: Int,
length: Int = Snackbar.LENGTH_SHORT,
builder: Snackbar.() -> Unit = {}
) : this(res.asText(), length, builder)
constructor(
msg: String,
length: Int = Snackbar.LENGTH_SHORT,
builder: Snackbar.() -> Unit = {}
) : this(msg.asText(), length, builder)
private fun snackbar(
view: View,
anchor: View?,
message: String,
length: Int,
builder: Snackbar.() -> Unit
) = Snackbar.make(view, message, length).setAnchorView(anchor).apply(builder).show()
override fun invoke(activity: UIActivity<*>) {
snackbar(activity.snackbarView, activity.snackbarAnchorView,
msg.getText(activity.resources).toString(),
length, builder)
}
}

View File

@@ -5,12 +5,16 @@ import android.content.Context
import android.net.Uri
import android.view.View
import android.widget.Toast
import androidx.annotation.StringRes
import androidx.navigation.NavDirections
import com.google.android.material.snackbar.Snackbar
import com.topjohnwu.magisk.MainDirections
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.*
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.utils.TextHolder
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.utils.asText
import com.topjohnwu.magisk.view.Shortcuts
class PermissionEvent(
@@ -67,7 +71,7 @@ class NavigationEvent(
) : ViewEvent(), ActivityExecutor {
override fun invoke(activity: UIActivity<*>) {
(activity as? NavigationActivity<*>)?.apply {
if (pop) navigation?.popBackStack()
if (pop) navigation.popBackStack()
directions.navigate()
}
}
@@ -83,7 +87,7 @@ class SelectModuleEvent : ViewEvent(), FragmentExecutor {
override fun invoke(fragment: BaseFragment<*>) {
try {
fragment.apply {
activity.getContent("application/zip") {
activity?.getContent("application/zip") {
MainDirections.actionFlashFragment(Const.Value.FLASH_ZIP, it).navigate()
}
}
@@ -92,3 +96,26 @@ class SelectModuleEvent : ViewEvent(), FragmentExecutor {
}
}
}
class SnackbarEvent(
private val msg: TextHolder,
private val length: Int = Snackbar.LENGTH_SHORT,
private val builder: Snackbar.() -> Unit = {}
) : ViewEvent(), ActivityExecutor {
constructor(
@StringRes res: Int,
length: Int = Snackbar.LENGTH_SHORT,
builder: Snackbar.() -> Unit = {}
) : this(res.asText(), length, builder)
constructor(
msg: String,
length: Int = Snackbar.LENGTH_SHORT,
builder: Snackbar.() -> Unit = {}
) : this(msg.asText(), length, builder)
override fun invoke(activity: UIActivity<*>) {
activity.showSnackbar(msg.getText(activity.resources), length, builder)
}
}

View File

@@ -29,7 +29,7 @@ class ManagerInstallDialog : MarkDownDialog() {
setCancelable(true)
setButton(MagiskDialog.ButtonType.POSITIVE) {
text = R.string.install
onClick { DownloadService.start(context, Subject.Manager()) }
onClick { DownloadService.start(context, Subject.App()) }
}
setButton(MagiskDialog.ButtonType.NEGATIVE) {
text = android.R.string.cancel

View File

@@ -1,22 +0,0 @@
package com.topjohnwu.magisk.events.dialog
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.tasks.HideAPK
import com.topjohnwu.magisk.view.MagiskDialog
class RestoreAppDialog : DialogEvent() {
override fun build(dialog: MagiskDialog) {
dialog.apply {
setTitle(R.string.settings_restore_app_title)
setMessage(R.string.restore_app_confirmation)
setButton(MagiskDialog.ButtonType.POSITIVE) {
text = android.R.string.ok
onClick { HideAPK.restore(dialog.ownerActivity!!) }
}
setButton(MagiskDialog.ButtonType.NEGATIVE) {
text = android.R.string.cancel
}
setCancelable(true)
}
}
}

View File

@@ -34,7 +34,7 @@ class UninstallDialog : DialogEvent() {
show()
}
Shell.su("restore_imgs").submit { result ->
Shell.cmd("restore_imgs").submit { result ->
dialog.dismiss()
if (result.isSuccess) {
Utils.toast(R.string.restore_done, Toast.LENGTH_SHORT)

View File

@@ -84,7 +84,7 @@ fun Intent.startActivity(context: Context) = context.startActivity(this)
fun Intent.startActivityWithRoot() {
val args = mutableListOf("am", "start", "--user", Const.USER_ID.toString())
val cmd = toCommand(args).joinToString(" ")
Shell.su(cmd).submit()
Shell.cmd(cmd).submit()
}
fun Intent.toCommand(args: MutableList<String> = mutableListOf()): MutableList<String> {

View File

@@ -8,14 +8,14 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
fun reboot(reason: String = if (Config.recovery) "recovery" else "") {
Shell.su("/system/bin/svc power reboot $reason || /system/bin/reboot $reason").submit()
Shell.cmd("/system/bin/svc power reboot $reason || /system/bin/reboot $reason").submit()
}
fun relaunchApp(context: Context) {
val intent = context.packageManager.getLaunchIntentForPackage(context.packageName) ?: return
val args = mutableListOf("am", "start", "--user", Const.USER_ID.toString())
val cmd = intent.toCommand(args).joinToString(separator = " ")
Shell.su("run_delay 1 \"$cmd\"").exec()
Shell.cmd("run_delay 1 \"$cmd\"").exec()
Runtime.getRuntime().exit(0)
}

View File

@@ -492,7 +492,7 @@ public class SignApk {
}
public static void sign(X509Certificate cert, PrivateKey key,
JarMap inputJar, FileOutputStream outputFile) throws Exception {
JarMap inputJar, OutputStream outputStream) throws Exception {
int alignment = 4;
int hashes = 0;
@@ -531,7 +531,7 @@ public class SignApk {
// This assumes outputChunks are array-backed. To avoid this assumption, the
// code could be rewritten to use FileChannel.
for (ByteBuffer outputChunk : outputChunks) {
outputFile.write(outputChunk.array(),
outputStream.write(outputChunk.array(),
outputChunk.arrayOffset() + outputChunk.position(), outputChunk.remaining());
outputChunk.position(outputChunk.limit());
}

View File

@@ -15,7 +15,10 @@ import com.topjohnwu.magisk.MainDirections
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseMainActivity
import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.core.*
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.databinding.ActivityMainMd2Binding
import com.topjohnwu.magisk.di.viewModel
import com.topjohnwu.magisk.ktx.startAnimations
@@ -51,7 +54,7 @@ class MainActivity : BaseMainActivity<ActivityMainMd2Binding>() {
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
navigation?.addOnDestinationChangedListener { _, destination, _ ->
navigation.addOnDestinationChangedListener { _, destination, _ ->
isRootFragment = when (destination.id) {
R.id.homeFragment,
R.id.modulesFragment,

View File

@@ -26,7 +26,7 @@ class DenyListFragment : BaseFragment<FragmentDenyMd2Binding>() {
override fun onAttach(context: Context) {
super.onAttach(context)
activity.setTitle(R.string.denylist)
activity?.setTitle(R.string.denylist)
setHasOptionsMenu(true)
}

View File

@@ -103,7 +103,7 @@ class ProcessRvItem(
set(value) = set(value, process.isEnabled, { process.isEnabled = it }, BR.enabled) {
val arg = if (it) "add" else "rm"
val (name, pkg) = process
Shell.su("magisk --denylist $arg $pkg \'$name\'").submit()
Shell.cmd("magisk --denylist $arg $pkg \'$name\'").submit()
}
fun toggle() {

View File

@@ -52,7 +52,7 @@ class DenyListViewModel : BaseViewModel() {
state = State.LOADING
val (apps, diff) = withContext(Dispatchers.Default) {
val pm = AppContext.packageManager
val denyList = Shell.su("magisk --denylist ls").exec().out
val denyList = Shell.cmd("magisk --denylist ls").exec().out
.map { CmdlineListItem(it) }
val apps = pm.getInstalledApplications(MATCH_UNINSTALLED_PACKAGES).run {
asFlow()

View File

@@ -31,10 +31,10 @@ class FlashFragment : BaseFragment<FragmentFlashMd2Binding>() {
override fun onStart() {
super.onStart()
setHasOptionsMenu(true)
activity.setTitle(R.string.flash_screen_title)
activity?.setTitle(R.string.flash_screen_title)
viewModel.subtitle.observe(this) {
activity.supportActionBar?.setSubtitle(it)
activity?.supportActionBar?.setSubtitle(it)
}
}
@@ -49,15 +49,15 @@ class FlashFragment : BaseFragment<FragmentFlashMd2Binding>() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
defaultOrientation = activity.requestedOrientation
activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
defaultOrientation = activity?.requestedOrientation ?: -1
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
viewModel.startFlashing()
}
@SuppressLint("WrongConstant")
override fun onDestroyView() {
if (defaultOrientation != -1) {
activity.requestedOrientation = defaultOrientation
activity?.requestedOrientation = defaultOrientation
}
super.onDestroyView()
}

View File

@@ -103,9 +103,11 @@ class FlashViewModel : BaseViewModel() {
val name = "magisk_install_log_%s.log".format(now.toTime(timeFormatStandard))
val file = MediaStoreUtils.getFile(name, true)
file.uri.outputStream().bufferedWriter().use { writer ->
logItems.forEach {
writer.write(it)
writer.newLine()
synchronized(logItems) {
logItems.forEach {
writer.write(it)
writer.newLine()
}
}
}
SnackbarEvent(file.toString()).publish()

View File

@@ -19,7 +19,7 @@ class HomeFragment : BaseFragment<FragmentHomeMd2Binding>() {
override fun onStart() {
super.onStart()
activity.title = resources.getString(R.string.section_home)
activity?.title = resources.getString(R.string.section_home)
setHasOptionsMenu(true)
DownloadService.observeProgress(this, viewModel::onProgressUpdate)
}
@@ -64,7 +64,7 @@ class HomeFragment : BaseFragment<FragmentHomeMd2Binding>() {
when (item.itemId) {
R.id.action_settings ->
HomeFragmentDirections.actionHomeFragmentToSettingsFragment().navigate()
R.id.action_reboot -> RebootEvent.inflateMenu(activity).show()
R.id.action_reboot -> activity?.let { RebootEvent.inflateMenu(it).show() }
else -> return super.onOptionsItemSelected(item)
}
return true

View File

@@ -10,7 +10,7 @@ import com.topjohnwu.magisk.arch.*
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.download.Subject
import com.topjohnwu.magisk.core.download.Subject.Manager
import com.topjohnwu.magisk.core.download.Subject.App
import com.topjohnwu.magisk.data.repository.NetworkService
import com.topjohnwu.magisk.databinding.itemBindingOf
import com.topjohnwu.magisk.databinding.set
@@ -112,7 +112,7 @@ class HomeViewModel(
}.publish()
fun onProgressUpdate(progress: Float, subject: Subject) {
if (subject is Manager)
if (subject is App)
stateManagerProgress = progress.times(100f).roundToInt()
}
@@ -123,7 +123,11 @@ class HomeViewModel(
fun onDeletePressed() = UninstallDialog().publish()
fun onManagerPressed() = when (state) {
State.LOADED -> withExternalRW { ManagerInstallDialog().publish() }
State.LOADED -> withExternalRW {
withInstallPermission {
ManagerInstallDialog().publish()
}
}
State.LOADING -> SnackbarEvent(R.string.loading).publish()
else -> SnackbarEvent(R.string.no_connection).publish()
}
@@ -140,7 +144,7 @@ class HomeViewModel(
private suspend fun ensureEnv() {
if (MagiskState.NOT_INSTALLED == stateMagisk || checkedEnv) return
val cmd = "env_check ${Info.env.versionString} ${Info.env.versionCode}"
if (!Shell.su(cmd).await().isSuccess) {
if (!Shell.cmd(cmd).await().isSuccess) {
EnvFixDialog(this).publish()
}
checkedEnv = true

View File

@@ -38,7 +38,7 @@ class LogFragment : BaseFragment<FragmentLogMd2Binding>() {
override fun onStart() {
super.onStart()
setHasOptionsMenu(true)
activity.title = resources.getString(R.string.logs)
activity?.title = resources.getString(R.string.logs)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

View File

@@ -5,6 +5,8 @@ import android.view.View
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.databinding.FragmentModuleMd2Binding
import com.topjohnwu.magisk.databinding.RvItem
import com.topjohnwu.magisk.databinding.adapterOf
import com.topjohnwu.magisk.di.viewModel
import rikka.recyclerview.addEdgeSpacing
import rikka.recyclerview.addInvalidateItemDecorationsObserver
@@ -19,13 +21,14 @@ class ModuleFragment : BaseFragment<FragmentModuleMd2Binding>() {
override fun onStart() {
super.onStart()
setHasOptionsMenu(true)
activity.title = resources.getString(R.string.modules)
activity?.title = resources.getString(R.string.modules)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.moduleList.apply {
adapter = adapterOf<RvItem>()
addEdgeSpacing(top = R.dimen.l_50, bottom = R.dimen.l1)
addItemSpacing(R.dimen.l1, R.dimen.l_50, R.dimen.l1)
fixEdgeEffect()

View File

@@ -8,7 +8,6 @@ import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.model.module.LocalModule
import com.topjohnwu.magisk.core.model.module.OnlineModule
import com.topjohnwu.magisk.databinding.RvItem
import com.topjohnwu.magisk.databinding.adapterOf
import com.topjohnwu.magisk.databinding.diffListOf
import com.topjohnwu.magisk.databinding.itemBindingOf
import com.topjohnwu.magisk.events.SelectModuleEvent
@@ -26,7 +25,6 @@ class ModuleViewModel : BaseViewModel() {
private val itemsInstalled = diffListOf<LocalModuleRvItem>()
val adapter = adapterOf<RvItem>()
val items = MergeObservableList<RvItem>()
val itemBinding = itemBindingOf<RvItem> {
it.bindExtra(BR.viewModel, this)

View File

@@ -18,7 +18,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsMd2Binding>() {
override fun onStart() {
super.onStart()
activity.title = resources.getString(R.string.settings)
activity?.title = resources.getString(R.string.settings)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

View File

@@ -25,6 +25,7 @@ import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.di.AppContext
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.utils.asText
import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@@ -105,6 +106,26 @@ object Hide : BaseSettingsItem.Input() {
object Restore : BaseSettingsItem.Blank() {
override val title = R.string.settings_restore_app_title.asText()
override val description = R.string.settings_restore_app_summary.asText()
override fun onPressed(view: View, handler: Handler) {
handler.onItemPressed(view, this) {
MagiskDialog(view.context).apply {
setTitle(R.string.settings_restore_app_title)
setMessage(R.string.restore_app_confirmation)
setButton(MagiskDialog.ButtonType.POSITIVE) {
text = android.R.string.ok
onClick {
handler.onItemAction(view, this@Restore)
}
}
setButton(MagiskDialog.ButtonType.NEGATIVE) {
text = android.R.string.cancel
}
setCancelable(true)
show()
}
}
}
}
object AddShortcut : BaseSettingsItem.Blank() {
@@ -236,7 +257,7 @@ object DenyList : BaseSettingsItem.Toggle() {
set(value) {
field = value
val cmd = if (value) "enable" else "disable"
Shell.su("magisk --denylist $cmd").submit { result ->
Shell.cmd("magisk --denylist $cmd").submit { result ->
if (result.isSuccess) {
Config.denyList = value
} else {

View File

@@ -20,7 +20,6 @@ import com.topjohnwu.magisk.events.AddHomeIconEvent
import com.topjohnwu.magisk.events.RecreateEvent
import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.events.dialog.BiometricEvent
import com.topjohnwu.magisk.events.dialog.RestoreAppDialog
import com.topjohnwu.magisk.ktx.activity
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.superuser.Shell
@@ -103,7 +102,7 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
Theme -> SettingsFragmentDirections.actionSettingsFragmentToThemeFragment().navigate()
DenyListConfig -> SettingsFragmentDirections.actionSettingsFragmentToDenyFragment().navigate()
SystemlessHosts -> createHosts()
Restore -> RestoreAppDialog().publish()
Hide, Restore -> withInstallPermission(andThen)
AddShortcut -> AddHomeIconEvent().publish()
else -> andThen()
}
@@ -114,6 +113,7 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
Language -> RecreateEvent().publish()
UpdateChannel -> openUrlIfNecessary(view)
is Hide -> viewModelScope.launch { HideAPK.hide(view.activity, item.value) }
Restore -> viewModelScope.launch { HideAPK.restore(view.activity) }
Zygisk -> if (Zygisk.mismatch) SnackbarEvent(R.string.reboot_apply_change).publish()
else -> Unit
}
@@ -134,7 +134,7 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
}
private fun createHosts() {
Shell.su("add_hosts_module").submit {
Shell.cmd("add_hosts_module").submit {
Utils.toast(R.string.settings_hosts_toast, Toast.LENGTH_SHORT)
}
}

View File

@@ -4,7 +4,9 @@ import android.os.Bundle
import android.view.View
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.databinding.AnyDiffRvItem
import com.topjohnwu.magisk.databinding.FragmentSuperuserMd2Binding
import com.topjohnwu.magisk.databinding.adapterOf
import com.topjohnwu.magisk.di.viewModel
import rikka.recyclerview.addEdgeSpacing
import rikka.recyclerview.addItemSpacing
@@ -17,13 +19,14 @@ class SuperuserFragment : BaseFragment<FragmentSuperuserMd2Binding>() {
override fun onStart() {
super.onStart()
activity.title = resources.getString(R.string.superuser)
activity?.title = resources.getString(R.string.superuser)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.superuserList.apply {
adapter = adapterOf<AnyDiffRvItem>()
addEdgeSpacing(top = R.dimen.l_50, bottom = R.dimen.l1)
addItemSpacing(R.dimen.l1, R.dimen.l_50, R.dimen.l1)
fixEdgeEffect()

View File

@@ -10,7 +10,6 @@ import com.topjohnwu.magisk.core.model.su.SuPolicy
import com.topjohnwu.magisk.core.utils.BiometricHelper
import com.topjohnwu.magisk.core.utils.currentLocale
import com.topjohnwu.magisk.databinding.AnyDiffRvItem
import com.topjohnwu.magisk.databinding.adapterOf
import com.topjohnwu.magisk.databinding.diffListOf
import com.topjohnwu.magisk.databinding.itemBindingOf
import com.topjohnwu.magisk.events.SnackbarEvent
@@ -33,7 +32,6 @@ class SuperuserViewModel(
private val itemsPolicies = diffListOf<PolicyRvItem>()
private val itemsHelpers = ObservableArrayList<TextItem>()
val adapter = adapterOf<AnyDiffRvItem>()
val items = MergeObservableList<AnyDiffRvItem>()
.insertList(itemsHelpers)
.insertList(itemsPolicies)

View File

@@ -73,7 +73,7 @@ class SuRequestViewModel(
val itemBinding = ItemBinding.of<String>(BR.item, R.layout.item_spinner)
private val handler = SuRequestHandler(AppContext.packageManager, policyDB)
private lateinit var timer: CountDownTimer
private var timer: CountDownTimer? = null
fun grantPressed() {
cancelTimer()
@@ -121,7 +121,7 @@ class SuRequestViewModel(
}
private fun respond(action: Int) {
timer.cancel()
timer?.cancel()
val pos = selectedItemPosition
timeoutPrefs.edit().putInt(handler.policy.packageName, pos).apply()
@@ -132,7 +132,7 @@ class SuRequestViewModel(
}
private fun cancelTimer() {
timer.cancel()
timer?.cancel()
denyText.seconds = 0
}

View File

@@ -61,7 +61,7 @@ class ThemeFragment : BaseFragment<FragmentThemeMd2Binding>() {
override fun onStart() {
super.onStart()
activity.title = getString(R.string.section_theme)
activity?.title = getString(R.string.section_theme)
}
}

View File

@@ -121,15 +121,15 @@ class MagiskDialog(
super.onCreate(savedInstanceState)
super.setContentView(binding.root)
val default = MaterialColors.getColor(context, R.attr.colorSurface, javaClass.canonicalName)
val default = MaterialColors.getColor(context, com.google.android.material.R.attr.colorSurface, javaClass.canonicalName)
val surfaceColor = MaterialColors.getColor(context, R.attr.colorSurfaceSurfaceVariant, default)
val materialShapeDrawable = MaterialShapeDrawable(context, null, R.attr.alertDialogStyle, R.style.MaterialAlertDialog_MaterialComponents)
val materialShapeDrawable = MaterialShapeDrawable(context, null, androidx.appcompat.R.attr.alertDialogStyle, com.google.android.material.R.style.MaterialAlertDialog_MaterialComponents)
materialShapeDrawable.initializeElevationOverlay(context)
materialShapeDrawable.fillColor = ColorStateList.valueOf(surfaceColor)
materialShapeDrawable.elevation = context.resources.getDimension(R.dimen.margin_generic)
materialShapeDrawable.setCornerSize(context.resources.getDimension(R.dimen.l_50))
val inset = context.resources.getDimensionPixelSize(R.dimen.appcompat_dialog_background_inset)
val inset = context.resources.getDimensionPixelSize(com.google.android.material.R.dimen.appcompat_dialog_background_inset)
window?.apply {
setBackgroundDrawable(InsetDrawable(materialShapeDrawable, inset, inset, inset, inset))
setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)

View File

@@ -1,15 +1,16 @@
package com.topjohnwu.magisk.view
import android.annotation.SuppressLint
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build.VERSION.SDK_INT
import androidx.core.content.getSystemService
import androidx.core.graphics.drawable.toIcon
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Const.ID.PROGRESS_NOTIFICATION_CHANNEL
import com.topjohnwu.magisk.core.Const.ID.UPDATE_NOTIFICATION_CHANNEL
import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.core.download.Subject
import com.topjohnwu.magisk.di.AppContext
@@ -21,51 +22,80 @@ object Notifications {
val mgr by lazy { AppContext.getSystemService<NotificationManager>()!! }
private const val APK_UPDATE_NOTIFICATION_ID = 5
private val nextId = AtomicInteger(APK_UPDATE_NOTIFICATION_ID)
private const val APP_UPDATED_NOTIFICATION_ID = 4
private const val APP_UPDATE_NOTIFICATION_ID = 5
private const val UPDATE_CHANNEL = "update"
private const val PROGRESS_CHANNEL = "progress"
private const val UPDATED_CHANNEL = "updated"
private val nextId = AtomicInteger(APP_UPDATE_NOTIFICATION_ID)
fun setup(context: Context) {
if (SDK_INT >= 26) {
val channel = NotificationChannel(UPDATE_NOTIFICATION_CHANNEL,
val channel = NotificationChannel(UPDATE_CHANNEL,
context.getString(R.string.update_channel), NotificationManager.IMPORTANCE_DEFAULT)
val channel2 = NotificationChannel(PROGRESS_NOTIFICATION_CHANNEL,
val channel2 = NotificationChannel(PROGRESS_CHANNEL,
context.getString(R.string.progress_channel), NotificationManager.IMPORTANCE_LOW)
mgr.createNotificationChannels(listOf(channel, channel2))
val channel3 = NotificationChannel(UPDATED_CHANNEL,
context.getString(R.string.updated_channel), NotificationManager.IMPORTANCE_HIGH)
mgr.createNotificationChannels(listOf(channel, channel2, channel3))
}
}
private fun updateBuilder(context: Context): Notification.Builder {
return Notification.Builder(context).apply {
val bitmap = context.getBitmap(R.drawable.ic_magisk_outline)
setLargeIcon(bitmap)
if (SDK_INT >= 26) {
setSmallIcon(bitmap.toIcon())
setChannelId(UPDATE_NOTIFICATION_CHANNEL)
} else {
setSmallIcon(R.drawable.ic_magisk_outline)
}
}
fun selfLaunchIntent(context: Context): Intent {
val pm = context.packageManager
val intent = pm.getLaunchIntentForPackage(context.packageName)!!
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
return intent
}
fun managerUpdate(context: Context) {
val intent = DownloadService.getPendingIntent(context, Subject.Manager())
@SuppressLint("InlinedApi")
fun updateDone(context: Context) {
setup(context)
val flag = PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
val pending = PendingIntent.getActivity(context, 0, selfLaunchIntent(context), flag)
val builder = if (SDK_INT >= 26) {
Notification.Builder(context, UPDATED_CHANNEL)
.setSmallIcon(context.getBitmap(R.drawable.ic_magisk_outline).toIcon())
} else {
Notification.Builder(context).setPriority(Notification.PRIORITY_HIGH)
.setSmallIcon(R.drawable.ic_magisk_outline)
}
.setContentIntent(pending)
.setContentTitle(context.getText(R.string.updated_title))
.setContentText(context.getText(R.string.updated_text))
.setAutoCancel(true)
mgr.notify(APP_UPDATED_NOTIFICATION_ID, builder.build())
}
val builder = updateBuilder(context)
fun updateAvailable(context: Context) {
val intent = DownloadService.getPendingIntent(context, Subject.App())
val bitmap = context.getBitmap(R.drawable.ic_magisk_outline)
val builder = if (SDK_INT >= 26) {
Notification.Builder(context, UPDATE_CHANNEL)
.setSmallIcon(bitmap.toIcon())
} else {
Notification.Builder(context)
.setSmallIcon(R.drawable.ic_magisk_outline)
}
.setLargeIcon(bitmap)
.setContentTitle(context.getString(R.string.magisk_update_title))
.setContentText(context.getString(R.string.manager_download_install))
.setAutoCancel(true)
.setContentIntent(intent)
mgr.notify(APK_UPDATE_NOTIFICATION_ID, builder.build())
mgr.notify(APP_UPDATE_NOTIFICATION_ID, builder.build())
}
fun progress(context: Context, title: CharSequence): Notification.Builder {
val builder = if (SDK_INT >= 26) {
Notification.Builder(context, PROGRESS_NOTIFICATION_CHANNEL)
Notification.Builder(context, PROGRESS_CHANNEL)
} else {
Notification.Builder(context).setPriority(Notification.PRIORITY_LOW)
}
builder.setSmallIcon(android.R.drawable.stat_sys_download)
.setSmallIcon(android.R.drawable.stat_sys_download)
.setContentTitle(title)
.setProgress(0, 0, true)
.setOngoing(true)

View File

@@ -29,11 +29,11 @@ public class ConcealableBottomNavigationView extends BottomNavigationView {
}
public ConcealableBottomNavigationView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, R.attr.bottomNavigationStyle);
this(context, attrs, com.google.android.material.R.attr.bottomNavigationStyle);
}
public ConcealableBottomNavigationView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, R.style.Widget_Design_BottomNavigationView);
this(context, attrs, defStyleAttr, com.google.android.material.R.style.Widget_Design_BottomNavigationView);
}
public ConcealableBottomNavigationView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {

View File

@@ -19,7 +19,6 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/module_list"
adapter="@{viewModel.adapter}"
gone="@{viewModel.loading}"
itemBinding="@{viewModel.itemBinding}"
items="@{viewModel.items}"

View File

@@ -19,7 +19,6 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/superuser_list"
adapter="@{viewModel.adapter}"
goneUnless="@{viewModel.loaded || !viewModel.items.empty}"
itemBinding="@{viewModel.itemBinding}"
items="@{viewModel.items}"

View File

@@ -8,16 +8,19 @@
<string name="install">Installi</string>
<string name="section_home">Kodu</string>
<string name="section_theme">Teemad</string>
<string name="denylist">Keeluloend</string>
<!--Home-->
<string name="no_connection">Ühendus puudub</string>
<string name="app_changelog">Muudatuste logi</string>
<string name="loading">Laadimine…</string>
<string name="update">Uuenda</string>
<string name="not_available">puudub</string>
<string name="not_available">teadmata</string>
<string name="hide">Peida</string>
<string name="home_package">Pakett</string>
<string name="home_app_title">Rakendus</string>
<string name="home_notice_content">Laadi Magisk alla vaid ametlikult GitHubi lehelt. Tundmatutest allikatest laaditud failid võivad olla pahatahtlikud!</string>
<string name="home_support_title">Toeta meid</string>
<string name="home_item_source">Lähtekood</string>
<string name="home_support_content">Magisk on ja jääb alati tasuta ning avatud lähtekoodiga kättesaadavaks. Siiski, sa võid meile väikese annetuse näol toetust üles näidata.</string>
@@ -25,20 +28,21 @@
<string name="home_latest_version">Viimatine</string>
<string name="invalid_update_channel">Sobimatu uuenduste kanal</string>
<string name="uninstall_magisk_title">Eemalda Magisk</string>
<string name="uninstall_magisk_msg">Kõik moodulid keelatakse/eemaldatakse!\nJuurkasutaja eemaldatakse!\nSinu andmeid võidakse krüpteerida, kui need juba ei ole krüpteeritud!</string>
<string name="uninstall_magisk_msg">Kõik moodulid keelatakse/eemaldatakse!\nJuurkasutaja eemaldatakse!\nMistahes sisemälu failid, millelt eemaldati Magiski tarbeks krüpteering, krüpteeritakse taas!</string>
<!--Install-->
<string name="keep_force_encryption">Säilita sunnitud krüpteering</string>
<string name="keep_dm_verity">Säilita AVB 2.0/dm-verity</string>
<string name="patch_vbmeta">Paika käivitustõmmises vbmeta</string>
<string name="recovery_mode">Taastusrežiim</string>
<string name="install_options_title">Valikud</string>
<string name="install_method_title">Meetod</string>
<string name="install_next">Edasi</string>
<string name="install_start">Läksime</string>
<string name="manager_download_install">Vajuta allalaadimiseks ja installimiseks.</string>
<string name="manager_download_install">Vajuta allalaadimiseks ja installimiseks</string>
<string name="direct_install">Otsene install (soovitatud)</string>
<string name="install_inactive_slot">Installi ebaaktiivsesse lahtrisse (pärast üle-õhu uuendust)</string>
<string name="install_inactive_slot_msg">Sinu seade SUNNITAKSE peale taaskäivitust käivituma praegusesse ebaaktiivsesse lahtrisse!\nKasuta seda valikut vaid peale üle-õhu uuenduse teostamist.\nJätkad?</string>
<string name="install_inactive_slot_msg">Pärast taaskäivitust SUNNITAKSE sinu seade käivituma praegusesse ebaaktiivsesse lahtrisse!\nKasuta seda valikut vaid peale üle-õhu uuenduse teostamist.\nJätkad?</string>
<string name="setup_title">Lisaseadistus</string>
<string name="select_patch_file">Vali ja paika fail</string>
<string name="patch_file_msg">Vali toortõmmis (*.img) või ODIN tar-fail (*.tar)</string>
@@ -47,6 +51,7 @@
<!--Superuser-->
<string name="su_request_title">Superkasutaja taotlus</string>
<string name="touch_filtered_warning">Kuna rakendus varjab superkasutaja päringut, ei saa Magisk sinu vastust kinnitada</string>
<string name="deny">Keela</string>
<string name="prompt">Küsi</string>
<string name="grant">Luba</string>
@@ -75,8 +80,8 @@
<string name="superuser_policy_none">Ükski rakendus ei ole veel superkasutaja õigusi küsinud.</string>
<!--Logs-->
<string name="log_data_none">Sa oled logivaba, proovi oma superkasutaja õigustega rakendusi rohkem kasutada.</string>
<string name="log_data_magisk_none">Magiski logid on tühjad, see on imelik.</string>
<string name="log_data_none">Sa oled logivaba, proovi oma superkasutaja õigustega rakendusi rohkem kasutada</string>
<string name="log_data_magisk_none">Magiski logid on tühjad, see on imelik</string>
<string name="menuSaveLog">Salvesta logi</string>
<string name="menuClearLog">Tühjenda logi nüüd</string>
<string name="logs_cleared">Logi edukalt tühjendatud.</string>
@@ -85,13 +90,15 @@
<!--SafetyNet-->
<!-- MagiskHide -->
<string name="show_system_app">Kuva süsteemirakendused</string>
<!--MagiskHide-->
<string name="show_system_app">Kuva uuendatavad süsteemirakendused</string>
<string name="show_os_app">Kuva fikseeritud süsteemirakendused</string>
<string name="hide_filter_hint">Filtreeri nime järgi</string>
<string name="hide_search">Otsing</string>
<!--Module -->
<!--Module-->
<string name="no_info_provided">(Info puudub)</string>
<string name="reboot_userspace">Pehme taaskäivitus</string>
<string name="reboot_recovery">Taaskäivita taastusesse</string>
<string name="reboot_bootloader">Taaskäivita käivitushaldurisse</string>
<string name="reboot_download">Taaskäivita allalaadimisrežiimi</string>
@@ -101,8 +108,11 @@
<string name="module_state_restore">Taasta</string>
<string name="module_action_install_external">Installi sisemälust</string>
<string name="update_available">Uuendus saadaval</string>
<string name="suspend_text_riru">Moodul keelatud %1$s lubamise tõttu</string>
<string name="suspend_text_zygisk">Moodul keelatud %1$s mittelubamise tõttu</string>
<string name="zygisk_module_unloaded">Zygisk-moodulit ei laaditud ühildumatuse tõttu</string>
<!--Settings -->
<!--Settings-->
<string name="settings_dark_mode_title">Teema režiim</string>
<string name="settings_dark_mode_message">Vali režiim, mis ühtib sinu stiiliga!</string>
<string name="settings_dark_mode_light">Alati hele</string>
@@ -110,20 +120,30 @@
<string name="settings_dark_mode_dark">Alati tume</string>
<string name="settings_download_path_title">Allalaadimise failitee</string>
<string name="settings_download_path_message">Failid salvestatakse kausta %1$s</string>
<string name="settings_hide_app_title">Peida Magiski rakendus</string>
<string name="settings_hide_app_summary">Paigalda juhusliku paketi-ID ja kohandatud nimega puhverrakendus</string>
<string name="settings_restore_app_title">Taasta Magiski rakendus</string>
<string name="settings_restore_app_summary">Too rakendus peidust välja, taastades originaalse APK</string>
<string name="language">Keel</string>
<string name="system_default">(Süsteemi vaikesäte)</string>
<string name="settings_check_update_title">Kontrolli uuendusi</string>
<string name="settings_check_update_summary">Kontrolli taustal perioodiliselt uuendusi.</string>
<string name="settings_check_update_summary">Kontrolli taustal perioodiliselt uuendusi</string>
<string name="settings_update_channel_title">Uuenduste kanal</string>
<string name="settings_update_stable">Stabiilne</string>
<string name="settings_update_beta">Beeta</string>
<string name="settings_update_custom">Kohandatud</string>
<string name="settings_update_custom_msg">Sisesta kohandatud URL</string>
<string name="settings_update_custom_msg">Sisesta kohandatud kanali URL</string>
<string name="settings_zygisk_summary">Käivita teatud Magiski osi zygote-protsessis</string>
<string name="settings_denylist_title">Jõusta keeluloend</string>
<string name="settings_denylist_summary">Keeluloendis olevatel protsessidel tühistatakse kõik Magiski muudatused</string>
<string name="settings_denylist_error">See funktsioon eeldab %1$s lubamist</string>
<string name="settings_denylist_config_title">Seadista keeluloendit</string>
<string name="settings_denylist_config_summary">Vali keeluloendisse lisatavad protsessid</string>
<string name="settings_hosts_title">Süsteemivaba hosts</string>
<string name="settings_hosts_summary">Süsteemivaba hosts-tugi reklaamiblokeerijatest rakendustele</string>
<string name="settings_hosts_toast">Süsteemivaba hostsi moodul lisatud</string>
<string name="settings_app_name_hint">Uus nimi</string>
<string name="settings_app_name_helper">Rakendus pakitakse selle nimega</string>
<string name="settings_app_name_helper">Rakendus taaspakitakse selle nimega</string>
<string name="settings_app_name_error">Sobimatu vorming</string>
<string name="settings_su_app_adb">Rakendused ja ADB</string>
<string name="settings_su_app">Ainult rakendused</string>
@@ -140,12 +160,14 @@
<string name="request_timeout">Taotluse ajalõpp</string>
<string name="superuser_notification">Superkasutaja teavitus</string>
<string name="settings_su_reauth_title">Taas-autendi peale uuendust</string>
<string name="settings_su_reauth_summary">Taas-autendi superkasutaja õigused peale rakenduse uuendamist</string>
<string name="settings_su_reauth_summary">Pärast rakenduste uuendamist küsi superkasutaja luba uuesti</string>
<string name="settings_su_tapjack_title">Nupu varjamise kaitse</string>
<string name="settings_su_tapjack_summary">Superkasutaja taotluse hüpik ei reageeri vajutusele, kui seda katab mõni teine aken või ülekate</string>
<string name="settings_su_biometric_title">Luba biomeetriaga autentimine</string>
<string name="settings_su_biometric_summary">Kasuta superkasutaja taotluste kinnitamiseks biomeetrilist autentimist</string>
<string name="no_biometric">Mittetoetatud seade või ükski biomeetriaseadistus pole lubatud</string>
<string name="settings_customization">Kohandamine</string>
<string name="setting_add_shortcut_summary">Lisa avakuvale ilus otsetee, juhul kui nime ja ikooni on pärast rakenduse peitmist raske tuvastada</string>
<string name="setting_add_shortcut_summary">Lisa avakuvale ilus otsetee juhuks, kui nime ja ikooni on pärast rakenduse peitmist raske tuvastada</string>
<string name="settings_doh_title">DNS üle HTTPSi</string>
<string name="settings_doh_description">Väldi mõnes riigis DNSi mürgitamist</string>
@@ -182,6 +204,7 @@
<string name="flashing">Välgutamine…</string>
<string name="done">Valmis!</string>
<string name="failure">Ebaõnnestus</string>
<string name="hide_app_title">Magiski rakenduse peitmine…</string>
<string name="open_link_failed_toast">Lingi avamiseks sobivat rakendust ei leitud.</string>
<string name="complete_uninstall">Täielik eemaldus</string>
<string name="restore_img">Taasta tõmmised</string>
@@ -190,11 +213,22 @@
<string name="restore_fail">Originaalne varundus puudub!</string>
<string name="setup_fail">Seadistus ebaõnnnestus</string>
<string name="env_fix_title">Vajab lisaseadistust</string>
<string name="env_fix_msg">Sinu seade vajab Magiski korralikuks toimimiseks lisaseadistust. Kas soovid jätkata ning seadme taaskäivitada?</string>
<string name="setup_msg">Käivitan keskkonnaseadistust…</string>
<string name="authenticate">Autendi</string>
<string name="unsupport_magisk_title">Mittetoetatud Magiski versioon</string>
<string name="unsupport_magisk_msg">See rakenduse versioon ei toeta Magiski versioone, mis on vanemad kui %1$s.\n\nRakendus käitub nii, nagu Magisk ei olekski installitud, palun täienda Magiskit esimesel võimalusel.</string>
<string name="unsupport_general_title">Ebanormaalne seisund</string>
<string name="unsupport_system_app_msg">Selle rakenduse käitamine süsteemirakendusena ei ole toetatud. Palun taasta see kasutajarakenduseks.</string>
<string name="unsupport_other_su_msg">Tuvastati \"su\"-binaar, mida ei installinud Magisk. Palun eemalda mistahes konkureeriv juurkasutaja paigaldus ja/või taasinstalli Magisk.</string>
<string name="unsupport_external_storage_msg">Magisk on paigaldatud välismällu. Palun liiguta rakendus sisemällu.</string>
<string name="unsupport_nonroot_stub_msg">Peidetud Magiski rakendus ei saa enam töötada, kuna juurkasutaja on kadunud. Palun taasta originaalne APK.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">Selle funktsionaalsuse lubamiseks anna mäluruumi haldamise luba</string>
<string name="add_shortcut_title">Lisa avakuvale otsetee</string>
<string name="add_shortcut_msg">Pärast selle rakenduse peitmist võib selle nimi ja ikoon olla raskesti tuvastatav. Kas soovid avakuvale lisada ilusa otsetee?</string>
<string name="app_not_found">Selle tegevuse teostamiseks ei leitud ühtegi rakendust</string>
<string name="reboot_apply_change">Muudatuste rakendamiseks taaskäivita</string>
<string name="restore_app_confirmation">See taastab peidetud rakenduse uuesti originaalseks rakenduseks. Kas soovid tõesti seda teha?</string>
</resources>

View File

@@ -112,7 +112,6 @@
<string name="suspend_text_zygisk">Module suspendu car %1$s nest pas actif</string>
<string name="zygisk_module_unloaded">Module Zygisk non chargé en raison dune incompatibilité</string>
<!--Settings -->
<string name="settings_dark_mode_title">Mode du thème</string>
<string name="settings_dark_mode_message">Choisissez le mode qui correspond le mieux à votre style !</string>
@@ -191,9 +190,12 @@
<!--Notifications-->
<string name="update_channel">Mises à jour de Magisk</string>
<string name="progress_channel">Notifications de progression</string>
<string name="updated_channel">Mise à jour Terminée</string>
<string name="download_complete">Téléchargement terminé</string>
<string name="download_file_error">Erreur lors du téléchargement du fichier</string>
<string name="magisk_update_title">Une mise à jour de Magisk est disponible !</string>
<string name="updated_title">Magisk Mis à jour</string>
<string name="updated_text">Appuyer pour ouvrir lapplication</string>
<!--Toasts, Dialogs-->
<string name="yes">Oui</string>
@@ -226,6 +228,7 @@
<string name="unsupport_nonroot_stub_msg">Cette application ne peut continuer à fonctionner en étant masquée car laccès en tant que superutilisateur a été perdu. Merci de restaurer lAPK originel.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">Permettre laccès au stockage pour activer cette fonctionnalité</string>
<string name="install_unknown_denied">Autoriser "installation dapplications inconnues" pour activer cette fonctionnalité</string>
<string name="add_shortcut_title">Ajouter un raccourci à lécran daccueil</string>
<string name="add_shortcut_msg">Après avoir masqué Magisk, son nom et son icône peuvent devenir difficiles à reconnaître. Voulezvous ajouter un joli raccourci vers lécran daccueil ?</string>
<string name="app_not_found">Aucune application na été trouvée pour gérer cette action</string>

View File

@@ -23,16 +23,17 @@
<string name="home_notice_content">Scarica Magisk SOLTANTO dalla pagina GitHub ufficiale. I file provenienti da fonti sconosciute possono essere dannosi!</string>
<string name="home_support_title">Supportaci</string>
<string name="home_item_source">Codice sorgente</string>
<string name="home_support_content">Magisk è e sempre sarà gratuito ed open source. Puoi comunque mostrarci il tuo apprezzamento inviando una piccola donazione.</string>
<string name="home_support_content">Magisk è, e sempre sarà, gratuito ed open source. Puoi comunque mostrarci il tuo apprezzamento facendo una donazione.</string>
<string name="home_installed_version">Installata</string>
<string name="home_latest_version">Ultima</string>
<string name="invalid_update_channel">Canale di aggiornamento non valido</string>
<string name="uninstall_magisk_title">Disinstalla Magisk</string>
<string name="uninstall_magisk_msg">Tutti i moduli verranno disabilitati/rimossi!\nIl root verrà rimosso e i tuoi dati potrebbero essere criptati, nel caso non lo siano già.</string>
<string name="uninstall_magisk_msg">Tutti i moduli verranno disabilitati/rimossi!\nIl root verrà rimosso!\nGli spazi di archiviazione interni decriptati tramite l\'uso di Magisk verranno nuovamente criptati!</string>
<!--Install-->
<string name="keep_force_encryption">Mantieni crittografia forzata</string>
<string name="keep_dm_verity">Mantieni AVB 2.0/dm-verity</string>
<string name="patch_vbmeta">Correggi vbmeta nell\'immagine di boot</string>
<string name="recovery_mode">Modalità recovery</string>
<string name="install_options_title">Opzioni</string>
<string name="install_method_title">Metodo</string>
@@ -87,8 +88,6 @@
<string name="pid">PID: %1$d</string>
<string name="target_uid">Target UID: %1$d</string>
<!--SafetyNet-->
<!-- MagiskHide -->
<string name="show_system_app">Mostra app di sistema</string>
<string name="show_os_app">Mostra app del sistema operativo</string>
@@ -130,8 +129,8 @@
<string name="settings_update_channel_title">Canale di aggiornamento</string>
<string name="settings_update_stable">Stabile</string>
<string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Canale personalizzato</string>
<string name="settings_update_custom_msg">Inserisci un URL personalizzato</string>
<string name="settings_update_custom">Personalizzato</string>
<string name="settings_update_custom_msg">Inserisci l\'URL del canale personalizzato</string>
<string name="settings_zygisk_summary">Esegui parti di Magisk nel processo zygote</string>
<string name="settings_denylist_title">Applica lista di blocco</string>
<string name="settings_denylist_summary">Tutte le modifiche apportate da Magisk verranno annullate per i processi in lista di blocco</string>
@@ -160,15 +159,15 @@
<string name="superuser_notification">Notifica di accesso root</string>
<string name="settings_su_reauth_title">Riautentica dopo aggiornamento</string>
<string name="settings_su_reauth_summary">Richiedi nuovamente i permessi di root dopo l\'aggiornamento di un\'app</string>
<string name="settings_su_tapjack_title">Abilita protezione anti-tapjacking</string>
<string name="settings_su_tapjack_title">Protezione anti-tapjacking</string>
<string name="settings_su_tapjack_summary">La schermata di richiesta dei permessi di root non risponderà al tocco mentre è oscurata da altre finestre o elementi in sovraimpressione</string>
<string name="settings_su_biometric_title">Abilita autenticazione biometrica</string>
<string name="settings_su_biometric_title">Autenticazione biometrica</string>
<string name="settings_su_biometric_summary">Utilizza l\'autenticazione biometrica per accettare le richieste di accesso root</string>
<string name="no_biometric">Il dispositivo non è supportato o le impostazioni biometriche sono disattivate</string>
<string name="settings_customization">Personalizzazione</string>
<string name="setting_add_shortcut_summary">Aggiungi un collegamento alla schermata iniziale se il nome e l\'icona sono difficili da riconoscere dopo aver nascosto l\'app</string>
<string name="settings_doh_title">DNS over HTTPS</string>
<string name="settings_doh_description">Soluzione alternativa al DNS poisoning in alcune nazioni</string>
<string name="settings_doh_description">Aggira il DNS poisoning in alcune nazioni</string>
<string name="multiuser_mode">Modalità multiutente</string>
<string name="settings_owner_only">Solo per il proprietario del dispositivo</string>
@@ -187,11 +186,14 @@
<string name="isolate_summary">Ogni sessione di root avrà il suo namespace isolato</string>
<!--Notifications-->
<string name="update_channel">Aggiornamenti Magisk</string>
<string name="update_channel">Aggiornamenti di Magisk</string>
<string name="progress_channel">Notifiche di avanzamento</string>
<string name="updated_channel">Aggiornamento completato</string>
<string name="download_complete">Download completato</string>
<string name="download_file_error">Errore durante il download del file</string>
<string name="magisk_update_title">È disponibile un aggiornamento di Magisk!</string>
<string name="updated_title">Magisk è stato aggiornato</string>
<string name="updated_text">Tocca per aprire l\'app</string>
<!--Toasts, Dialogs-->
<string name="yes"></string>
@@ -216,14 +218,15 @@
<string name="setup_msg">Configurazione dell\'ambiente in corso…</string>
<string name="authenticate">Autentica</string>
<string name="unsupport_magisk_title">Versione di Magisk non supportata</string>
<string name="unsupport_magisk_msg">Questa versione dell\'app non supporta versioni di Magisk inferiori a %1$s.\n\nL\'app si comporterà come se Magisk non fosse installato: aggiornalo il prima possibile.</string>
<string name="unsupport_magisk_msg">Questa versione dell\'app non supporta le versioni di Magisk inferiori a %1$s.\n\nL\'app si comporterà come se Magisk non fosse installato: aggiornalo il prima possibile.</string>
<string name="unsupport_general_title">Stato anomalo rilevato</string>
<string name="unsupport_system_app_msg">L\'esecuzione di quest\'app come app di sistema non è supportata. Reinstallala come applicazione utente.</string>
<string name="unsupport_other_su_msg">È stato rilevato un comando \"su\" che non appartiene a Magisk. Rimuovilo per evitare malfunzionamenti.</string>
<string name="unsupport_other_su_msg">È stato rilevato un binario \"su\" che non appartiene a Magisk. Rimuovi qualsiasi altro sistema di root e/o reinstalla Magisk.</string>
<string name="unsupport_external_storage_msg">Magisk è installato nella memoria esterna. Sposta l\'app nella memoria interna.</string>
<string name="unsupport_nonroot_stub_msg">Dal momento che i permessi di root sono stati persi, l\'app non può più funzionare rimanendo nascosta. Ripristina l\'APK originale.</string>
<string name="unsupport_nonroot_stub_msg">Dal momento che i permessi di root sono stati persi, l\'app di Magisk nascosta non può più funzionare. Ripristina l\'APK originale.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">Consenti l\'accesso alla memoria del dispositivo per abilitare questa opzione</string>
<string name="install_unknown_denied">Consenti l\'installazione di app sconosciute per abilitare questa funzionalità</string>
<string name="add_shortcut_title">Aggiungi collegamento alla schermata iniziale</string>
<string name="add_shortcut_msg">Dopo aver nascosto quest\'app, il suo nome e la sua icona potrebbero diventare difficili da riconoscere. Vuoi aggiungere una scorciatoia alla schermata principale?</string>
<string name="app_not_found">Non è stata trovata un\'app per gestire questa azione</string>

View File

@@ -8,6 +8,7 @@
<string name="install">설치</string>
<string name="section_home"></string>
<string name="section_theme">테마</string>
<string name="denylist">거부목록</string>
<!--Home-->
<string name="no_connection">사용 가능한 연결 없음</string>
@@ -32,6 +33,7 @@
<!--Install-->
<string name="keep_force_encryption">강제 암호화 유지</string>
<string name="keep_dm_verity">AVB 2.0/dm-verity 유지</string>
<string name="patch_vbmeta">부트 이미지에 vbmeta 패치</string>
<string name="recovery_mode">리커버리 모드</string>
<string name="install_options_title">옵션</string>
<string name="install_method_title">설치 방법</string>
@@ -79,7 +81,7 @@
<!--Logs-->
<string name="log_data_none">로그가 없습니다. SU 권한을 필요로 하는 앱을 사용하십시오.</string>
<string name="log_data_magisk_none">로그가 없습니다.</string>
<string name="log_data_magisk_none">Magisk 로그가 없습니다.</string>
<string name="menuSaveLog">로그 저장</string>
<string name="menuClearLog">지금 로그 삭제</string>
<string name="logs_cleared">로그 삭제 완료.</string>
@@ -106,6 +108,9 @@
<string name="module_state_restore">복구</string>
<string name="module_action_install_external">저장소에서 설치</string>
<string name="update_available">업데이트 가능</string>
<string name="suspend_text_riru">%1$s 가 활성화 되어있기 때문에 모듈이 중단되었습니다</string>
<string name="suspend_text_zygisk">%1$s 가 비활성화 되어있기 때문에 모듈이 중단되었습니다</string>
<string name="zygisk_module_unloaded">호환성 문제로 인해 Zygisk 모듈이 로드되지 않았습니다.</string>
<!--Settings-->
<string name="settings_dark_mode_title">테마 선택</string>
@@ -130,6 +135,8 @@
<string name="settings_update_custom_msg">사용자 지정 URL 입력</string>
<string name="settings_zygisk_summary">zygote 데몬에서 Magisk 부분 실행</string>
<string name="settings_denylist_title">DenyList 적용</string>
<string name="settings_denylist_summary">DenyList의 프로세스는 Magisk의 모든 수정사항을 되돌립니다</string>
<string name="settings_denylist_error">이 기능을 사용하려면 %1$s 활성화가 필요합니다</string>
<string name="settings_denylist_config_title">DenyList 구성</string>
<string name="settings_denylist_config_summary">denylist에 포함할 프로세스를 선택합니다.</string>
<string name="settings_hosts_title">Systemless hosts</string>
@@ -175,7 +182,7 @@
<string name="mount_namespace_mode">이름공간 마운트 모드</string>
<string name="settings_ns_global">전역 이름공간</string>
<string name="settings_ns_requester">이름공간 상속</string>
<string name="settings_ns_isolate">이름공간 고립</string>
<string name="settings_ns_isolate">격리된 이름공간</string>
<string name="global_summary">모든 루트 세션이 전역 마운트 이름공간을 사용합니다.</string>
<string name="requester_summary">루트 세션은 요청자의 이름공간을 상속합니다.</string>
<string name="isolate_summary">각각의 루트 세션은 자신만의 독립된 이름공간을 사용합니다.</string>
@@ -183,19 +190,23 @@
<!--Notifications-->
<string name="update_channel">Magisk 업데이트</string>
<string name="progress_channel">진행 상황</string>
<string name="updated_channel">업데이트 완료</string>
<string name="download_complete">다운로드 완료</string>
<string name="download_file_error">파일 다운로드 오류</string>
<string name="magisk_update_title">새 버전의 Magisk를 사용할 수 있습니다!</string>
<string name="updated_title">업데이트 된 Magisk</string>
<string name="updated_text">터치하여 앱 열기</string>
<!--Toasts, Dialogs-->
<string name="yes"></string>
<string name="no">아니오</string>
<string name="repo_install_title">%1$s %2$s(%3$d) 설치</string>
<string name="download">다운로드</string>
<string name="reboot">다시 시작</string>
<string name="release_notes">릴리즈 노트</string>
<string name="flashing">플래싱 중…</string>
<string name="done">완료!</string>
<string name="failure">실패</string>
<string name="failure">실패!</string>
<string name="hide_app_title">Magisk 앱 숨기는 중…</string>
<string name="open_link_failed_toast">링크를 열 수 있는 앱이 없습니다.</string>
<string name="complete_uninstall">완전히 제거</string>
@@ -209,10 +220,19 @@
<string name="setup_msg">환경 설정 진행 중…</string>
<string name="authenticate">인증</string>
<string name="unsupport_magisk_title">지원되지 않는 Magisk 버전</string>
<string name="unsupport_magisk_msg">이 버전의 앱은 %1$s 미만의 Magisk 버전을 지원하지 않습니다.\n\n해당앱은 Magisk가 설치되지 않은것처럼 동작할것입니다. 가능한 빨리 Magisk 를 업데이트 하세요.</string>
<string name="unsupport_general_title">비정상적인 상태</string>
<string name="unsupport_system_app_msg">해당 앱을 시스템 앱으로 실행하는 것은 지원하지 않습니다. 앱을 일반사용자 앱으로 실행해 주세요.</string>
<string name="unsupport_other_su_msg">Magisk 로 부터 설치되지 않은 \"su\" 바이너리가 감지되었습니다. 다른 루팅 솔루션을 제거하거나, Magisk 를 다시 설치해주세요.</string>
<string name="unsupport_external_storage_msg">Magisk 가 외부 저장소에 설치되어 있습니다. Magisk 를 내부 저장소에 설치 해주세요.</string>
<string name="unsupport_nonroot_stub_msg">숨겨진 Magisk 앱은 루팅이 풀려 더이상 동작하지 않습니다. 원본 APK 를 복원하거나 재설치 해주세요.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">해당 기능을 사용하려면 저장소 권한을 허용해 주십시오.</string>
<string name="install_unknown_denied">이 기능을 활성화 하려면 "알수 없는 앱 설치"를 허용해주세요.</string>
<string name="add_shortcut_title">홈 화면에 바로가기 추가</string>
<string name="add_shortcut_msg">앱을 숨긴 후 아이콘과 이름을 알아보기 힘들 경우를 위해 알아보기 쉬운 바로가기를 홈 화면에 추가합니다.</string>
<string name="app_not_found">해당 작업을 처리할 어플리케이션이 없습니다.</string>
<string name="reboot_apply_change">변경 사항을 적용하려면 재부팅하세요.</string>
<string name="restore_app_confirmation">정말로 실행하시겠습니까? 숨겨진 앱이 원본 앱으로 복원됩니다.</string>
</resources>

View File

@@ -12,69 +12,73 @@
<!--Home-->
<string name="no_connection">Nenhuma conexão disponível</string>
<string name="hide">Ocultar</string>
<string name="app_changelog">Registro de alterações</string>
<string name="loading">Carregando…</string>
<string name="home_support_title">Contribua com o Projeto</string>
<string name="home_notice_content">Baixe o Magisk SOMENTE pela página oficial do Github. Arquivos de fontes desconhecidas podem ser maliciosos.</string>
<string name="home_item_source">Origem</string>
<string name="home_support_content">Magisk é, e sempre será, gratuito e de código aberto. No entanto, você pode nos agradecer enviando uma pequena doação.</string>
<string name="update">Atualizar</string>
<string name="not_available">N/A</string>
<string name="hide">Ocultar</string>
<string name="home_package">Pacote</string>
<string name="home_app_title">App</string>
<string name="home_notice_content">Baixe o Magisk SOMENTE pela página oficial do Github. Arquivos de fontes desconhecidas podem ser maliciosos e danificar seu aparelho.</string>
<string name="home_support_title">Contribua com o Projeto</string>
<string name="home_item_source">Fonte</string>
<string name="home_support_content">Magisk é, e sempre será, gratuito e de código aberto. No entanto, você pode agradecer enviando uma pequena doação.</string>
<string name="home_installed_version">Instalado</string>
<string name="home_latest_version">Recente</string>
<string name="invalid_update_channel">Canal de atualização inválido</string>
<string name="uninstall_magisk_title">Desinstalar Magisk</string>
<string name="uninstall_magisk_msg">Todos os módulos serão desativados/removidos!\nA raiz será removida!\nSeus dados potencialmente criptografados, se ainda não estiverem!</string>
<string name="update">Atualização</string>
<string name="uninstall_magisk_msg">Todos os módulos serão desativados/removidos!\nA raiz será removida!\nSeus dados não criptografados devido uso do Magisk, serão re-criptografados!</string>
<!--Install-->
<string name="keep_force_encryption">Manter a criptografia forçada</string>
<string name="keep_dm_verity">Manter o AVB 2.0/dm-verity</string>
<string name="keep_force_encryption">Manter criptografia forçada</string>
<string name="keep_dm_verity">Manter AVB 2.0/dm-verity</string>
<string name="patch_vbmeta">Corrigir vbmeta na imagem de boot</string>
<string name="recovery_mode">Modo de recuperação</string>
<string name="install_options_title">Opções</string>
<string name="install_method_title">Método</string>
<string name="install_next">Próximo</string>
<string name="install_start">Vamos lá</string>
<string name="manager_download_install">Pressione para baixar e instalar</string>
<string name="manager_download_install">Toque para baixar e instalar</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_msg">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.\nContinuar?</string>
<string name="install_inactive_slot_msg">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="setup_title">Configuração adicional</string>
<string name="select_patch_file">Selecione e corrija um arquivo</string>
<string name="patch_file_msg">Selecione uma imagem raw (*.img) ou um arquivo tar ODIN (*.tar)</string>
<string name="patch_file_msg">Selecione um arquivo imagem (*.img) ou um arquivo tar (*.tar)</string>
<string name="reboot_delay_toast">Reiniciando em 5 segundos…</string>
<string name="flash_screen_title">Instalação</string>
<!--Superuser-->
<string name="su_request_title">Solicitação de Superusuário</string>
<string name="touch_filtered_warning">Devido um app estar obscurecendo a solicitação de superusuário, o Magisk não pode conferir suas resposta</string>
<string name="deny">Negar</string>
<string name="prompt">Perguntar</string>
<string name="grant">Conceder</string>
<string name="su_warning">Concede acesso total ao seu dispositivo.\nNegar se você não tiver certeza!</string>
<string name="grant">Permitir</string>
<string name="su_warning">Permite acesso total ao seu aparelho.\nNão permita se você não tiver certeza do que está fazendo!</string>
<string name="forever">Sempre</string>
<string name="once">Uma vez</string>
<string name="tenmin">10 mins</string>
<string name="twentymin">20 mins</string>
<string name="thirtymin">30 mins</string>
<string name="sixtymin">60 mins</string>
<string name="su_allow_toast">%1$s foi concedido Acesso superusuário</string>
<string name="su_deny_toast">%1$s foi negado Acesso superusuário</string>
<string name="su_snack_grant">Acesso de superusuário de %1$s foram concedidos</string>
<string name="su_snack_deny">Os Acesso de superusuário de %1$s foram negados</string>
<string name="su_snack_notif_on">As notificações de %1$s foram habilitadas</string>
<string name="su_allow_toast">%1$s foi permitido o acesso Superusuário</string>
<string name="su_deny_toast">%1$s foi negado o acesso Superusuário</string>
<string name="su_snack_grant">Os acessos de Superusuário de %1$s foram permitidos</string>
<string name="su_snack_deny">Os acessos de Superusuário de %1$s foram negados</string>
<string name="su_snack_notif_on">As notificações de %1$s foram ativadas</string>
<string name="su_snack_notif_off">As notificações de %1$s foram desativadas</string>
<string name="su_snack_log_on">O registro de %1$s foi ativado</string>
<string name="su_snack_log_off">O registro de %1$s foi desativado</string>
<string name="su_snack_log_on">Os registros de %1$s foram ativados</string>
<string name="su_snack_log_off">Os registros de %1$s foram desativados</string>
<string name="su_revoke_title">Revogar?</string>
<string name="su_revoke_msg">Confirmar revogar Acesso de %1$s?</string>
<string name="toast">Pop-up no estilo Toast</string>
<string name="su_revoke_msg">Confirmar a revogação do acesso de %1$s?</string>
<string name="toast">Notificação (Pop-up)</string>
<string name="none">Nenhum</string>
<string name="superuser_toggle_notification">Notificações</string>
<string name="superuser_toggle_revoke">Revogar</string>
<string name="superuser_policy_none">Nenhum aplicativo solicitou permissão de superusuário ainda.</string>
<string name="superuser_policy_none">Nenhum app solicitou permissão de Superusuário ainda.</string>
<!--Logs-->
<string name="log_data_none">Você não tem registros, tente usar mais os aplicativos habilitados para SU.</string>
<string name="log_data_none">Não há registros. Tente usar os apps permitidos para Superusuário.</string>
<string name="log_data_magisk_none">Os Registro de atividade do Magisk estão vazios, isso é estranho.</string>
<string name="menuSaveLog">Salvar Registro</string>
<string name="menuClearLog">Limpar Registro agora</string>
@@ -82,62 +86,60 @@
<string name="pid">PID: %1$d</string>
<string name="target_uid">Alvo UID: %1$d</string>
<!--SafetyNet-->
<!-- MagiskHide -->
<string name="show_system_app">Mostrar aplicativos do sistema</string>
<string name="hide_filter_hint">Filtrar por nome</string>
<!--MagiskHide-->
<string name="show_system_app">Mostrar apps do Sistema</string>
<string name="show_os_app">Mostrar apps do Sistema</string>
<string name="hide_filter_hint">Filtrar pelo nome</string>
<string name="hide_search">Pesquisa</string>
<!--Module Fragment-->
<!--Module-->
<string name="no_info_provided">(Nenhuma informação fornecida)</string>
<string name="reboot_recovery">Reiniciar para Recovery</string>
<string name="reboot_bootloader">Reiniciar para Bootloader</string>
<string name="reboot_download">Reiniciar para Download</string>
<string name="reboot_edl">Reiniciar para EDL</string>
<string name="reboot_userspace">Reinício rápido</string>
<string name="reboot_recovery">Reiniciar em modo Recovery</string>
<string name="reboot_bootloader">Reiniciar em modo Bootloader</string>
<string name="reboot_download">Reiniciar em modo Download</string>
<string name="reboot_edl">Reiniciar em modo EDL</string>
<string name="module_version_author">%1$s por %2$s</string>
<string name="module_state_remove">Remover</string>
<string name="module_state_restore">Restaurar</string>
<string name="module_action_install_external">Instale a partir do armazenamento</string>
<string name="module_action_install_external">Instalar a partir do armazenamento</string>
<string name="update_available">Atualização disponível</string>
<string name="home_installed_version">Instalado</string>
<string name="suspend_text_riru">Módulo suspenso porque %1$s está ativo</string>
<string name="suspend_text_zygisk">Módulo suspenso porque %1$s não está ativo</string>
<string name="zygisk_module_unloaded">Modulo Zygisk não carregado devido a incompatibilidade</string>
<!--Settings -->
<!--Settings-->
<string name="settings_dark_mode_title">Modo de tema</string>
<string name="settings_dark_mode_message">Selecione o modo mais adequado ao seu estilo!</string>
<string name="settings_dark_mode_light">Sempre Claro</string>
<string name="settings_dark_mode_system">Baseado no Sistema</string>
<string name="settings_dark_mode_dark">Sempre Escuro</string>
<string name="settings_download_path_title">Caminho de Download</string>
<string name="settings_download_path_title">Caminho para Baixar</string>
<string name="settings_download_path_message">Os arquivos serão salvos em %1$s</string>
<string name="settings_hide_app_title">Ocultar o app do Magisk</string>
<string name="settings_hide_app_summary">Instala um app proxy com ID de pacote aleatório e nome de app personalizado</string>
<string name="settings_restore_app_title">Restaura o app do Magisk</string>
<string name="settings_restore_app_summary">Desocultar o app e restaurá-lo ao APK original</string>
<string name="settings_hide_app_summary">Instala o app ooulto com ID aleatório e nome personalizado</string>
<string name="settings_restore_app_title">Restaurar o app do Magisk</string>
<string name="settings_restore_app_summary">Desoculta o app do Magisk e restaura o APK original</string>
<string name="language">Idioma</string>
<string name="system_default">(Padrão do sistema)</string>
<string name="settings_check_update_title">Verificar atualizações</string>
<string name="settings_check_update_summary">Verifique periodicamente se há atualizações em segundo plano</string>
<string name="settings_check_update_summary">Verificar periodicamente em segundo plano se há atualizações</string>
<string name="settings_update_channel_title">Canal de Atualização</string>
<string name="settings_update_stable">Estável</string>
<string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Canal personalizado</string>
<string name="settings_update_custom_msg">Insira um URL personalizado</string>
<string name="settings_zygisk_summary">Roda partes do Magisk no Zygote</string>
<string name="settings_zygisk_summary">Executa partes do Magisk no Zygote</string>
<string name="settings_denylist_title">Aplicar lista de negação</string>
<string name="settings_denylist_summary">Os processos na lista de negação terão todas as modificações do Magisk revertidas</string>
<string name="settings_denylist_summary">Os processos na lista de negação terão revertidas todas as modificações do Magisk</string>
<string name="settings_denylist_error">Isso requer %1$s para ser ativado</string>
<string name="settings_denylist_config_title">Configurar lista de negação</string>
<string name="settings_denylist_config_summary">Selecione os processos a serem incluídos na lista de negação</string>
<string name="settings_hosts_title">Hosts systemless</string>
<string name="settings_hosts_summary">Suporte de hosts systemless para aplicativos Adblock</string>
<string name="settings_hosts_toast">Adicionado módulo de hosts systemless</string>
<string name="settings_hosts_title">Ativar /etc/hosts systemless</string>
<string name="settings_hosts_summary">Suporte de /etc/hosts fora do sistema para aplicativos Adblock</string>
<string name="settings_hosts_toast">Adicionado módulo do /etc/hosts systemless</string>
<string name="settings_app_name_hint">Novo nome</string>
<string name="settings_app_name_helper">O aplicativo será reinstalado para esse nome</string>
<string name="settings_app_name_helper">O app do Magisk será reinstalado com este nome</string>
<string name="settings_app_name_error">Formato inválido</string>
<string name="settings_su_app_adb">Aplicativos e ADB</string>
<string name="settings_su_app">Apenas aplicativos</string>
@@ -152,11 +154,11 @@
<string name="superuser_access">Acesso de Superusuário</string>
<string name="auto_response">Resposta automática</string>
<string name="request_timeout">Tempo limite da solicitação</string>
<string name="superuser_notification">Notificação de superusuário</string>
<string name="superuser_notification">Notificação de Superusuário</string>
<string name="settings_su_reauth_title">Autenticar novamente após a atualização</string>
<string name="settings_su_reauth_summary">Reautenticar permissões de superusuário após a atualização de um aplicativo</string>
<string name="settings_su_tapjack_title">Ativar proteção contra Tapjacking</string>
<string name="settings_su_tapjack_summary">A caixa de diálogo do superusuário não responderá à entrada enquanto estiver obscurecida por qualquer outra janela ou sobreposição</string>
<string name="settings_su_reauth_summary">Reautenticar permissões de Superusuário após atualizar aplicativo</string>
<string name="settings_su_tapjack_title">Ativar proteção contra atividades sobrepostas</string>
<string name="settings_su_tapjack_summary">A caixa de diálogo do Superusuário não responderá à entrada enquanto estiver obscurecida por qualquer outra janela ou sobreposição</string>
<string name="settings_su_biometric_title">Ativar autenticação biométrica</string>
<string name="settings_su_biometric_summary">Use a autenticação biométrica para permitir solicitações de superusuário</string>
<string name="no_biometric">Dispositivo não suportado ou nenhuma configuração biométrica está ativada</string>
@@ -164,57 +166,67 @@
<string name="setting_add_shortcut_summary">Adicione um atalho na tela inicial, caso o nome e o ícone sejam difíceis de reconhecer logo após ocultar o aplicativo</string>
<string name="settings_doh_title">DNS sobre HTTPS</string>
<string name="settings_doh_description">Solução alternativa para envenenamento de DNS em alguns países</string>
<string name="multiuser_mode">Modo multiusuário</string>
<string name="settings_owner_only">Somente proprietário do dispositivo</string>
<string name="settings_owner_manage">Gerenciado pelo proprietário do dispositivo</string>
<string name="settings_user_independent">Independente do usuário</string>
<string name="owner_only_summary">Somente o proprietário tem acesso root</string>
<string name="owner_manage_summary">Somente o proprietário pode gerenciar o acesso root e receber prompts de solicitação</string>
<string name="user_indepenent_summary">Cada usuário tem suas próprias regras para root separadas</string>
<string name="mount_namespace_mode">Montar modo de Namespace</string>
<string name="owner_only_summary">Somente o proprietário tem acesso ao Superusuário</string>
<string name="owner_manage_summary">Somente o proprietário pode gerenciar o acesso do Superusuário e receber pedidos de solicitação</string>
<string name="user_indepenent_summary">Cada usuário tem suas próprias regras de root separadas</string>
<string name="mount_namespace_mode">Ativar Modo Namespace</string>
<string name="settings_ns_global">Namespace global</string>
<string name="settings_ns_requester">Herdar Namespace</string>
<string name="settings_ns_isolate">Namespace isolado</string>
<string name="global_summary">Todas as sessões root usam o namespace de montagem global</string>
<string name="requester_summary">As sessões root herdarão o namespace do solicitante</string>
<string name="isolate_summary">Cada sessão root terá seu próprio namespace isolado</string>
<string name="isolate_summary">Cada sessão do Superusuário terá seu próprio namespace isolado</string>
<!--Notifications-->
<string name="update_channel">Atualizações do Magisk</string>
<string name="progress_channel">Notificações de progresso</string>
<string name="updated_channel">Atualização concluída</string>
<string name="download_complete">Download concluído</string>
<string name="download_file_error">Erro ao baixar o arquivo</string>
<string name="magisk_update_title">Atualização do Magisk disponível!</string>
<string name="download_file_error">Erro ao baixar arquivo</string>
<string name="magisk_update_title">Nova atualização do Magisk disponível!</string>
<string name="updated_title">Magisk Atualizado</string>
<string name="updated_text">Toque para abrir o app</string>
<!--Toasts, Dialogs-->
<string name="yes">Sim</string>
<string name="no">Não</string>
<string name="repo_install_title">Instalar %1$s %2$s(%3$d)</string>
<string name="download">Download</string>
<string name="reboot">Reinicializar</string>
<string name="release_notes">Notas de versão</string>
<string name="flashing">Flashando</string>
<string name="download">Baixar</string>
<string name="reboot">Reiniciar</string>
<string name="release_notes">Notas da atualização</string>
<string name="flashing">Fazendo Flash…</string>
<string name="done">Concluído!</string>
<string name="failure">Falha</string>
<string name="hide_app_title">Ocultando o app do Magisk…</string>
<string name="open_link_failed_toast">Nenhum aplicativo encontrado para abrir o link</string>
<string name="open_link_failed_toast">Nenhum app encontrado para abrir o link</string>
<string name="complete_uninstall">Desinstalação completa</string>
<string name="restore_img">Restaurar imagens</string>
   
<string name="restore_img_msg">Restaurando…</string>
<string name="restore_done">Restauração concluída!</string>
<string name="restore_fail">O backup stock não existe!</string>
<string name="restore_fail">O backup original não foi encontrado!</string>
<string name="setup_fail">Falha na instalação</string>
<string name="env_fix_title">Requer configuração adicional</string>
<string name="env_fix_msg">Seu dispositivo requer configuração adicional para o Magisk funcionar corretamente. Você quer continuar e reiniciar?</string>
<string name="env_fix_title">Configuração adicional exigida</string>
<string name="env_fix_msg">Seu dispositivo exige uma configuração adicional para o Magisk funcionar corretamente. Deseja continuar e reiniciar?</string>
<string name="setup_msg">Executando a configuração do ambiente…</string>
<string name="authenticate">Autenticar</string>
<string name="unsupport_magisk_title">Versão Magisk não suportada</string>
<string name="unsupport_magisk_msg">Essa versão do app não suporta versão do Magisk inferior a %1$s.\n\nO App irá se comportar como se nenhum Magisk estivesse sido instalado, por favor atualize o Magisk assim que possivel.</string>
<string name="unsupport_magisk_title">Versão do Magisk não suportada</string>
<string name="unsupport_magisk_msg">Essa versão do app não suporta versão do Magisk inferior a %1$s.\n\nO app irá se comportar como se nenhum Magisk estivesse sido instalado. Por favor, atualize o Magisk assim que possível.</string>
<string name="unsupport_general_title">Estado Anormal</string>
<string name="unsupport_system_app_msg">Não há suporte para executar este app como um app do sistema. Por favor, reverta o app para um app do usuário.</string>
<string name="unsupport_other_su_msg">Não foi possível detectar o binário \"su\" do Magisk. Por favor, remova qualquer outro root concorrente e/ou reinstale o Magisk.</string>
<string name="unsupport_external_storage_msg">O app do Magisk está instalado no armazenamento externo, Por favor, mova o app para o armazenamento interno.</string>
<string name="unsupport_nonroot_stub_msg">O app oculto do Magisk não pode continuar a funcionar porque o Superusuário foi perdido. Por favor, restaure o APK original.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">Autorize a permissão de armazenamento para ativar esta funcionalidade</string>
<string name="install_unknown_denied">Permita a "instalação apps desconhecidos" para ativar esta funcionalidade</string>
<string name="add_shortcut_title">Adicionar atalho à tela inicial</string>
<string name="add_shortcut_msg">Depois de ocultar o app, o seu nome e ícone ficarão difíceis de reconhecer. Você quer adicionar um atalho bonitinho na tela inicial?</string>
<string name="app_not_found">Nenhum aplicativo encontrado para realizar esta ação</string>
<string name="add_shortcut_msg">Depois de ocultar o app do Magisk, o seu nome e ícone ficarão difíceis de reconhecer. Deseja adicionar um atalho na tela inicial?</string>
<string name="app_not_found">Nenhum app encontrado para realizar esta ação</string>
<string name="reboot_apply_change">Reinicie para aplicar as mudanças</string>
<string name="restore_app_confirmation">Isso irá restaurar o app oculto do Magisk de volta para o app original. Deseja realmente fazer isso?</string>
</resources>

View File

@@ -1,61 +1,149 @@
<resources>
<!--Universal-->
<!--Welcome Activity-->
<!--Sections-->
<string name="modules">Módulos</string>
<string name="superuser">root</string>
<string name="logs">Registo</string>
<string name="settings">Definições</string>
<string name="superuser">Superusuário</string>
<string name="logs">Registros</string>
<string name="settings">Configurações</string>
<string name="install">Instalar</string>
<string name="section_home">Início</string>
<string name="section_theme">Temas</string>
<string name="denylist">Lista de Negação</string>
<!--Status Fragment-->
<!--Install Fragment-->
<string name="keep_force_encryption">Manter encriptação forçada</string>
<string name="keep_dm_verity">Manter AVB 2.0/dm-verity</string>
<string name="uninstall_magisk_title">Desinstalar Magisk</string>
<!--Home-->
<string name="no_connection">Nenhuma conexão disponível</string>
<string name="app_changelog">Registro de alterações</string>
<string name="loading">Carregando…</string>
<string name="update">Atualizar</string>
<!--Module Fragment-->
<string name="no_info_provided">(Nenhuma informação fornecida)</string>
<!--Repo Fragment-->
<string name="update_available">Atualização disponível</string>
<string name="not_available">N/A</string>
<string name="hide">Ocultar</string>
<string name="home_package">Pacote</string>
<string name="home_app_title">App</string>
<string name="home_notice_content">Baixe o Magisk SOMENTE pela página oficial do Github. Arquivos de fontes desconhecidas podem ser maliciosos e danificar seu aparelho.</string>
<string name="home_support_title">Contribua com o Projeto</string>
<string name="home_item_source">Fonte</string>
<string name="home_support_content">Magisk é, e sempre será, gratuito e de código aberto. No entanto, você pode agradecer enviando uma pequena doação.</string>
<string name="home_installed_version">Instalado</string>
<string name="home_latest_version">Recente</string>
<string name="invalid_update_channel">Canal de atualização inválido</string>
<string name="uninstall_magisk_title">Desinstalar Magisk</string>
<string name="uninstall_magisk_msg">Todos os módulos serão desativados/removidos!\nA raiz será removida!\nSeus dados não criptografados devido uso do Magisk, serão re-criptografados!</string>
<!--Log Fragment-->
<string name="menuSaveLog">Gravar registo</string>
<string name="menuClearLog">Limpar registo agora</string>
<string name="logs_cleared">Registo limpo com sucesso</string>
<!--Install-->
<string name="keep_force_encryption">Manter criptografia forçada</string>
<string name="keep_dm_verity">Manter AVB 2.0/dm-verity</string>
<string name="patch_vbmeta">Corrigir vbmeta na imagem de boot</string>
<string name="recovery_mode">Modo de recuperação</string>
<string name="install_options_title">Opções</string>
<string name="install_method_title">Método</string>
<string name="install_next">Próximo</string>
<string name="install_start">Vamos lá</string>
<string name="manager_download_install">Toque para baixar e instalar</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_msg">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="setup_title">Configuração adicional</string>
<string name="select_patch_file">Selecione e corrija um arquivo</string>
<string name="patch_file_msg">Selecione um arquivo imagem (*.img) ou um arquivo tar (*.tar)</string>
<string name="reboot_delay_toast">Reiniciando em 5 segundos…</string>
<string name="flash_screen_title">Instalação</string>
<!--About Activity-->
<string name="app_changelog">Lista de alterações da aplicação</string>
<!--Superuser-->
<string name="su_request_title">Solicitação de Superusuário</string>
<string name="touch_filtered_warning">Devido um app estar obscurecendo a solicitação de superusuário, o Magisk não pode conferir suas resposta</string>
<string name="deny">Negar</string>
<string name="prompt">Perguntar</string>
<string name="grant">Permitir</string>
<string name="su_warning">Permite acesso total ao seu aparelho.\nNão permita se você não tiver certeza do que está fazendo!</string>
<string name="forever">Sempre</string>
<string name="once">Uma vez</string>
<string name="tenmin">10 mins</string>
<string name="twentymin">20 mins</string>
<string name="thirtymin">30 mins</string>
<string name="sixtymin">60 mins</string>
<string name="su_allow_toast">%1$s foi permitido o acesso Superusuário</string>
<string name="su_deny_toast">%1$s foi negado o acesso Superusuário</string>
<string name="su_snack_grant">Os acessos de Superusuário de %1$s foram permitidos</string>
<string name="su_snack_deny">Os acessos de Superusuário de %1$s foram negados</string>
<string name="su_snack_notif_on">As notificações de %1$s foram ativadas</string>
<string name="su_snack_notif_off">As notificações de %1$s foram desativadas</string>
<string name="su_snack_log_on">Os registros de %1$s foram ativados</string>
<string name="su_snack_log_off">Os registros de %1$s foram desativados</string>
<string name="su_revoke_title">Revogar?</string>
<string name="su_revoke_msg">Confirmar a revogação do acesso de %1$s?</string>
<string name="toast">Notificação (Pop-up)</string>
<string name="none">Nenhum</string>
<string name="superuser_toggle_notification">Notificações</string>
<string name="superuser_toggle_revoke">Revogar</string>
<string name="superuser_policy_none">Nenhum app solicitou permissão de Superusuário ainda.</string>
<!--Toasts, Dialogs-->
<string name="repo_install_title">Instalar %1$s %2$s(%3$d)</string>
<string name="download">Transferir</string>
<string name="reboot">Reiniciar</string>
<string name="magisk_update_title">Nova atualização do Magisk disponível!</string>
<string name="release_notes">Notas da atualização</string>
<string name="manager_download_install">Pressione para transferir e instalar</string>
<string name="update_channel">Atualizações do Magisk</string>
<string name="flashing">A instalar</string>
<string name="direct_install">Instalar Diretamente (Recomendado)</string>
<string name="complete_uninstall">Desinstalação Completa</string>
<string name="restore_done">Restauração feita!</string>
<string name="download_file_error">Erro ao transferir ficheiro</string>
<!--Logs-->
<string name="log_data_none">Não há registros. Tente usar os apps permitidos para Superusuário.</string>
<string name="log_data_magisk_none">Os Registro de atividade do Magisk estão vazios, isso é estranho.</string>
<string name="menuSaveLog">Salvar Registro</string>
<string name="menuClearLog">Limpar Registro agora</string>
<string name="logs_cleared">Registro limpo com sucesso.</string>
<string name="pid">PID: %1$d</string>
<string name="target_uid">Alvo UID: %1$d</string>
<!--Settings Activity -->
<string name="language">Língua</string>
<string name="system_default">(Padrão do Sistema)</string>
<!--MagiskHide-->
<string name="show_system_app">Mostrar apps do Sistema</string>
<string name="show_os_app">Mostrar apps do Sistema</string>
<string name="hide_filter_hint">Filtrar pelo nome</string>
<string name="hide_search">Pesquisa</string>
<!--Module-->
<string name="no_info_provided">(Nenhuma informação fornecida)</string>
<string name="reboot_userspace">Reinício rápido</string>
<string name="reboot_recovery">Reiniciar em modo Recovery</string>
<string name="reboot_bootloader">Reiniciar em modo Bootloader</string>
<string name="reboot_download">Reiniciar em modo Download</string>
<string name="reboot_edl">Reiniciar em modo EDL</string>
<string name="module_version_author">%1$s por %2$s</string>
<string name="module_state_remove">Remover</string>
<string name="module_state_restore">Restaurar</string>
<string name="module_action_install_external">Instalar a partir do armazenamento</string>
<string name="update_available">Atualização disponível</string>
<string name="suspend_text_riru">Módulo suspenso porque %1$s está ativo</string>
<string name="suspend_text_zygisk">Módulo suspenso porque %1$s não está ativo</string>
<string name="zygisk_module_unloaded">Modulo Zygisk não carregado devido a incompatibilidade</string>
<!--Settings-->
<string name="settings_dark_mode_title">Modo de tema</string>
<string name="settings_dark_mode_message">Selecione o modo mais adequado ao seu estilo!</string>
<string name="settings_dark_mode_light">Sempre Claro</string>
<string name="settings_dark_mode_system">Baseado no Sistema</string>
<string name="settings_dark_mode_dark">Sempre Escuro</string>
<string name="settings_download_path_title">Caminho para Baixar</string>
<string name="settings_download_path_message">Os arquivos serão salvos em %1$s</string>
<string name="settings_hide_app_title">Ocultar o app do Magisk</string>
<string name="settings_hide_app_summary">Instala o app ooulto com ID aleatório e nome personalizado</string>
<string name="settings_restore_app_title">Restaurar o app do Magisk</string>
<string name="settings_restore_app_summary">Desoculta o app do Magisk e restaura o APK original</string>
<string name="language">Idioma</string>
<string name="system_default">(Padrão do sistema)</string>
<string name="settings_check_update_title">Verificar atualizações</string>
<string name="settings_check_update_summary">Verificar periodicamente em segundo plano se há atualizações</string>
<string name="settings_update_channel_title">Canal de Atualização</string>
<string name="settings_update_stable">Estável</string>
<string name="settings_update_beta">Beta</string>
<string name="settings_hosts_title">Ativar systemless hosts</string>
<string name="settings_hosts_summary">Suporte de systemless para aplicações Adblock</string>
<string name="settings_su_app_adb">Aplicações e ADB</string>
<string name="settings_su_app">Somente Aplicações</string>
<string name="settings_su_adb">Somente ADB</string>
<string name="settings_update_custom">Canal personalizado</string>
<string name="settings_update_custom_msg">Insira um URL personalizado</string>
<string name="settings_zygisk_summary">Executa partes do Magisk no Zygote</string>
<string name="settings_denylist_title">Aplicar lista de negação</string>
<string name="settings_denylist_summary">Os processos na lista de negação terão revertidas todas as modificações do Magisk</string>
<string name="settings_denylist_error">Isso requer %1$s para ser ativado</string>
<string name="settings_denylist_config_title">Configurar lista de negação</string>
<string name="settings_denylist_config_summary">Selecione os processos a serem incluídos na lista de negação</string>
<string name="settings_hosts_title">Ativar /etc/hosts systemless</string>
<string name="settings_hosts_summary">Suporte de /etc/hosts fora do sistema para aplicativos Adblock</string>
<string name="settings_hosts_toast">Adicionado módulo do /etc/hosts systemless</string>
<string name="settings_app_name_hint">Novo nome</string>
<string name="settings_app_name_helper">O app do Magisk será reinstalado com este nome</string>
<string name="settings_app_name_error">Formato inválido</string>
<string name="settings_su_app_adb">Aplicativos e ADB</string>
<string name="settings_su_app">Apenas aplicativos</string>
<string name="settings_su_adb">Apenas ADB</string>
<string name="settings_su_disable">Desativado</string>
<string name="settings_su_request_10">10 segundos</string>
<string name="settings_su_request_15">15 segundos</string>
@@ -63,56 +151,82 @@
<string name="settings_su_request_30">30 segundos</string>
<string name="settings_su_request_45">45 segundos</string>
<string name="settings_su_request_60">60 segundos</string>
<string name="superuser_access">Acesso de root</string>
<string name="auto_response">Resposta Automática</string>
<string name="request_timeout">Tempo limite de solicitação</string>
<string name="superuser_notification">Notificação de root</string>
<string name="settings_su_reauth_title">Autenticar novamente após atualizar</string>
<string name="settings_su_reauth_summary">Autenticar novamente permissões de root após atualizar aplicações</string>
<string name="superuser_access">Acesso de Superusuário</string>
<string name="auto_response">Resposta automática</string>
<string name="request_timeout">Tempo limite da solicitação</string>
<string name="superuser_notification">Notificação de Superusuário</string>
<string name="settings_su_reauth_title">Autenticar novamente após a atualização</string>
<string name="settings_su_reauth_summary">Reautenticar permissões de Superusuário após atualizar aplicativo</string>
<string name="settings_su_tapjack_title">Ativar proteção contra atividades sobrepostas</string>
<string name="settings_su_tapjack_summary">A caixa de diálogo do Superusuário não responderá à entrada enquanto estiver obscurecida por qualquer outra janela ou sobreposição</string>
<string name="settings_su_biometric_title">Ativar autenticação biométrica</string>
<string name="settings_su_biometric_summary">Use a autenticação biométrica para permitir solicitações de superusuário</string>
<string name="no_biometric">Dispositivo não suportado ou nenhuma configuração biométrica está ativada</string>
<string name="settings_customization">Personalizações</string>
<string name="setting_add_shortcut_summary">Adicione um atalho na tela inicial, caso o nome e o ícone sejam difíceis de reconhecer logo após ocultar o aplicativo</string>
<string name="settings_doh_title">DNS sobre HTTPS</string>
<string name="settings_doh_description">Solução alternativa para envenenamento de DNS em alguns países</string>
<string name="multiuser_mode">Modo multiusuário</string>
<string name="settings_owner_only">Somente proprietário do dispositivo</string>
<string name="settings_owner_manage">Gerenciado pelo proprietário do dispositivo</string>
<string name="settings_user_independent">Independente do usuário</string>
<string name="owner_only_summary">Somente o proprietário tem acesso ao Superusuário</string>
<string name="owner_manage_summary">Somente o proprietário pode gerenciar o acesso do Superusuário e receber pedidos de solicitação</string>
<string name="user_indepenent_summary">Cada usuário tem suas próprias regras de root separadas</string>
<string name="mount_namespace_mode">Ativar Modo Namespace</string>
<string name="settings_ns_global">Namespace global</string>
<string name="settings_ns_requester">Herdar Namespace</string>
<string name="settings_ns_isolate">Namespace isolado</string>
<string name="global_summary">Todas as sessões root usam o namespace de montagem global</string>
<string name="requester_summary">As sessões root herdarão o namespace do solicitante</string>
<string name="isolate_summary">Cada sessão do Superusuário terá seu próprio namespace isolado</string>
<string name="multiuser_mode">Modo Multi-Utilizador</string>
<string name="settings_owner_only">Apenas Proprietário de Dispositivo</string>
<string name="settings_owner_manage">Gerido Proprietário do Dispositivo</string>
<string name="settings_user_independent">Independente de Utilizadores</string>
<string name="owner_only_summary">Apenas o proprietário tem acesso a root</string>
<string name="owner_manage_summary">Apenas o proprietário pode gerir acesso root e receber pedidos</string>
<string name="user_indepenent_summary">Cada utilizador tem suas próprias regras de root separadas</string>
<!--Notifications-->
<string name="update_channel">Atualizações do Magisk</string>
<string name="progress_channel">Notificações de progresso</string>
<string name="updated_channel">Atualização concluída</string>
<string name="download_complete">Download concluído</string>
<string name="download_file_error">Erro ao baixar arquivo</string>
<string name="magisk_update_title">Nova atualização do Magisk disponível!</string>
<string name="updated_title">Magisk Atualizado</string>
<string name="updated_text">Toque para abrir o app</string>
<string name="mount_namespace_mode">Cada sessão root terá sua própria identificação isolada</string>
<string name="settings_ns_global">Identificação Global</string>
<string name="settings_ns_requester">Herdar Identificação</string>
<string name="settings_ns_isolate">Identificação Isolada</string>
<string name="global_summary">Todas as sessões root usam a identificação de montagem global</string>
<string name="requester_summary">As sessões de root herdarão a identificação do seu solicitante</string>
<string name="isolate_summary">Cada sessão root terá sua própria identificação isolada</string>
<!--Superuser-->
<string name="su_request_title">Pedido de root</string>
<string name="deny">Negar</string>
<string name="prompt">Perguntar</string>
<string name="grant">Permitir</string>
<string name="su_warning">Concede acesso total ao seu dispositivo.
\nNegue se não tiver certeza!</string>
<string name="forever">Sempre</string>
<string name="once">Uma vez</string>
<string name="tenmin">10 minutos</string>
<string name="twentymin">20 minutos</string>
<string name="thirtymin">30 minutos</string>
<string name="sixtymin">60 minutos</string>
<string name="su_allow_toast">%1$s foi permitido o acesso de root</string>
<string name="su_deny_toast">%1$s foi negado o acesso de root</string>
<string name="su_snack_grant">Acesso de root a %1$s foi permitido</string>
<string name="su_snack_deny">Acesso de root a %1$s foi negado</string>
<string name="su_snack_notif_on">Notificações de %1$s está ativado</string>
<string name="su_snack_notif_off">Notificações da %1$s está desativado</string>
<string name="su_snack_log_on">Registo de %1$s está ativado</string>
<string name="su_snack_log_off">Registo de %1$s está desativado</string>
<string name="su_revoke_title">Revogar?</string>
<string name="su_revoke_msg">Revogar os diretos do %1$s, Confirmar?</string>
<string name="toast">Notificação(pop-up)</string>
<string name="none">Nenhum</string>
<!--Superuser logs-->
<string name="target_uid">Alvo UID: %1$d</string>
<!--Toasts, Dialogs-->
<string name="yes">Sim</string>
<string name="no">Não</string>
<string name="repo_install_title">Instalar %1$s %2$s(%3$d)</string>
<string name="download">Baixar</string>
<string name="reboot">Reiniciar</string>
<string name="release_notes">Notas da atualização</string>
<string name="flashing">Fazendo Flash…</string>
<string name="done">Concluído!</string>
<string name="failure">Falha</string>
<string name="hide_app_title">Ocultando o app do Magisk…</string>
<string name="open_link_failed_toast">Nenhum app encontrado para abrir o link</string>
<string name="complete_uninstall">Desinstalação completa</string>
<string name="restore_img">Restaurar imagens</string>
<string name="restore_img_msg">Restaurando…</string>
<string name="restore_done">Restauração concluída!</string>
<string name="restore_fail">O backup original não foi encontrado!</string>
<string name="setup_fail">Falha na instalação</string>
<string name="env_fix_title">Configuração adicional exigida</string>
<string name="env_fix_msg">Seu dispositivo exige uma configuração adicional para o Magisk funcionar corretamente. Deseja continuar e reiniciar?</string>
<string name="setup_msg">Executando a configuração do ambiente…</string>
<string name="authenticate">Autenticar</string>
<string name="unsupport_magisk_title">Versão do Magisk não suportada</string>
<string name="unsupport_magisk_msg">Essa versão do app não suporta versão do Magisk inferior a %1$s.\n\nO app irá se comportar como se nenhum Magisk estivesse sido instalado. Por favor, atualize o Magisk assim que possível.</string>
<string name="unsupport_general_title">Estado Anormal</string>
<string name="unsupport_system_app_msg">Não há suporte para executar este app como um app do sistema. Por favor, reverta o app para um app do usuário.</string>
<string name="unsupport_other_su_msg">Não foi possível detectar o binário \"su\" do Magisk. Por favor, remova qualquer outro root concorrente e/ou reinstale o Magisk.</string>
<string name="unsupport_external_storage_msg">O app do Magisk está instalado no armazenamento externo, Por favor, mova o app para o armazenamento interno.</string>
<string name="unsupport_nonroot_stub_msg">O app oculto do Magisk não pode continuar a funcionar porque o Superusuário foi perdido. Por favor, restaure o APK original.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">Autorize a permissão de armazenamento para ativar esta funcionalidade</string>
<string name="install_unknown_denied">Permita a "instalação apps desconhecidos" para ativar esta funcionalidade</string>
<string name="add_shortcut_title">Adicionar atalho à tela inicial</string>
<string name="add_shortcut_msg">Depois de ocultar o app do Magisk, o seu nome e ícone ficarão difíceis de reconhecer. Deseja adicionar um atalho na tela inicial?</string>
<string name="app_not_found">Nenhum app encontrado para realizar esta ação</string>
<string name="reboot_apply_change">Reinicie para aplicar as mudanças</string>
<string name="restore_app_confirmation">Isso irá restaurar o app oculto do Magisk de volta para o app original. Deseja realmente fazer isso?</string>
</resources>

View File

@@ -23,16 +23,17 @@
<string name="home_notice_content">Descarcă Magisk NUMAI de pe pagina oficială GitHub. Fișierele din surse necunoscute pot fi rău intenționate!</string>
<string name="home_support_title">Sprijină-ne</string>
<string name="home_item_source">Sursă</string>
<string name="home_support_content">Magisk este și va fi întotdeauna gratuit și open-source. Cu toate acestea, ne poți arăta că îți pasă trimițând o mică donație.</string>
<string name="home_support_content">Magisk este și va fi întotdeauna gratuit și open-source. Cu toate acestea, ne poți arăta că îți pasă făcând o donație.</string>
<string name="home_installed_version">Versiune instalată</string>
<string name="home_latest_version">Ultima versiune</string>
<string name="invalid_update_channel">Canal de actualizare nevalid</string>
<string name="uninstall_magisk_title">Dezinstalează Magisk</string>
<string name="uninstall_magisk_msg">Toate modulele vor fi dezactivate/eliminate!\nRootul va fi eliminat!\nPotențial ți se vor cripta datele dacă nu sunt criptate deja!</string>
<string name="uninstall_magisk_msg">Toate modulele vor fi dezactivate/eliminate!\nRootul va fi eliminat!\nOrice spațiu de stocare intern necriptat prin folosirea Magisk va fi recriptat!</string>
<!--Install-->
<string name="keep_force_encryption">Păstrează criptarea forțată</string>
<string name="keep_dm_verity">Păstrează AVB 2.0/dm-verity</string>
<string name="patch_vbmeta">Patchuiește vbmeta în imaginea de boot</string>
<string name="recovery_mode">Mod de recuperare</string>
<string name="install_options_title">Opțiuni</string>
<string name="install_method_title">Metodă</string>
@@ -70,16 +71,16 @@
<string name="su_snack_log_on">Jurnalizarea pentru %1$s a fost activată</string>
<string name="su_snack_log_off">Jurnalizarea pentru %1$s a fost dezactivată</string>
<string name="su_revoke_title">Revoci?</string>
<string name="su_revoke_msg">Confirmi revocarea drepturilor pentru %1$s?</string>
<string name="su_revoke_msg">Confirmă revocarea drepturilor de superutilizator pentru %1$s</string>
<string name="toast">Mesaj</string>
<string name="none">Niciuna</string>
<string name="superuser_toggle_notification">Notificări</string>
<string name="superuser_toggle_revoke">Revocă</string>
<string name="superuser_policy_none">Nicio aplicație nu a cerut încă permisiuni de superutilizator.</string>
<string name="superuser_policy_none">Nicio aplicație nu a cerut încă permisiunea de superutilizator.</string>
<!--Logs-->
<string name="log_data_none">Nu există jurnale, încearcă să folosești ceva mai mult aplicațiile cu acces de superutilizator</string>
<string name="log_data_none">Nu există jurnale, încearcă să folosești ceva mai mult aplicațiile care folosesc root</string>
<string name="log_data_magisk_none">Jurnalele Magisk sunt goale, asta-i ciudat</string>
<string name="menuSaveLog">Salvează jurnalul</string>
<string name="menuClearLog">Golește jurnalul acum</string>
@@ -107,6 +108,9 @@
<string name="module_state_restore">Restaurează</string>
<string name="module_action_install_external">Instalează din spațiul de stocare</string>
<string name="update_available">Actualizare disponibilă</string>
<string name="suspend_text_riru">Modul suspendat deoarece %1$s este activat</string>
<string name="suspend_text_zygisk">Modul suspendat deoarece %1$s nu este activat</string>
<string name="zygisk_module_unloaded">Modulul Zygisk nu a fost încărcat din cauza incompatibilității</string>
<!--Settings-->
<string name="settings_dark_mode_title">Mod pentru temă</string>
@@ -119,7 +123,7 @@
<string name="settings_hide_app_title">Ascunde aplicația Magisk</string>
<string name="settings_hide_app_summary">Instalează o aplicație proxy cu ID aleatoriu pentru pachet și etichetă personalizată pentru aplicație</string>
<string name="settings_restore_app_title">Restaurează aplicația Magisk</string>
<string name="settings_restore_app_summary">Dezvăluie aplicația și restaureaz-o înapoi în APK-ul original</string>
<string name="settings_restore_app_summary">Dezvăluie aplicația și restaurează APK-ul original</string>
<string name="language">Limbă</string>
<string name="system_default">(Implicită a sistemului)</string>
<string name="settings_check_update_title">Caută actualizări</string>
@@ -127,8 +131,8 @@
<string name="settings_update_channel_title">Canal de actualizare</string>
<string name="settings_update_stable">Stabil</string>
<string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Canal personalizat</string>
<string name="settings_update_custom_msg">Inserează un URL personalizat</string>
<string name="settings_update_custom">Personalizat</string>
<string name="settings_update_custom_msg">Inserează un URL pentru canal personalizat</string>
<string name="settings_zygisk_summary">Rulează părți ale Magisk în daemonul zygote</string>
<string name="settings_denylist_title">Impune lista de refuzări</string>
<string name="settings_denylist_summary">Procesele din lista de refuzări vor avea toate modificările Magisk anulate</string>
@@ -136,7 +140,7 @@
<string name="settings_denylist_config_title">Configurează lista de refuzări</string>
<string name="settings_denylist_config_summary">Selectează procesele care vor fi incluse în lista de refuzări</string>
<string name="settings_hosts_title">Fișier hosts în afara partiției system</string>
<string name="settings_hosts_summary">Suport pentru fișierul hosts în afara partiției system, în cazul aplicațiilor adblock</string>
<string name="settings_hosts_summary">Suport pentru fișierul hosts în afara partiției system, în cazul aplicațiilor care blochează reclame</string>
<string name="settings_hosts_toast">Modulul pentru fișierul hosts în afara partiției system, adăugat</string>
<string name="settings_app_name_hint">Nume nou</string>
<string name="settings_app_name_helper">Aplicația va fi reîmpachetată cu acest nume</string>
@@ -156,10 +160,10 @@
<string name="request_timeout">Expirare pentru cerere</string>
<string name="superuser_notification">Notificare de superutilizator</string>
<string name="settings_su_reauth_title">Reautentificare după actualizare</string>
<string name="settings_su_reauth_summary">Reautentifică permisiunile pentru superutilizator după o actualizare a aplicației</string>
<string name="settings_su_tapjack_title">Activează protecția față de tapjacking</string>
<string name="settings_su_tapjack_summary">Caseta de dialog pentru solicitarea drepturilor de superutilizator nu va răspunde la input cât timp este ascunsă de orice altă fereastră sau suprapunere</string>
<string name="settings_su_biometric_title">Activează autentificarea biometrică</string>
<string name="settings_su_reauth_summary">Cere din nou permisiunile de superutilizator după actualizarea aplicațiilor</string>
<string name="settings_su_tapjack_title">Protecție față de tapjacking</string>
<string name="settings_su_tapjack_summary">Caseta de dialog pentru solicitarea permisiunilor de superutilizator nu va răspunde la input cât timp este ascunsă de orice altă fereastră sau suprapunere</string>
<string name="settings_su_biometric_title">Autentificare biometrică</string>
<string name="settings_su_biometric_summary">Folosește autentificarea biometrică pentru a permite cereri de superutilizator</string>
<string name="no_biometric">Dispozitiv nesuportat sau nu sunt activate setări biometrice</string>
<string name="settings_customization">Personalizare</string>
@@ -186,9 +190,12 @@
<!--Notifications-->
<string name="update_channel">Actualizări Magisk</string>
<string name="progress_channel">Notificări de progres</string>
<string name="updated_channel">Actualizare finalizată</string>
<string name="download_complete">Descărcare finalizată</string>
<string name="download_file_error">Eroare la descărcarea fișierului</string>
<string name="magisk_update_title">Actualizare Magisk disponibilă!</string>
<string name="updated_title">Magisk actualizat</string>
<string name="updated_text">Atinge pentru a deschide aplicația</string>
<!--Toasts, Dialogs-->
<string name="yes">Da</string>
@@ -213,17 +220,19 @@
<string name="setup_msg">Rulează configurarea mediului…</string>
<string name="authenticate">Autentificare</string>
<string name="unsupport_magisk_title">Versiune Magisk nesuportată</string>
<string name="unsupport_magisk_msg">Această versiune a aplicației nu suportă versiunea Magisk mai mică de %1$s.\n\nAplicația se va comporta ca și cum Magisk nu este instalat, te rugăm să actualizezi Magisk cât mai curând posibil.</string>
<string name="unsupport_magisk_msg">Această versiune a aplicației nu suportă versiunile Magisk mai mici de %1$s.\n\nAplicația se va comporta ca și cum Magisk nu este instalat, te rugăm să actualizezi Magisk cât mai curând posibil.</string>
<string name="unsupport_general_title">Stare anormală</string>
<string name="unsupport_system_app_msg">Rularea acestei aplicații ca aplicație de sistem nu este suportată. Te rugăm să readuci aplicația într-o aplicație de utilizator.</string>
<string name="unsupport_other_su_msg">Este detectată o comandă „su” care nu aparține Magisk. Te rugăm să elimini cealaltă aplicație su nesuportată.</string>
<string name="unsupport_other_su_msg">A fost detectat un binar „su” care nu provine de la Magisk. Te rugăm să elimini orice soluție root concurentă și/sau să reinstalezi Magisk.</string>
<string name="unsupport_external_storage_msg">Magisk este instalat în spațiul de stocare extern. Te rugăm să muți aplicația în spațiul de stocare intern.</string>
<string name="unsupport_nonroot_stub_msg">Aplicația nu poate continua să funcționeze în starea ascunsă, deoarece rootul a fost pierdut. Te rugăm să o restaurezi înapoi în APK-ul original.</string>
<string name="unsupport_nonroot_stub_msg">Aplicația Magisk ascunsă nu poate continua să funcționeze deoarece rootul a fost pierdut. Te rugăm să restaurezi APK-ul original.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">Acordă permisiunea de stocare pentru a activa această funcționalitate</string>
<string name="install_unknown_denied">Permite „instalarea de aplicații necunoscute” pentru a activa această funcționalitate</string>
<string name="add_shortcut_title">Adaugă comandă rapidă pe ecranul de pornire</string>
<string name="add_shortcut_msg">După ascunderea acestei aplicații, numele și pictograma acesteia ar putea deveni dificil de recunoscut. Vrei să adaugi o comandă rapidă frumoasă pe ecranul de pornire?</string>
<string name="app_not_found">Nu s-a găsit nicio aplicație care să gestioneze această acțiune</string>
<string name="reboot_apply_change">Repornește pentru a aplica modificările</string>
<string name="reboot_apply_change">Repornește pentru a aplica modificările</string>
<string name="restore_app_confirmation">Acest lucru va restaura aplicația ascunsă în aplicația originală. Sigur vrei să faci asta?</string>
</resources>

View File

@@ -190,9 +190,12 @@
<!--Notifications-->
<string name="update_channel">Обновление Magisk</string>
<string name="progress_channel">Уведомления о прогрессе</string>
<string name="updated_channel">Обновление завершено</string>
<string name="download_complete">Загрузка завершена</string>
<string name="download_file_error">Ошибка загрузки файла</string>
<string name="magisk_update_title">Доступно обновление Magisk!</string>
<string name="updated_title">Magisk обновлён</string>
<string name="updated_text">Нажмите, чтобы открыть</string>
<!--Toasts, Dialogs-->
<string name="yes">Да</string>
@@ -224,7 +227,8 @@
<string name="unsupport_external_storage_msg">Приложение установлено во внешнее хранилище. Пожалуйста, переустановите его во внутреннее хранилище.</string>
<string name="unsupport_nonroot_stub_msg">Пересобранное для скрытия приложение Magisk не может дальше работать, поскольку Root-права недоступны. Пожалуйста, восстановите приложение к исходному состоянию.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">Пожалуйста, предоставьте доступ к хранилищу</string>
<string name="external_rw_permission_denied">Предоставьте разрешение на доступ к хранилищу</string>
<string name="install_unknown_denied">Предоставьте разрешение на "Установку из неизвестных источников"</string>
<string name="add_shortcut_title">Добавление ярлыка</string>
<string name="add_shortcut_msg">После скрытия приложения Magisk его название и иконка могут быть неудобны для восприятия. Хотите создать ярлык на рабочем столе?</string>
<string name="app_not_found">Приложение для обработки этого действия не найдено</string>

View File

@@ -33,6 +33,7 @@
<!--Install-->
<string name="keep_force_encryption">Ponechať vynútené šifrovanie</string>
<string name="keep_dm_verity">Ponechať AVB 2.0/dm-verity</string>
<string name="patch_vbmeta">Zaplátať vbmeta v boot image</string>
<string name="recovery_mode">Režim Recovery</string>
<string name="install_options_title">Možnosti</string>
<string name="install_method_title">Metóda</string>
@@ -189,9 +190,12 @@
<!--Notifications-->
<string name="update_channel">Aktualizácie Magisku</string>
<string name="progress_channel">Upozornenia o priebehu</string>
<string name="updated_channel">Aktualizácia dokončená</string>
<string name="download_complete">Sťahovanie ukončené</string>
<string name="download_file_error">Chyba sťahovania súboru</string>
<string name="magisk_update_title">Je dostupná aktualizácia Magisku!</string>
<string name="updated_title">Magisk aktualizovaný</string>
<string name="updated_text">Ťuknutím otvoríte apku</string>
<!--Toasts, Dialogs-->
<string name="yes">Áno</string>
@@ -224,6 +228,7 @@
<string name="unsupport_nonroot_stub_msg">Skrytá aplikácia Magisk nemôže pokračovať v práci, lebo root sa stratil. Prosím, obnovte ju z pôvodného súboru APK.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">Udeľte povolenie pre povolenie tejto funkcie</string>
<string name="install_unknown_denied">Povoľte "inštaláciu neznámych aplikácii" na povolenie tejto funkcie</string>
<string name="add_shortcut_title">Pridať odkaz na domovskú obrazovku</string>
<string name="add_shortcut_msg">Po skrytí tejto aplikácie sa jej názov a ikona môžu stať ťažko rozoznateľnými. Chcete pridať krajší odkaz na domovskú obrazovku?</string>
<string name="app_not_found">Nenašla sa žiadna aplikácia, ktorá dokáže spracovať túto akciu</string>

View File

@@ -106,7 +106,7 @@
<string name="module_version_author">%1$s nga %2$s</string>
<string name="module_state_remove">Hiqe</string>
<string name="module_state_restore">Rikëthe</string>
<string name="module_action_install_external">Instaloni nga ruajtja</string>
<string name="module_action_install_external">Instaloni nga sdcard</string>
<string name="update_available">Përditësimi në dispozicion</string>
<string name="suspend_text_riru">Moduli u pezullua sepse %1$s është aktivizuar</string>
<string name="suspend_text_zygisk">Moduli është pezulluar sepse %1$s nuk është i aktivizuar</string>
@@ -133,7 +133,7 @@
<string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Kanal me porosi</string>
<string name="settings_update_custom_msg">Fut një URL të personalizuar</string>
<string name="settings_zygisk_summary">Drejtoni pjesë të Magisk në demonin zigotë</string>
<string name="settings_zygisk_summary">Drejtoni pjesë të Magisk në demonin zygote</string>
<string name="settings_denylist_title">Zbato Listën e Mohimit</string>
<string name="settings_denylist_summary">Proceset në listën e mohimit do të kenë të gjitha modifikimet e Magisk</string>
<string name="settings_denylist_error">Ky funksion kërkon %1$s për tu aktivizuar</string>
@@ -157,7 +157,7 @@
<string name="settings_su_request_60">60 Sekonda</string>
<string name="superuser_access">Aksesi i Super-përdorues</string>
<string name="auto_response">Përgjigje automatike</string>
<string name="request_timeout">Kërkesës i mbaroi koha</string>
<string name="request_timeout">Koha për mbarimit të Kërkesës</string>
<string name="superuser_notification">Njoftimi i Super-përdoruesit</string>
<string name="settings_su_reauth_title">Ri-vërtetimi pas azhurnimit</string>
<string name="settings_su_reauth_summary">Ri-vërtetoni lejet e super-përdoruesit pas azhurnimit të aplikacionit</string>
@@ -187,10 +187,13 @@
<!--Notifications-->
<string name="update_channel">Përditësimet e magisk</string>
<string name="updated_channel">Përditësimi përfundoi</string>
<string name="progress_channel">Njoftimet e progresit</string>
<string name="download_complete">Shkarkimi përfundoi</string>
<string name="download_file_error">Gabim në shkarkimin e skedarit</string>
<string name="magisk_update_title">Përditësimi Magisk i disponueshëm!</string>
<string name="updated_title">Magisk u përditësua</string>
<string name="updated_text">Prekni për të hapur aplikacionin</string>
<!--Toasts, Dialogs-->
<string name="yes">Po</string>
@@ -223,6 +226,7 @@
<string name="unsupport_nonroot_stub_msg">Aplikacioni nuk mund të vazhdojë të punojë në gjendjen e fshehur pasi rrënja ishte e humbur. Ju lutemi rivendoseni përsëri në APK-në origjinale.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">Jepni lejen e ruajtjes për të aktivizuar këtë funksion</string>
<string name="install_unknown_denied">Lejo "instaloni aplikacione të panjohura" për të aktivizuar këtë funksion</string>
<string name="add_shortcut_title">Shto shkurtore në ekranin bazë</string>
<string name="add_shortcut_msg">Pas fshehjes së këtij aplikacioni, emri dhe ikona e tij mund të bëhen të vështira për tu njohur. Dëshironi të shtoni një shkurtore mjaft të bukur në ekranin bazë?</string>
<string name="app_not_found">Asnjë aplikacion nuk u gjet për të trajtuar këtë veprim</string>

View File

@@ -8,12 +8,12 @@
<string name="install">ติดตั้ง</string>
<!--Status Fragment-->
<string name="invalid_update_channel">ช่องทางการอัเดตไม่ถูกต้อง</string>
<string name="invalid_update_channel">ช่องทางการอัเดตไม่ถูกต้อง</string>
<string name="keep_force_encryption">เก็บค่าบังคับการเข้ารหัส</string>
<string name="keep_dm_verity">เก็บค่า AVB 2.0/dm-verity</string>
<string name="uninstall_magisk_title">ถอนการติดตั้ง Magisk</string>
<string name="uninstall_magisk_msg">โมดูลทั้งหมดจะถูกปิดการใช้งาน/ถูกลบ, สิทธิการเข้าถึง Root จะถูกลบ และข้อมูลของคุณอาจถูกเข้ารหัส</string>
<string name="update">อัเดต</string>
<string name="update">อัเดต</string>
<!--Module Fragment-->
<string name="no_info_provided">(ไม่มีข้อมูล)</string>
@@ -22,7 +22,7 @@
<string name="reboot_download">รีบู๊ตไป Download</string>
<!--Repo Fragment-->
<string name="update_available">มีการอัเดต</string>
<string name="update_available">มีการอัเดต</string>
<string name="home_installed_version">ติดตั้งแล้ว</string>
<!--Log Fragment-->
@@ -34,17 +34,17 @@
<string name="app_changelog">สิ่งที่เพิ่มใหม่</string>
<!-- System Components, Notifications -->
<string name="update_channel">การอัเดต Magisk</string>
<string name="update_channel">การอัเดต Magisk</string>
<string name="progress_channel">สถานะ</string>
<string name="download_complete">ดาวน์โหลดสำเร็จ</string>
<string name="download_file_error">เกิดข้อผิดพลาดในการดาวน์โหลดไฟล์</string>
<string name="magisk_update_title">มีการอัเดต Magisk!</string>
<string name="magisk_update_title">มีการอัเดต Magisk!</string>
<!--Toasts, Dialogs-->
<string name="repo_install_title">ติดตั้ง %1$s %2$s(%3$d)</string>
<string name="download">ดาวน์โหลด</string>
<string name="reboot">รีบู๊ต</string>
<string name="release_notes">-้อมูลเพิ่มเติม</string>
<string name="release_notes">้อมูลเพิ่มเติม</string>
<string name="manager_download_install">แตะเพื่อดาวน์โหลดและติดตั้ง</string>
<string name="flashing">กำลังแฟลช</string>
<string name="open_link_failed_toast">ไม่พบแอปพลิเคชันสำหรับเปิดลิ้งค์</string>
@@ -64,9 +64,9 @@
<!--Settings Activity -->
<string name="language">ภาษา</string>
<string name="system_default">(มาตรฐานระบบ)</string>
<string name="settings_check_update_title">ตรวจสอบการอัเดต</string>
<string name="settings_check_update_summary">ตรวจสอบการอัเดตเป็นระยะในพื้นหลัง</string>
<string name="settings_update_channel_title">ช่องทางการอัเดต</string>
<string name="settings_check_update_title">ตรวจสอบการอัเดต</string>
<string name="settings_check_update_summary">ตรวจสอบการอัเดตเป็นระยะในพื้นหลัง</string>
<string name="settings_update_channel_title">ช่องทางการอัเดต</string>
<string name="settings_update_stable">เสถียร</string>
<string name="settings_update_beta">เบต้า</string>
<string name="settings_update_custom">กำหนดเอง</string>
@@ -89,8 +89,8 @@
<string name="auto_response">การตอบกลับ</string>
<string name="request_timeout">เวลาการขอใช้งาน</string>
<string name="superuser_notification">การแจ้งเตือน Superuser</string>
<string name="settings_su_reauth_title">ขอสิทธิ์ใหม่หลังจากอัเกรด</string>
<string name="settings_su_reauth_summary">ขอสิทธิ์ superuser ใหม่หลังจากแอปถูกอัเกรด</string>
<string name="settings_su_reauth_title">ขอสิทธิ์ใหม่หลังจากอัเกรด</string>
<string name="settings_su_reauth_summary">ขอสิทธิ์ superuser ใหม่หลังจากแอปถูกอัเกรด</string>
<string name="multiuser_mode">โหมดผู้ใช้หลายคน</string>
<string name="settings_owner_only">เจ้าของอุปกรณ์เท่านั้น</string>
@@ -115,7 +115,7 @@
<string name="grant">อนุญาต</string>
<string name="su_warning">จะให้การเข้าถึงอุปกรณ์ในทุกรูปแบบ กรุณาปฏิเสธหากคุณไม่มั่นใจ!</string>
<string name="forever">ตลอดกาล</string>
<string name="once">คั้งเดียว</string>
<string name="once">ั้งเดียว</string>
<string name="tenmin">10 นาที</string>
<string name="twentymin">20 นาที</string>
<string name="thirtymin">30 นาที</string>

View File

@@ -6,7 +6,7 @@
<string name="logs">Nhật ký</string>
<string name="settings">Cài đặt</string>
<string name="install">Cài đặt</string>
<string name="section_home">Home</string>
<string name="section_home">Trang chủ</string>
<string name="section_theme">Chủ đề</string>
<string name="denylist">DenyList</string>
@@ -23,16 +23,17 @@
<string name="home_notice_content">Chỉ nên tải Magisk từ trang GitHub chính thức. Tải tệp từ các nguồn không rõ có thể gây hại!</string>
<string name="home_support_title">Hỗ trợ chúng tôi</string>
<string name="home_item_source">Nguồn</string>
<string name="home_support_content">Magisk, và sẽ luôn luôn là, miễn phí và mã nguồn mở. Tuy nhiên, bạn có thể cho chúng tôi thấy rằng bạn quan tâm bằng cách gửi một khoản đóng góp nhỏ.</string>
<string name="home_support_content">Magisk sẽ, và luôn luôn là, miễn phí và mã nguồn mở. Tuy nhiên, bạn có thể cho chúng tôi thấy rằng bạn quan tâm bằng cách gửi một khoản đóng góp nhỏ.</string>
<string name="home_installed_version">Cài đặt</string>
<string name="home_latest_version">Mới nhất</string>
<string name="invalid_update_channel">Kênh cập nhật không hợp lệ</string>
<string name="uninstall_magisk_title">Gỡ cài đặt Magisk</string>
<string name="uninstall_magisk_msg">Tất cả các mô-đun sẽ bị tắt hoặc bị xóa!\nRoot sẽ bị gỡ bỏ\nDữ liệu của bạn có thể bị mã hóa lại nếu nó không mã hóa!</string>
<!--Settings-->
<!--Install-->
<string name="keep_force_encryption">Giữ bắt buộc mã hóa</string>
<string name="keep_dm_verity">Giữ AVB 2.0/dm-verity</string>
<string name="patch_vbmeta">Vá vbmeta trong boot image</string>
<string name="recovery_mode">Chế độ Recovery</string>
<string name="install_options_title">Tùy chọn</string>
<string name="install_method_title">Phương pháp</string>
@@ -41,7 +42,7 @@
<string name="manager_download_install">Nhấn để tải xuống và cài đặt</string>
<string name="direct_install">Cài đặt trực tiếp (Khuyến nghị)</string>
<string name="install_inactive_slot">Cài đặt vào vùng không hoạt động (Sau OTA)</string>
<string name="install_inactive_slot_msg">Thiết bị của bạn sẽ BẮT BUỘC khởi động vào vị trí không hoạt động hiện tại sau khi khởi động lại!\nChỉ sử dụng tùy chọn này sau khi hoàn tất OTA.\nTiếp tục chứ?</string>
<string name="install_inactive_slot_msg">Thiết bị của bạn sẽ bị BUỘC khởi động vào vị trí không hoạt động hiện tại sau khi khởi động lại!\nChỉ sử dụng tùy chọn này sau khi hoàn tất OTA.\nTiếp tục chứ?</string>
<string name="setup_title">Thiết lập bổ sung</string>
<string name="select_patch_file">Chọn và vá tệp</string>
<string name="patch_file_msg">Chọn đĩa ảnh (*.img) hoặc tệp tarfile ODIN (*.tar)</string>
@@ -50,7 +51,7 @@
<!--Superuser-->
<string name="su_request_title">Yêu cầu Superuser</string>
<string name="touch_filtered_warning">Vì một ứng dụng đang che phủ yêu cầu Superuser, Magisk không thể xác minh đó là phản hồi của bạn</string>
<string name="touch_filtered_warning">Vì một ứng dụng đang che phủ yêu cầu Superuser, Magisk không thể xác minh phản hồi của bạn</string>
<string name="deny">Từ chối</string>
<string name="prompt">Nhắc nhở</string>
<string name="grant">Cấp phép</string>
@@ -79,7 +80,7 @@
<string name="superuser_policy_none">Chưa có ứng dụng nào yêu cầu Superuser.</string>
<!--Logs-->
<string name="log_data_none">Nhật ký của bạn đang trống, hãy thử sử dụng các ứng dụng hỗ trợ SU của bạn nhiều hơn</string>
<string name="log_data_none">Nhật ký của bạn đang trống, hãy thử sử dụng các ứng dụng root của bạn nhiều hơn</string>
<string name="log_data_magisk_none">Nhật ký Magisk trống, điều đó thật kỳ lạ</string>
<string name="menuSaveLog">Lưu nhật ký</string>
<string name="menuClearLog">Xóa nhật ký ngay bây giờ</string>
@@ -102,14 +103,15 @@
<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</string>
<string name="reboot_edl">Khởi động lại vào EDL</string>
<string name="module_version_author">%1$s x %2$s</string>
<string name="module_state_remove">Loại bỏ</string>
<string name="module_version_author">%1$s bởi %2$s</string>
<string name="module_state_remove">Gỡ bỏ</string>
<string name="module_state_restore">Khôi phục</string>
<string name="module_action_install_external">Cài đặt từ bộ nhớ</string>
<string name="update_available">Cập nhật có sẵn</string>
<string name="suspend_text_riru">Mô-đun bị vô hiệu hóa vì %1$s được bật</string>
<string name="suspend_text_zygisk">Mô-đun bị vô hiệu hóa vì %1$s không được bật</string>
<string name="zygisk_module_unloaded">Không tải mô-đun Zygisk vì không tương thích</string>
<!--Settings-->
<string name="settings_dark_mode_title">Chế độ chủ đề</string>
<string name="settings_dark_mode_message">Chọn chế độ phù hợp nhất với phong cách của bạn!</string>
@@ -159,13 +161,15 @@
<string name="superuser_notification">Thông báo của Superuser</string>
<string name="settings_su_reauth_title">Xác thực lại sau khi nâng cấp</string>
<string name="settings_su_reauth_summary">Xác thực lại quyền Superuser sau khi nâng cấp ứng dụng</string>
<string name="settings_su_tapjack_title">Kích hoạt tính năng bảo vệ bằng Tapjacking</string>
<string name="settings_su_tapjack_title">Bảo vệ khỏi Tapjacking</string>
<string name="settings_su_tapjack_summary">Hộp thoại nhắc Superuser sẽ không trả lời đầu vào khi bị che khuất bởi bất kỳ cửa sổ hoặc lớp phủ nào khác</string>
<string name="settings_su_biometric_title">Bật xác thực sinh trắc học</string>
<string name="settings_su_biometric_summary">Sử dụng xác thực sinh trắc học để xác nhận yêu cầu Superuser</string>
<string name="no_biometric">Thiết bị của bạn không được hỗ trợ hoặc không có phương pháp xác thực sinh trắc học nào được kích hoạt</string>
<string name="settings_customization">Tùy biến</string>
<string name="setting_add_shortcut_summary">Thêm một phím tắt đẹp vào màn hình trong trường hợp khó nhận ra tên và biểu tượng sau khi ẩn ứng dụng</string>
<string name="settings_doh_title">DNS over HTTPS</string>
<string name="settings_doh_description">Workaround DNS poisoning in some nations</string>
<string name="multiuser_mode">Chế độ đa người dùng</string>
<string name="settings_owner_only">Chỉ chủ sở hữu thiết bị</string>
@@ -186,9 +190,12 @@
<!--Thông báo-->
<string name="update_channel">Cập nhật Magisk</string>
<string name="progress_channel">Thông báo tiến độ</string>
<string name="updated_channel">Cập nhật hoàn tất</string>
<string name="download_complete">Tải về hoàn tất</string>
<string name="download_file_error">Lỗi khi tải xuống tệp</string>
<string name="magisk_update_title">Cập nhật Magisk có sẵn!</string>
<string name="updated_title">Đã cập nhật Magisk</string>
<string name="updated_text">Chạm để mở ứng dụng</string>
<!--Toasts, Dialogs-->
<string name="yes">Đồng ý</string>
@@ -203,10 +210,10 @@
<string name="hide_app_title">Đang ẩn ứng dụng Magisk…</string>
<string name="open_link_failed_toast">Không tìm thấy ứng dụng nào để mở liên kết</string>
<string name="complete_uninstall">Hoàn thành Gỡ cài đặt</string>
<string name="restore_img">Khôi phục đĩa ảnh boot</string>
<string name="restore_img">Khôi phục đĩa ảnh boot (image)</string>
<string name="restore_img_msg">Đang khôi phục…</string>
<string name="restore_done">Đã khôi phục xong!</string>
<string name="restore_fail">Bản gốc không tồn tại!</string>
<string name="restore_fail">Bản sao lưu gốc không tồn tại!</string>
<string name="setup_fail">Thiết lập không thành công</string>
<string name="env_fix_title">Yêu cầu thiết lập bổ sung</string>
<string name="env_fix_msg">Thiết bị của bạn cần thiết lập bổ sung để Magisk hoạt động bình thường. Bạn có muốn tiếp tục và khởi động lại không?</string>
@@ -216,14 +223,16 @@
<string name="unsupport_magisk_msg">Phiên bản hiện tại của ứng dụng không hỗ trợ phiên bản Magisk thấp hơn %1$s.\n\nỨng dụng sẽ hoạt động như thể Magisk chưa được cài đặt. Vui lòng nâng cấp lên phiên bản mới nhất.</string>
<string name="unsupport_general_title">Trạng thái bất thường</string>
<string name="unsupport_system_app_msg">Không hỗ trợ chạy ứng dụng này dưới dạng ứng dụng hệ thống. Vui lòng hoàn nguyên ứng dụng về ứng dụng người dùng.</string>
<string name="unsupport_other_su_msg">Một lệnh \"su\" không thuộc về Magisk được phát hiện. Vui lòng loại bỏ su không được hỗ trợ khác.</string>
<string name="unsupport_other_su_msg">Một lệnh \"su\" không thuộc về Magisk được phát hiện. Vui lòng gỡ bỏ bất kì phương pháp root khác và/hoặc cài đặt lại Magisk.</string>
<string name="unsupport_external_storage_msg">Magisk được cài đặt vào bộ nhớ ngoài. Vui lòng chuyển ứng dụng vào bộ nhớ trong.</string>
<string name="unsupport_nonroot_stub_msg">Ứng dụng không thể tiếp tục hoạt động ở trạng thái ẩn vì mất quyền root. Vui lòng khôi phục nó trở lại APK ban đầu.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">Cấp quyền lưu trữ để bật chức năng này</string>
<string name="install_unknown_denied">Cho phép "cài đặt ứng dụng không rõ nguồn gốc" để bật chức năng này</string>
<string name="add_shortcut_title">Thêm lối tắt vào màn hình chính</string>
<string name="add_shortcut_msg">Sau khi ẩn ứng dụng này, tên và biểu tượng của nó có thể trở nên khó nhận ra. Bạn có muốn thêm một phím tắt đẹp vào màn hình chính không?</string>
<string name="app_not_found">Không tìm thấy ứng dụng nào để xử lý hành động này</string>
<string name="reboot_apply_change">Khởi động lại để áp dụng các thay đổi</string>
<string name="restore_app_confirmation">Điều này sẽ khôi phục ứng dụng ẩn về nguyên bản. Bạn chắc chắn muốn làm điều này chứ?</string>
</resources>

View File

@@ -23,7 +23,7 @@
<string name="home_notice_content">仅从官方 GitHub 页面下载 Magisk。未知来源的文件可能具有恶意行为</string>
<string name="home_support_title">支持开发</string>
<string name="home_item_source">源代码</string>
<string name="home_support_content">Magisk 将一直保持自由且开源,向开发者捐赠以表示支持。</string>
<string name="home_support_content">Magisk 将一直保持免费且开源,向开发者捐赠以表示支持。</string>
<string name="home_installed_version">当前</string>
<string name="home_latest_version">最新</string>
<string name="invalid_update_channel">无效的更新通道</string>
@@ -190,9 +190,12 @@
<!--Notifications-->
<string name="update_channel">更新提示</string>
<string name="progress_channel">下载进度</string>
<string name="updated_channel">更新完成</string>
<string name="download_complete">下载完成</string>
<string name="download_file_error">下载失败</string>
<string name="magisk_update_title">Magisk 已发布新版本!</string>
<string name="updated_title">Magisk 已完成更新</string>
<string name="updated_text">点按即可打开应用</string>
<!--Toasts, Dialogs-->
<string name="yes"></string>
@@ -225,6 +228,7 @@
<string name="unsupport_nonroot_stub_msg">超级用户权限丢失,应用无法在隐藏状态下继续工作,请恢复到原始 Magisk 应用。</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">允许访问存储空间以使用此功能</string>
<string name="install_unknown_denied">允许安装未知应用以使用此功能</string>
<string name="add_shortcut_title">添加快捷方式到桌面</string>
<string name="add_shortcut_msg">隐藏后应用的名字和图标可能难以识别。需要在桌面上添加具有原始名称和图标的快捷方式吗?</string>
<string name="app_not_found">找不到可处理此操作的应用</string>

View File

@@ -33,6 +33,7 @@
<!--Install-->
<string name="keep_force_encryption">保持強制加密</string>
<string name="keep_dm_verity">保持 AVB 2.0/dm-verity</string>
<string name="patch_vbmeta">修補 vbmeta 到開機映像檔</string>
<string name="recovery_mode">安裝至 Recovery</string>
<string name="install_options_title">選項</string>
<string name="install_method_title">安裝方式</string>
@@ -107,6 +108,9 @@
<string name="module_state_restore">還原</string>
<string name="module_action_install_external">從本機安裝</string>
<string name="update_available">有可用的更新</string>
<string name="suspend_text_riru">此模組因 %1$s 已啟用而暫停運作</string>
<string name="suspend_text_zygisk">此模組因 %1$s 未啟用而暫停運作</string>
<string name="zygisk_module_unloaded">此 Zygisk 模組因未相容而不載入</string>
<!--Settings -->
<string name="settings_dark_mode_title">主題模式</string>
@@ -224,6 +228,7 @@
<string name="add_shortcut_title">新增捷徑到首頁</string>
<string name="add_shortcut_msg">在隱藏 Magisk 之後,其名稱與圖示將難以辨識。您想要新增一個精緻的捷徑到桌面嗎?</string>
<string name="app_not_found">沒有可以處理這個操作的應用程式</string>
<string name="reboot_apply_change">重新啟動裝置以套用設變更</string>
<string name="reboot_apply_change">重新啟動裝置以套用設變更</string>
<string name="restore_app_confirmation">這將會還原隱藏的應用程式回到原本的應用程式。請問您確定要執行?</string>
</resources>

View File

@@ -131,8 +131,8 @@
<string name="settings_update_channel_title">Update Channel</string>
<string name="settings_update_stable">Stable</string>
<string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Custom Channel</string>
<string name="settings_update_custom_msg">Insert a custom URL</string>
<string name="settings_update_custom">Custom</string>
<string name="settings_update_custom_msg">Insert a custom channel URL</string>
<string name="settings_zygisk_summary">Run parts of Magisk in the zygote daemon</string>
<string name="settings_denylist_title">Enforce DenyList</string>
<string name="settings_denylist_summary">Processes on the denylist will have all Magisk modifications reverted</string>
@@ -190,9 +190,12 @@
<!--Notifications-->
<string name="update_channel">Magisk Updates</string>
<string name="progress_channel">Progress Notifications</string>
<string name="updated_channel">Update Complete</string>
<string name="download_complete">Download complete</string>
<string name="download_file_error">Error downloading file</string>
<string name="magisk_update_title">Magisk Update Available!</string>
<string name="updated_title">Magisk Updated</string>
<string name="updated_text">Tap to open app</string>
<!--Toasts, Dialogs-->
<string name="yes">Yes</string>
@@ -225,6 +228,7 @@
<string name="unsupport_nonroot_stub_msg">The hidden Magisk app cannot continue to work because root was lost. Please restore the original APK.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">Grant storage permission to enable this functionality</string>
<string name="install_unknown_denied">Allow "install unknown apps" to enable this functionality</string>
<string name="add_shortcut_title">Add shortcut to home screen</string>
<string name="add_shortcut_msg">After hiding this app, its name and icon might become difficult to recognize. Do you want to add a pretty shortcut to the home screen?</string>
<string name="app_not_found">No app found to handle this action</string>

View File

@@ -405,7 +405,7 @@ def cleanup(args):
def setup_ndk(args):
os_name = platform.system().lower()
ndk_ver = config['ndkVersion']
url = f'https://dl.google.com/android/repository/android-ndk-r{ndk_ver}-{os_name}-x86_64.zip'
url = f'https://dl.google.com/android/repository/android-ndk-r{ndk_ver}-{os_name}.zip'
ndk_zip = url.split('/')[-1]
header(f'* Downloading {ndk_zip}')
@@ -417,7 +417,7 @@ def setup_ndk(args):
with zipfile.ZipFile(ndk_zip, 'r') as zf:
for info in zf.infolist():
vprint(f'Extracting {info.filename}')
if info.external_attr == 2716663808: # symlink
if info.external_attr >> 28 == 0xA: # symlink
src = zf.read(info).decode("utf-8")
dest = op.join(ndk_root, info.filename)
os.symlink(src, dest)
@@ -491,7 +491,7 @@ def patch_avd_ramdisk(args):
'scripts/avd_patch.sh', '/data/local/tmp'])
if proc.returncode != 0:
error('adb push failed!')
proc = execv([adb_path, 'push', backup, '/data/local/tmp/ramdisk.cpio.gz'])
proc = execv([adb_path, 'push', backup, '/data/local/tmp/ramdisk.cpio.tmp'])
if proc.returncode != 0:
error('adb push failed!')

View File

@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
`kotlin-dsl`
}
@@ -15,10 +17,16 @@ gradlePlugin {
}
}
tasks.withType<KotlinCompile> {
kotlinOptions {
jvmTarget = "11"
}
}
dependencies {
implementation(kotlin("gradle-plugin", "1.6.10"))
implementation("com.android.tools.build:gradle:7.0.4")
implementation("androidx.navigation:navigation-safe-args-gradle-plugin:2.4.0-rc01")
implementation("com.android.tools.build:gradle:7.1.2")
implementation("androidx.navigation:navigation-safe-args-gradle-plugin:2.5.0-alpha01")
implementation("io.michaelrocks:paranoid-gradle-plugin:0.3.7")
implementation("org.eclipse.jgit:org.eclipse.jgit:5.12.0.202106070339-r")
}

View File

@@ -74,36 +74,13 @@ fun genKeyData(keysDir: File, outSrc: File) {
}
fun genStubManifest(srcDir: File, outDir: File): String {
class Component(
val real: String,
val stub: String,
val xml: String
)
outDir.deleteRecursively()
val mainPkgDir = File(outDir, "com/topjohnwu/magisk")
mainPkgDir.mkdirs()
fun String.ind(level: Int) = replaceIndentByMargin(" ".repeat(level))
val cmpList = mutableListOf<Component>()
val cmpList = mutableListOf<String>()
cmpList.add(Component(
"androidx.core.app.CoreComponentFactory",
"DelegateComponentFactory",
""
))
cmpList.add(Component(
"com.topjohnwu.magisk.core.App",
"DelegateApplication",
""
))
cmpList.add(Component(
"com.topjohnwu.magisk.core.Provider",
"dummy.DummyProvider",
cmpList.add(
"""
|<provider
| android:name="%s"
@@ -111,11 +88,9 @@ fun genStubManifest(srcDir: File, outDir: File): String {
| android:directBootAware="true"
| android:exported="false"
| android:grantUriPermissions="true" />""".ind(2)
))
)
cmpList.add(Component(
"com.topjohnwu.magisk.core.Receiver",
"dummy.DummyReceiver",
cmpList.add(
"""
|<receiver
| android:name="%s"
@@ -124,6 +99,7 @@ fun genStubManifest(srcDir: File, outDir: File): String {
| <intent-filter>
| <action android:name="android.intent.action.LOCALE_CHANGED" />
| <action android:name="android.intent.action.UID_REMOVED" />
| <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
| </intent-filter>
| <intent-filter>
| <action android:name="android.intent.action.PACKAGE_REPLACED" />
@@ -132,11 +108,9 @@ fun genStubManifest(srcDir: File, outDir: File): String {
| <data android:scheme="package" />
| </intent-filter>
|</receiver>""".ind(2)
))
)
cmpList.add(Component(
"com.topjohnwu.magisk.ui.MainActivity",
"DownloadActivity",
cmpList.add(
"""
|<activity
| android:name="%s"
@@ -146,43 +120,38 @@ fun genStubManifest(srcDir: File, outDir: File): String {
| <category android:name="android.intent.category.LAUNCHER" />
| </intent-filter>
|</activity>""".ind(2)
))
)
cmpList.add(Component(
"com.topjohnwu.magisk.ui.surequest.SuRequestActivity",
"",
cmpList.add(
"""
|<activity
| android:name="%s"
| android:directBootAware="true"
| android:excludeFromRecents="true"
| android:exported="false"
| android:taskAffinity=""
| tools:ignore="AppLinkUrlError">
| <intent-filter>
| <action android:name="android.intent.action.VIEW"/>
| <category android:name="android.intent.category.DEFAULT"/>
| </intent-filter>
|</activity>""".ind(2)
))
)
cmpList.add(Component(
"com.topjohnwu.magisk.core.download.DownloadService",
"",
cmpList.add(
"""
|<service
| android:name="%s"
| android:exported="false" />""".trimIndent().ind(2)
))
| android:exported="false" />""".ind(2)
)
cmpList.add(Component(
"com.topjohnwu.magisk.core.JobService",
"",
cmpList.add(
"""
|<service
| android:name="%s"
| android:exported="false"
| android:permission="android.permission.BIND_JOB_SERVICE" />""".ind(2)
))
)
val names = mutableListOf<String>()
names.addAll(c1)
@@ -190,77 +159,66 @@ fun genStubManifest(srcDir: File, outDir: File): String {
names.addAll(c3.subList(0, 10))
names.shuffle(RANDOM)
// Distinct by lower case to support case insensitive file systems
val pkgNames = names.distinctBy { it.toLowerCase(Locale.ROOT) }
val pkgNames = names
// Distinct by lower case to support case insensitive file systems
.distinctBy { it.toLowerCase(Locale.ROOT) }
// Old Android does not support capitalized package names
// Check Android 7.0.0 PackageParser#buildClassName
.map { it.decapitalize(Locale.ROOT) }
var idx = 0
fun isJavaKeyword(name: String) = when (name) {
"do", "if", "for", "int", "new", "try" -> true
else -> false
}
fun genCmpName() : String {
var pkgName : String
val cmps = mutableListOf<String>()
val usedNames = mutableListOf<String>()
fun genCmpName(): String {
var pkgName: String
do {
pkgName = pkgNames[idx++]
pkgName = pkgNames.random(kRANDOM)
} while (isJavaKeyword(pkgName))
var clzName : String
var clzName: String
do {
clzName = names.random(kRANDOM)
} while (isJavaKeyword(clzName))
return "${pkgName}.${clzName}"
val cmp = "${pkgName}.${clzName}"
usedNames.add(cmp)
return cmp
}
fun genClass(clzName: String, type: String) {
fun genClass(type: String) {
val clzName = genCmpName()
val (pkg, name) = clzName.split('.')
val pkgDir = File(outDir, pkg)
pkgDir.mkdir()
pkgDir.mkdirs()
PrintStream(File(pkgDir, "$name.java")).use {
it.println("package $pkg;")
it.println("public class $name extends com.topjohnwu.magisk.$type {}")
}
}
val cmps = mutableListOf<String>()
val usedNames = mutableListOf<String>()
val maps = StringBuilder()
// Generate 2 non redirect-able classes
genClass("DelegateComponentFactory")
genClass("DelegateApplication")
for (gen in cmpList) {
val name = genCmpName()
usedNames.add(name)
maps.append("|map.put(\"$name\", \"${gen.real}\");".ind(2))
maps.append('\n')
if (gen.stub.isNotEmpty()) {
if (gen.stub != "DelegateComponentFactory") {
maps.append("|internalMap.put(\"$name\", com.topjohnwu.magisk.${gen.stub}.class);".ind(2))
maps.append('\n')
}
if (gen.stub.startsWith("Delegate")) {
genClass(name, gen.stub)
}
}
if (gen.xml.isNotEmpty()) {
cmps.add(gen.xml.format(name))
}
cmps.add(gen.format(name))
}
// Shuffle the order of the components
cmps.shuffle(RANDOM)
val xml = File(srcDir, "AndroidManifest.xml").readText()
val genXml = xml.format(usedNames[0], usedNames[1], cmps.joinToString("\n\n"))
// Write mapping information to code
val mapping = File(srcDir, "Mapping.java").readText().format(maps)
PrintStream(File(mainPkgDir, "Mapping.java")).use {
it.print(mapping)
}
return genXml
return xml.format(usedNames[0], usedNames[1], cmps.joinToString("\n\n"))
}
fun genEncryptedResources(res: InputStream, outDir: File) {
val mainPkgDir = File(outDir, "com/topjohnwu/magisk")
mainPkgDir.mkdirs()
// Generate iv and key
val iv = ByteArray(16)

View File

@@ -29,7 +29,7 @@ fun Project.setupCommon() {
androidBase {
compileSdkVersion(31)
buildToolsVersion = "31.0.0"
ndkPath = "${System.getenv("ANDROID_SDK_ROOT")}/ndk/magisk"
ndkPath = "$sdkDirectory/ndk/magisk"
defaultConfig {
minSdk = 21
@@ -123,7 +123,8 @@ fun Project.setupApp() {
inputs.property("versionCode", Config.versionCode)
into("src/main/assets")
from(rootProject.file("scripts")) {
include("util_functions.sh", "boot_patch.sh", "uninstaller.sh", "addon.d.sh")
include("util_functions.sh", "boot_patch.sh", "addon.d.sh")
include("uninstaller.sh", "module_installer.sh")
}
from(rootProject.file("tools/bootctl"))
into("chromeos") {
@@ -187,8 +188,6 @@ fun Project.setupStub() {
val apkTmp = File("${apk}.tmp")
val genManifestTask = tasks.register("generate${variantCapped}ObfuscatedManifest") {
inputs.property("versionCode", Config.versionCode)
outputs.file(manifest)
doLast {
val xml = genStubManifest(templateDir, outSrcDir)
manifest.parentFile.mkdirs()

View File

@@ -1,10 +1,38 @@
# Magisk Changelog
### v24.3
- [General] Stop using `getrandom` syscall
- [Zygisk] Update API to v3, adding new fields to `AppSpecializeArgs`
- [App] Improve app repackaging installation workflow
### v24.2
- [MagiskSU] Fix buffer overflow
- [MagiskSU] Fix owner managed multiuser superuser settings
- [MagiskSU] Fix command logging when using `su -c <cmd>`
- [MagiskSU] Prevent su request indefinite blocking
- [MagiskBoot] Support `lz4_legacy` archive with multiple magic
- [MagiskBoot] Fix `lz4_lg` compression
- [DenyList] Allow targeting processes running as system UID
- [Zygisk] Workaround Samsung's "early zygote"
- [Zygisk] Improved Zygisk loading mechanism
- [Zygisk] Fix application UID tracking
- [Zygisk] Fix improper `umask` being set in zygote
- [App] Fix BusyBox execution test
- [App] Improve stub loading mechanism
- [App] Major app upgrade flow improvements
- [General] Improve commandline error handling and messaging
### v24.1
- [App] Stability improvements
### v24.0
- [General] MagiskHide is removed from Magisk
- [General] Support 64-bit only systems
- [General] Support Android 12
- [General] Support devices that do not support 32-bit and only runs 64-bit code
- [General] Update BusyBox to 1.34.1
- [Zygisk] Introduce new feature: Zygisk
- [Zygisk] Introduce DenyList feature to revert Magisk features in user selected processes

View File

@@ -34,11 +34,11 @@ Next, we need to know whether your device has a separate `vbmeta` partition.
- If you find `vbmeta`, `vbmeta_a`, or `vbmeta_b`, then yes, your device **has** a separate `vbmeta` partition
- Otherwise, your device **does not** have a separate `vbmeta` partition.
Quick recap, at this point, you should know and prepared:
Quick recap, at this point, you should have known and prepared:
1. Whether your device has boot ramdisk
2. Whether your device has a separate `vbmeta` partition
3. A `boot.img` or `recovery.img` based on the result of (1)
3. A `boot.img` or `recovery.img` based on (1)
Let's continue to [Patching Images](#patching-images).
@@ -103,16 +103,15 @@ Unlocking the bootloader on modern Samsung devices have some caveats. The newly
- Use either [samfirm.js](https://github.com/jesec/samfirm.js), [Frija](https://forum.xda-developers.com/s10-plus/how-to/tool-frija-samsung-firmware-downloader-t3910594), or [Samloader](https://forum.xda-developers.com/s10-plus/how-to/tool-samloader-samfirm-frija-replacement-t4105929) to download the latest firmware zip of your device directly from Samsung servers.
- Unzip the firmware and copy the `AP` tar file to your device. It is normally named as `AP_[device_model_sw_ver].tar.md5`
- Press the **Install** button in the Magisk card
- If you are patching a recovery image, check the **"Recovery Mode"** option
- If your device does **NOT** have boot ramdisk, check the **"Recovery Mode"** option
- Choose **"Select and Patch a File"** in method, and select the `AP` tar file
- The Magisk app will patch the whole firmware file to `[Internal Storage]/Download/magisk_patched_[random_strings].tar`
- Start the installation, and copy the patched tar file to your PC using ADB:<br>
`adb pull /sdcard/Download/magisk_patched_[random_strings].tar`<br>
**DO NOT USE MTP** as it is known to corrupt large files.
- Reboot to download mode. Open Odin on your PC, and flash `magisk_patched.tar` as `AP`, together with `BL`, `CP`, and `CSC` (**NOT** `HOME_CSC` because we want to **wipe data**) from the original firmware.
- Your device should reboot automatically once Odin finished flashing. Agree to do a factory reset if asked.
- If your device does **NOT** have boot ramdisk, reboot to recovery now to enable Magisk (reason stated in [Magisk in Recovery](#magisk-in-recovery)).
- Install the Magisk app you've downloaded and launch the app. It should show a dialog asking for additional setup.
- Install the Magisk app you've already downloaded and launch the app. It should show a dialog asking for additional setup.
- Let the app do its job and automatically reboot the device. Voila!
### Upgrading the OS

23
docs/releases/24100.md Normal file
View File

@@ -0,0 +1,23 @@
## 2022.1.28 Magisk v24.1
> For those coming from v24.0, v24.1 only has some minor app improvements. The following are copied from v24.0 release notes.
It has been a while since the last public release, long time no see! A personal update for those unaware: I am now working at Google on the Android Platform Security team. Without further ado, let's jump right into it!
### MagiskHide Removal
I have lost interest in fighting this battle for quite a while; plus, the existing MagiskHide implementation is flawed in so many ways. Decoupling Magisk from root hiding is, in my opinion, beneficial to the community. Ever since my announcement on Twitter months ago, highly effective "root hiding" modules (much **MUCH** better than MagiskHide) has been flourishing, which again shows that people are way more capable than I am on this subject. So why not give those determined their time to shine, and let me focus on improving Magisk instead of drowning in the everlasting cat-and-mouse game 😉.
### Sunsetting Magisk-Modules-Repo
Due to lack of time and maintenance, the centralized Magisk-Modules-Repo was frozen, and the functionality to download modules from the repo is removed in v24.0. As a supplement, module developers can now specify an `updateJson` URL in their modules. The Magisk app will use that to check, download, and install module updates.
### Introducing Zygisk
Zygisk is **Magisk in Zygote**, the next big thing for Magisk! When this feature is enabled, a part of Magisk will run in the `Zygote` daemon process, allowing module developers to run code directly in every Android apps' processes. If you've heard of [Riru](https://github.com/RikkaApps/Riru), then Zygisk is inspired by that project and is functionally similar, though the implementation is quite different internally. I cannot wait to see what module developers can achieve using Zygisk!
### Documentation
For developers, details about `updateJson` and building Zygisk modules can all be found in the updated [documentation](https://topjohnwu.github.io/Magisk/guides.html#magisk-modules).
### Full Changelog: [here](https://topjohnwu.github.io/Magisk/changes.html)

21
docs/releases/24200.md Normal file
View File

@@ -0,0 +1,21 @@
## 2022.3.1 Magisk v24.2
Maintenance release fixing various issues.
- [MagiskSU] Fix buffer overflow
- [MagiskSU] Fix owner managed multiuser superuser settings
- [MagiskSU] Fix command logging when using `su -c <cmd>`
- [MagiskSU] Prevent su request indefinite blocking
- [MagiskBoot] Support `lz4_legacy` archive with multiple magic
- [MagiskBoot] Fix `lz4_lg` compression
- [DenyList] Allow targeting processes running as system UID
- [Zygisk] Workaround Samsung's "early zygote"
- [Zygisk] Improved Zygisk loading mechanism
- [Zygisk] Fix application UID tracking
- [Zygisk] Fix improper `umask` being set in zygote
- [App] Fix BusyBox execution test
- [App] Improve stub loading mechanism
- [App] Major app upgrade flow improvements
- [General] Improve commandline error handling and messaging
### Full Changelog: [here](https://topjohnwu.github.io/Magisk/changes.html)

9
docs/releases/24300.md Normal file
View File

@@ -0,0 +1,9 @@
## 2022.3.10 Magisk v24.3
For those coming from v24.1, check the full changelog for changes introduced in v24.2.
- [General] Stop using `getrandom` syscall
- [Zygisk] Update API to v3, adding new fields to `AppSpecializeArgs`
- [App] Improve app repackaging installation workflow
### Full Changelog: [here](https://topjohnwu.github.io/Magisk/changes.html)

View File

@@ -1,5 +1,8 @@
# Release Notes
- [v24.3](24300.md)
- [v24.2](24200.md)
- [v24.1](24100.md)
- [v24.0](24000.md)
- [v23.0](23000.md)
- [v22.1](22100.md)

View File

@@ -24,9 +24,10 @@ org.gradle.caching=true
android.useAndroidX=true
android.databinding.incremental=true
android.injected.testOnly=false
android.nonTransitiveRClass=true
# Magisk
magisk.stubVersion=23
magisk.versionCode=24000
magisk.ndkVersion=21e
magisk.fullNdkVersion=21.4.7075529
magisk.stubVersion=27
magisk.versionCode=24300
magisk.ndkVersion=23b
magisk.fullNdkVersion=23.1.7779620

Binary file not shown.

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -8,7 +8,12 @@ ifdef B_MAGISK
include $(CLEAR_VARS)
LOCAL_MODULE := magisk
LOCAL_STATIC_LIBRARIES := libnanopb libsystemproperties libutils-shared libphmap libxhook
LOCAL_STATIC_LIBRARIES := \
libutils \
libnanopb \
libsystemproperties \
libphmap \
libxhook
LOCAL_SRC_FILES := \
core/applets.cpp \
@@ -43,12 +48,14 @@ include $(BUILD_EXECUTABLE)
endif
include $(CLEAR_VARS)
ifdef B_INIT
include $(CLEAR_VARS)
LOCAL_MODULE := magiskinit
LOCAL_STATIC_LIBRARIES := libsepol libxz libutils
LOCAL_STATIC_LIBRARIES := \
libutilx \
libsepol \
libxz
LOCAL_SRC_FILES := \
init/init.cpp \
@@ -73,7 +80,15 @@ ifdef B_BOOT
include $(CLEAR_VARS)
LOCAL_MODULE := magiskboot
LOCAL_STATIC_LIBRARIES := libmincrypt liblzma liblz4 libbz2 libfdt libutils libz libzopfli
LOCAL_STATIC_LIBRARIES := \
libutilx \
libmincrypt \
liblzma \
liblz4 \
libbz2 \
libfdt \
libz \
libzopfli
LOCAL_SRC_FILES := \
magiskboot/main.cpp \
@@ -95,7 +110,9 @@ ifdef B_POLICY
include $(CLEAR_VARS)
LOCAL_MODULE := magiskpolicy
LOCAL_STATIC_LIBRARIES := libsepol libutils
LOCAL_STATIC_LIBRARIES := \
libutilx \
libsepol
LOCAL_SRC_FILES := \
core/applet_stub.cpp \
@@ -115,7 +132,10 @@ ifdef B_PROP
include $(CLEAR_VARS)
LOCAL_MODULE := resetprop
LOCAL_STATIC_LIBRARIES := libnanopb libsystemproperties libutils
LOCAL_STATIC_LIBRARIES := \
libutilx \
libnanopb \
libsystemproperties
LOCAL_SRC_FILES := \
core/applet_stub.cpp \
@@ -133,7 +153,10 @@ ifneq (,$(wildcard jni/test.cpp))
include $(CLEAR_VARS)
LOCAL_MODULE := test
LOCAL_STATIC_LIBRARIES := libutils-shared libphmap
LOCAL_STATIC_LIBRARIES := \
libutils \
libphmap
LOCAL_SRC_FILES := test.cpp
include $(BUILD_EXECUTABLE)

View File

@@ -1,24 +1,21 @@
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
APP_CFLAGS := -Wall -Oz -fomit-frame-pointer -flto
APP_LDFLAGS := -flto
APP_CPPFLAGS := -std=c++17
APP_CPPFLAGS := -std=c++20
APP_STL := none
APP_PLATFORM := android-21
APP_THIN_ARCHIVE := true
APP_STRIP_MODE := --strip-all
ifneq ($(TARGET_ARCH),arm64)
ifneq ($(TARGET_ARCH),x86_64)
ifndef B_SHARED
# Disable fortify on static 32-bit targets
APP_CFLAGS += -D_FORTIFY_SOURCE=0 -Wno-macro-redefined
endif
endif
# Fix static variables' ctor/dtor when using LTO
# See: https://github.com/android/ndk/issues/1461
APP_LDFLAGS += -T jni/lto_fix.lds
endif
# Busybox should use stock libc.a
ifdef B_BB
APP_PLATFORM := android-22
APP_PLATFORM := android-24
ifeq ($(OS),Windows_NT)
APP_SHORT_COMMANDS := true
endif

View File

@@ -21,20 +21,23 @@ static int call_applet(int argc, char *argv[]) {
return (*applet_mains[i])(argc, argv);
}
}
if (str_starts(base, "app_process")) {
return app_process_main(argc, argv);
}
fprintf(stderr, "%s: applet not found\n", base.data());
return 1;
}
int main(int argc, char *argv[]) {
umask(0);
enable_selinux();
cmdline_logging();
init_argv0(argc, argv);
string_view base = basename(argv[0]);
// app_process is actually not an applet
if (str_starts(base, "app_process")) {
return app_process_main(argc, argv);
}
umask(0);
if (base == "magisk" || base == "magisk32" || base == "magisk64") {
if (argc > 1 && argv[1][0] != '-') {
// Calling applet via magisk [applet] args

View File

@@ -25,22 +25,36 @@ bool zygisk_enabled = false;
*********/
#define MNT_DIR_IS(dir) (me->mnt_dir == string_view(dir))
#define MNT_TYPE_IS(type) (me->mnt_type == string_view(type))
#define SETMIR(b, part) snprintf(b, sizeof(b), "%s/" MIRRDIR "/" #part, MAGISKTMP.data())
#define SETBLK(b, part) snprintf(b, sizeof(b), "%s/" BLOCKDIR "/" #part, MAGISKTMP.data())
#define do_mount_mirror(part, flag) {\
SETMIR(buf1, part); \
SETBLK(buf2, part); \
unlink(buf2); \
#define do_mount_mirror(part) { \
SETMIR(buf1, part); \
SETBLK(buf2, part); \
unlink(buf2); \
mknod(buf2, S_IFBLK | 0600, st.st_dev); \
xmkdir(buf1, 0755); \
xmount(buf2, buf1, me->mnt_type, flag, nullptr); \
LOGI("mount: %s\n", buf1); \
xmkdir(buf1, 0755); \
int flags = 0; \
auto opts = split_ro(me->mnt_opts, ",");\
for (string_view s : opts) { \
if (s == "ro") { \
flags |= MS_RDONLY; \
break; \
} \
} \
xmount(buf2, buf1, me->mnt_type, flags, nullptr); \
LOGI("mount: %s\n", buf1); \
}
#define mount_mirror(part, flag) \
else if (MNT_DIR_IS("/" #part) && me->mnt_type != "tmpfs"sv && me->mnt_type != "overlay"sv && lstat(me->mnt_dir, &st) == 0) \
do_mount_mirror(part, flag)
#define mount_mirror(part) \
if (MNT_DIR_IS("/" #part) \
&& !MNT_TYPE_IS("tmpfs") \
&& !MNT_TYPE_IS("overlay") \
&& lstat(me->mnt_dir, &st) == 0) { \
do_mount_mirror(part); \
break; \
}
#define link_mirror(part) \
SETMIR(buf1, part); \
@@ -50,11 +64,12 @@ if (access("/system/" #part, F_OK) == 0 && access(buf1, F_OK) != 0) { \
}
#define link_orig_dir(dir, part) \
else if (MNT_DIR_IS(dir) && me->mnt_type != "tmpfs"sv && me->mnt_type != "overlay"sv) { \
SETMIR(buf1, part); \
rmdir(buf1); \
xsymlink(dir, buf1); \
LOGI("link: %s\n", buf1); \
if (MNT_DIR_IS(dir) && !MNT_TYPE_IS("tmpfs") && !MNT_TYPE_IS("overlay")) { \
SETMIR(buf1, part); \
rmdir(buf1); \
xsymlink(dir, buf1); \
LOGI("link: %s\n", buf1); \
break; \
}
#define link_orig(part) link_orig_dir("/" #part, part)
@@ -66,20 +81,22 @@ static void mount_mirrors() {
LOGI("* Mounting mirrors\n");
parse_mnt("/proc/mounts", [&](mntent *me) {
struct stat st;
if (0) {}
mount_mirror(system, MS_RDONLY)
mount_mirror(vendor, MS_RDONLY)
mount_mirror(product, MS_RDONLY)
mount_mirror(system_ext, MS_RDONLY)
mount_mirror(data, 0)
link_orig(cache)
link_orig(metadata)
link_orig(persist)
link_orig_dir("/mnt/vendor/persist", persist)
else if (SDK_INT >= 24 && MNT_DIR_IS("/proc") && !strstr(me->mnt_opts, "hidepid=2")) {
xmount(nullptr, "/proc", nullptr, MS_REMOUNT, "hidepid=2,gid=3009");
}
struct stat st{};
do {
mount_mirror(system)
mount_mirror(vendor)
mount_mirror(product)
mount_mirror(system_ext)
mount_mirror(data)
link_orig(cache)
link_orig(metadata)
link_orig(persist)
link_orig_dir("/mnt/vendor/persist", persist)
if (SDK_INT >= 24 && MNT_DIR_IS("/proc") && !strstr(me->mnt_opts, "hidepid=2")) {
xmount(nullptr, "/proc", nullptr, MS_REMOUNT, "hidepid=2,gid=3009");
break;
}
} while (false);
return true;
});
SETMIR(buf1, system);
@@ -89,7 +106,7 @@ static void mount_mirrors() {
parse_mnt("/proc/mounts", [&](mntent *me) {
struct stat st;
if (MNT_DIR_IS("/") && me->mnt_type != "rootfs"sv && stat("/", &st) == 0) {
do_mount_mirror(system_root, MS_RDONLY)
do_mount_mirror(system_root)
return false;
}
return true;
@@ -256,6 +273,7 @@ static bool check_key_combo() {
***********************/
static pthread_mutex_t stage_lock = PTHREAD_MUTEX_INITIALIZER;
extern int disable_deny();
void post_fs_data(int client) {
// ack

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