From 959430e030f1b51151150c6742fb034b87badd25 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 5 Aug 2025 02:22:39 -0700 Subject: [PATCH] Fix systemless hosts installation --- .../magisk/ui/settings/SettingsViewModel.kt | 5 +- .../magisk/core/utils/IRootUtils.aidl | 1 + .../com/topjohnwu/magisk/core/ktx/XAndroid.kt | 2 +- .../topjohnwu/magisk/core/utils/RootUtils.kt | 52 ++++++++++++++----- .../com/topjohnwu/magisk/test/Environment.kt | 4 +- scripts/app_functions.sh | 18 ------- 6 files changed, 48 insertions(+), 34 deletions(-) diff --git a/app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt b/app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt index ffb07682e..1a6db30cc 100644 --- a/app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt +++ b/app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt @@ -22,11 +22,11 @@ import com.topjohnwu.magisk.core.ktx.activity import com.topjohnwu.magisk.core.ktx.toast import com.topjohnwu.magisk.core.tasks.AppMigration import com.topjohnwu.magisk.core.utils.LocaleSetting +import com.topjohnwu.magisk.core.utils.RootUtils import com.topjohnwu.magisk.databinding.bindExtra import com.topjohnwu.magisk.events.AddHomeIconEvent import com.topjohnwu.magisk.events.AuthEvent import com.topjohnwu.magisk.events.SnackbarEvent -import com.topjohnwu.superuser.Shell import kotlinx.coroutines.launch class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler { @@ -130,7 +130,8 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler { } private fun createHosts() { - Shell.cmd("add_hosts_module").submit { + viewModelScope.launch { + RootUtils.addSystemlessHosts() AppContext.toast(R.string.settings_hosts_toast, Toast.LENGTH_SHORT) } } diff --git a/app/core/src/main/aidl/com/topjohnwu/magisk/core/utils/IRootUtils.aidl b/app/core/src/main/aidl/com/topjohnwu/magisk/core/utils/IRootUtils.aidl index 981d82d69..242e14b6a 100644 --- a/app/core/src/main/aidl/com/topjohnwu/magisk/core/utils/IRootUtils.aidl +++ b/app/core/src/main/aidl/com/topjohnwu/magisk/core/utils/IRootUtils.aidl @@ -6,4 +6,5 @@ package com.topjohnwu.magisk.core.utils; interface IRootUtils { android.app.ActivityManager.RunningAppProcessInfo getAppProcess(int pid); IBinder getFileSystem(); + boolean addSystemlessHosts(); } diff --git a/app/core/src/main/java/com/topjohnwu/magisk/core/ktx/XAndroid.kt b/app/core/src/main/java/com/topjohnwu/magisk/core/ktx/XAndroid.kt index 52b0e0718..3a172e085 100644 --- a/app/core/src/main/java/com/topjohnwu/magisk/core/ktx/XAndroid.kt +++ b/app/core/src/main/java/com/topjohnwu/magisk/core/ktx/XAndroid.kt @@ -109,7 +109,7 @@ fun PackageManager.getPackageInfo(uid: Int, pid: Int): PackageInfo? { return null } // Try to find package name from PID - val proc = RootUtils.obj?.getAppProcess(pid) + val proc = RootUtils.getAppProcess(pid) if (proc == null) { if (uid == Process.SHELL_UID) { // It is possible that some apps installed are sharing UID with shell. diff --git a/app/core/src/main/java/com/topjohnwu/magisk/core/utils/RootUtils.kt b/app/core/src/main/java/com/topjohnwu/magisk/core/utils/RootUtils.kt index b4a209355..a0cd05a5b 100644 --- a/app/core/src/main/java/com/topjohnwu/magisk/core/utils/RootUtils.kt +++ b/app/core/src/main/java/com/topjohnwu/magisk/core/utils/RootUtils.kt @@ -7,11 +7,14 @@ import android.content.ServiceConnection import android.os.IBinder import android.system.Os import androidx.core.content.getSystemService +import com.topjohnwu.magisk.core.Const import com.topjohnwu.magisk.core.Info import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.ShellUtils import com.topjohnwu.superuser.ipc.RootService import com.topjohnwu.superuser.nio.FileSystemManager +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import timber.log.Timber import java.io.File import java.util.concurrent.locks.AbstractQueuedSynchronizer @@ -43,16 +46,7 @@ class RootUtils(stub: Any?) : RootService() { return object : IRootUtils.Stub() { override fun getAppProcess(pid: Int) = safe(null) { getAppProcessImpl(pid) } override fun getFileSystem(): IBinder = FileSystemManager.getService() - } - } - - private inline fun safe(default: T, block: () -> T): T { - return try { - block() - } catch (e: Throwable) { - // The process died unexpectedly - Timber.e(e) - default + override fun addSystemlessHosts() = safe(false) { addSystemlessHostsImpl() } } } @@ -78,6 +72,26 @@ class RootUtils(stub: Any?) : RootService() { return null } + private fun addSystemlessHostsImpl(): Boolean { + val module = File(Const.MODULE_PATH, "hosts") + if (module.exists()) return true + val hosts = File(module, "system/etc/hosts") + if (!hosts.parentFile.mkdirs()) return false + File(module, "module.prop").outputStream().writer().use { + it.write(""" + id=hosts + name=Systemless Hosts + version=1.0 + versionCode=1 + author=Magisk + description=Magisk app built-in systemless hosts module + """.trimIndent()) + } + File("/system/etc/hosts").copyTo(hosts) + File(module, "update").createNewFile() + return true + } + object Connection : AbstractQueuedSynchronizer(), ServiceConnection { init { state = 1 @@ -131,11 +145,25 @@ class RootUtils(stub: Any?) : RootService() { return field } private set - var obj: IRootUtils? = null + private var obj: IRootUtils? = null get() { Connection.await() return field } - private set + + fun getAppProcess(pid: Int) = safe(null) { obj?.getAppProcess(pid) } + + suspend fun addSystemlessHosts() = + withContext(Dispatchers.IO) { safe(false) { obj?.addSystemlessHosts() ?: false } } + + private inline fun safe(default: T, block: () -> T): T { + return try { + block() + } catch (e: Throwable) { + // The process died unexpectedly + Timber.e(e) + default + } + } } } diff --git a/app/core/src/main/java/com/topjohnwu/magisk/test/Environment.kt b/app/core/src/main/java/com/topjohnwu/magisk/test/Environment.kt index 24de33111..adb781a46 100644 --- a/app/core/src/main/java/com/topjohnwu/magisk/test/Environment.kt +++ b/app/core/src/main/java/com/topjohnwu/magisk/test/Environment.kt @@ -123,7 +123,9 @@ class Environment : BaseTest { } private fun setupSystemlessHost() { - assertTrue("hosts setup failed", Shell.cmd("add_hosts_module").exec().isSuccess) + val error = "hosts setup failed" + assertTrue(error, runBlocking { RootUtils.addSystemlessHosts() }) + assertTrue(error, RootUtils.fs.getFile(Const.MODULE_PATH).getChildFile("hosts").exists()) } private fun setupSepolicyRuleModule(root: ExtendedFile) { diff --git a/scripts/app_functions.sh b/scripts/app_functions.sh index 5ac141314..26dc0d66f 100644 --- a/scripts/app_functions.sh +++ b/scripts/app_functions.sh @@ -118,24 +118,6 @@ EOF cd / } -add_hosts_module() { - # Do not touch existing hosts module - [ -d /data/adb/modules/hosts ] && return - cd /data/adb/modules - mkdir -p hosts/system/etc - cat << EOF > hosts/module.prop -id=hosts -name=Systemless Hosts -version=1.0 -versionCode=1 -author=Magisk -description=Magisk app built-in systemless hosts module -EOF - magisk --clone /system/etc/hosts hosts/system/etc/hosts - touch hosts/update - cd / -} - # $1 = APK # $2 = package name adb_pm_install() {