diff --git a/app/src/main/java/com/topjohnwu/magisk/core/Config.kt b/app/src/main/java/com/topjohnwu/magisk/core/Config.kt
index c42c67443..1253875af 100644
--- a/app/src/main/java/com/topjohnwu/magisk/core/Config.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/core/Config.kt
@@ -37,6 +37,7 @@ object Config : PreferenceModel, DBConfig {
const val SU_MULTIUSER_MODE = "multiuser_mode"
const val SU_MNT_NS = "mnt_ns"
const val SU_BIOMETRIC = "su_biometric"
+ const val ZYGISK = "zygisk"
const val SU_MANAGER = "requester"
const val KEYSTORE = "keystore"
@@ -143,6 +144,7 @@ object Config : PreferenceModel, DBConfig {
var suMntNamespaceMode by dbSettings(Key.SU_MNT_NS, Value.NAMESPACE_MODE_REQUESTER)
var suMultiuserMode by dbSettings(Key.SU_MULTIUSER_MODE, Value.MULTIUSER_MODE_OWNER_ONLY)
var suBiometric by dbSettings(Key.SU_BIOMETRIC, false)
+ var zygisk by dbSettings(Key.ZYGISK, false)
var suManager by dbStrings(Key.SU_MANAGER, "", true)
var keyStoreRaw by dbStrings(Key.KEYSTORE, "", true)
diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/BaseSettingsItem.kt b/app/src/main/java/com/topjohnwu/magisk/ui/settings/BaseSettingsItem.kt
index ad216f42f..812aeac49 100644
--- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/BaseSettingsItem.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/ui/settings/BaseSettingsItem.kt
@@ -34,7 +34,7 @@ sealed class BaseSettingsItem : ObservableRvItem() {
@get:Bindable
var isEnabled = true
- set(value) = set(value, field, { field = it }, BR.enabled)
+ set(value) = set(value, field, { field = it }, BR.enabled, BR.description)
open fun onPressed(view: View, callback: Callback) {
callback.onItemPressed(view, this)
diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt
index 54a268717..9d4c47019 100644
--- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt
@@ -234,23 +234,44 @@ object Magisk : BaseSettingsItem.Section() {
override val title = R.string.magisk.asText()
}
+object Zygisk : BaseSettingsItem.Toggle() {
+ override val title = R.string.zygisk.asText()
+ override val description = R.string.settings_zygisk_summary.asText()
+ override var value = Config.zygisk
+ set(value) = setV(value, field, { field = it }) {
+ Config.zygisk = it
+ DenyList.isEnabled = it
+ DenyListConfig.isEnabled = it
+ }
+}
+
object DenyList : BaseSettingsItem.Toggle() {
override val title = R.string.settings_denylist_title.asText()
- override val description = R.string.settings_denylist_summary.asText()
+ override val description get() =
+ if (isEnabled) R.string.settings_denylist_summary.asText()
+ else R.string.settings_denylist_error.asText(R.string.zygisk.asText())
+
override var value = Info.env.denyListEnforced
set(value) = setV(value, field, { field = it }) {
val cmd = if (it) "enable" else "disable"
- Shell.su("magisk --denylist $cmd").submit { cb ->
- if (cb.isSuccess) Info.env.denyListEnforced = it
+ Shell.su("magisk --denylist $cmd").submit { result ->
+ if (result.isSuccess) Info.env.denyListEnforced = it
else field = !it
}
DenyListConfig.isEnabled = it
}
+
+ override fun refresh() {
+ isEnabled = Zygisk.value
+ }
}
object DenyListConfig : BaseSettingsItem.Blank() {
override val title = R.string.settings_denylist_config_title.asText()
override val description = R.string.settings_denylist_config_summary.asText()
+ override fun refresh() {
+ isEnabled = Zygisk.value
+ }
}
// --- Superuser
diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt
index 1340360ff..8afc4ba22 100644
--- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt
@@ -69,7 +69,7 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Callback {
SystemlessHosts
))
if (Const.Version.isCanary()) {
- list.addAll(listOf(DenyList, DenyListConfig))
+ list.addAll(listOf(Zygisk, DenyList, DenyListConfig))
}
}
diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/TextHolder.kt b/app/src/main/java/com/topjohnwu/magisk/utils/TextHolder.kt
index 7f3404228..3cf52ee51 100644
--- a/app/src/main/java/com/topjohnwu/magisk/utils/TextHolder.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/utils/TextHolder.kt
@@ -14,20 +14,26 @@ abstract class TextHolder {
class String(
private val value: CharSequence
) : TextHolder() {
-
override val isEmpty get() = value.isEmpty()
override fun getText(resources: Resources) = value
-
}
- class Resource(
- private val value: Int,
- private vararg val params: Any
+ open class Resource(
+ protected val value: Int
) : TextHolder() {
-
override val isEmpty get() = value == 0
- override fun getText(resources: Resources) = resources.getString(value, *params)
+ override fun getText(resources: Resources) = resources.getString(value)
+ }
+ class ResourceArgs(
+ value: Int,
+ private vararg val params: Any
+ ) : Resource(value) {
+ override fun getText(resources: Resources): kotlin.String {
+ // Replace TextHolder with strings
+ val args = params.map { if (it is TextHolder) it.getText(resources) else it }
+ return resources.getString(value, *args.toTypedArray())
+ }
}
// ---
@@ -37,7 +43,8 @@ abstract class TextHolder {
}
}
-fun Int.asText(vararg params: Any): TextHolder = TextHolder.Resource(this, *params)
+fun Int.asText(): TextHolder = TextHolder.Resource(this)
+fun Int.asText(vararg params: Any): TextHolder = TextHolder.ResourceArgs(this, *params)
fun CharSequence.asText(): TextHolder = TextHolder.String(this)
diff --git a/app/src/main/res/values/resources.xml b/app/src/main/res/values/resources.xml
index 16d5d048e..00d5c51d0 100644
--- a/app/src/main/res/values/resources.xml
+++ b/app/src/main/res/values/resources.xml
@@ -3,6 +3,7 @@
Magisk
+ Zygisk
\@topjohnwu
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 263b361b0..144aba5bf 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -145,8 +145,10 @@
Beta
Custom Channel
Insert a custom URL
+ Run parts of Magisk in the zygote daemon
Enforce DenyList
Processes on the denylist will have all Magisk modifications reverted
+ This feature requires %1$s to be enabled
Configure DenyList
Select the processes to be included on the denylist
Systemless hosts
diff --git a/native/jni/core/bootstages.cpp b/native/jni/core/bootstages.cpp
index 361bbacb8..73806dfab 100644
--- a/native/jni/core/bootstages.cpp
+++ b/native/jni/core/bootstages.cpp
@@ -18,6 +18,7 @@
using namespace std;
static bool safe_mode = false;
+bool zygisk_enabled = false;
/*********
* Setup *
@@ -301,7 +302,12 @@ void post_fs_data(int client) {
disable_deny();
} else {
exec_common_scripts("post-fs-data");
- check_enforce_denylist();
+ db_settings dbs;
+ get_db_settings(dbs, ZYGISK_CONFIG);
+ if (dbs[ZYGISK_CONFIG]) {
+ zygisk_enabled = true;
+ check_enforce_denylist();
+ }
handle_modules();
}
@@ -350,8 +356,6 @@ void boot_complete(int client) {
if (access(SECURE_DIR, F_OK) != 0)
xmkdir(SECURE_DIR, 0700);
- check_enforce_denylist();
-
if (!check_manager()) {
if (access(MANAGERAPK, F_OK) == 0) {
// Only try to install APK when no manager is installed
diff --git a/native/jni/core/core.hpp b/native/jni/core/core.hpp
index 73777ffd0..70a85ed4e 100644
--- a/native/jni/core/core.hpp
+++ b/native/jni/core/core.hpp
@@ -6,6 +6,7 @@
extern bool RECOVERY_MODE;
extern int DAEMON_STATE;
+extern bool zygisk_enabled;
void unlock_blocks();
void reboot();
diff --git a/native/jni/core/db.cpp b/native/jni/core/db.cpp
index 82d9a4ff1..4667fd629 100644
--- a/native/jni/core/db.cpp
+++ b/native/jni/core/db.cpp
@@ -113,6 +113,7 @@ db_settings::db_settings() {
data[SU_MULTIUSER_MODE] = MULTIUSER_MODE_OWNER_ONLY;
data[SU_MNT_NS] = NAMESPACE_MODE_REQUESTER;
data[DENYLIST_CONFIG] = false;
+ data[ZYGISK_CONFIG] = false;
}
int db_settings::get_idx(string_view key) const {
diff --git a/native/jni/core/module.cpp b/native/jni/core/module.cpp
index f9e882799..5dc69b519 100644
--- a/native/jni/core/module.cpp
+++ b/native/jni/core/module.cpp
@@ -616,10 +616,12 @@ void magic_mount() {
root->mount();
// Mount on top of modules to enable zygisk
- string zygisk_bin = MAGISKTMP + "/" ZYGISKBIN;
- mkdir(zygisk_bin.data(), 0);
- mount_zygisk(32)
- mount_zygisk(64)
+ if (zygisk_enabled) {
+ string zygisk_bin = MAGISKTMP + "/" ZYGISKBIN;
+ mkdir(zygisk_bin.data(), 0);
+ mount_zygisk(32)
+ mount_zygisk(64)
+ }
}
static void prepare_modules() {
diff --git a/native/jni/include/db.hpp b/native/jni/include/db.hpp
index 69df70353..59cc9d6e6 100644
--- a/native/jni/include/db.hpp
+++ b/native/jni/include/db.hpp
@@ -38,7 +38,8 @@ constexpr const char *DB_SETTING_KEYS[] = {
"root_access",
"multiuser_mode",
"mnt_ns",
- "denylist"
+ "denylist",
+ "zygisk"
};
// Settings key indices
@@ -46,7 +47,8 @@ enum {
ROOT_ACCESS = 0,
SU_MULTIUSER_MODE,
SU_MNT_NS,
- DENYLIST_CONFIG
+ DENYLIST_CONFIG,
+ ZYGISK_CONFIG
};
// Values for root_access