From a17ec6b1f755ad2bbe733393bba340ef474deeae Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 5 Jun 2018 05:31:27 +0200 Subject: [PATCH] ToolsInstaller: allow installing as Magisk module Signed-off-by: Jason A. Donenfeld --- .../preference/ToolsInstallerPreference.java | 28 +++++++++---- .../android/util/ToolsInstaller.java | 42 ++++++++++++++++++- app/src/main/res/values/strings.xml | 9 ++-- 3 files changed, 68 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.java b/app/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.java index 437d05e3..4d9e0fa8 100644 --- a/app/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.java +++ b/app/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.java @@ -26,7 +26,7 @@ import com.wireguard.android.util.ToolsInstaller; public class ToolsInstallerPreference extends Preference { private final AsyncWorker asyncWorker; private final ToolsInstaller toolsInstaller; - private State state = State.INITIAL; + private State state; @SuppressWarnings({"SameParameterValue", "WeakerAccess"}) public ToolsInstallerPreference(final Context context, final AttributeSet attrs) { @@ -34,6 +34,7 @@ public class ToolsInstallerPreference extends Preference { final ApplicationComponent applicationComponent = Application.getComponent(); asyncWorker = applicationComponent.getAsyncWorker(); toolsInstaller = applicationComponent.getToolsInstaller(); + state = initialState(); } @Override @@ -54,12 +55,12 @@ public class ToolsInstallerPreference extends Preference { private void onCheckResult(final Integer result, final Throwable throwable) { setState(throwable == null && result == OsConstants.EALREADY ? - State.ALREADY : State.INITIAL); + State.ALREADY : initialState()); } @Override protected void onClick() { - setState(State.WORKING); + setState(workingState()); asyncWorker.supplyAsync(toolsInstaller::install).whenComplete(this::onInstallResult); } @@ -68,7 +69,7 @@ public class ToolsInstallerPreference extends Preference { if (throwable != null) nextState = State.FAILURE; else if (result == OsConstants.EXIT_SUCCESS) - nextState = State.SUCCESS; + nextState = successState(); else if (result == OsConstants.EALREADY) nextState = State.ALREADY; else @@ -85,12 +86,25 @@ public class ToolsInstallerPreference extends Preference { notifyChanged(); } + private State initialState() { + return toolsInstaller.willInstallAsMagiskModule() ? State.INITIAL_MAGISK : State.INITIAL_SYSTEM; + } + private State workingState() { + return toolsInstaller.willInstallAsMagiskModule() ? State.WORKING_MAGISK : State.WORKING_SYSTEM; + } + private State successState() { + return toolsInstaller.willInstallAsMagiskModule() ? State.SUCCESS_MAGISK : State.SUCCESS_SYSTEM; + } + private enum State { ALREADY(R.string.tools_installer_already, false), FAILURE(R.string.tools_installer_failure, true), - INITIAL(R.string.tools_installer_initial, true), - SUCCESS(R.string.tools_installer_success, false), - WORKING(R.string.tools_installer_working, false); + INITIAL_SYSTEM(R.string.tools_installer_initial_system, true), + SUCCESS_SYSTEM(R.string.tools_installer_success_system, false), + WORKING_SYSTEM(R.string.tools_installer_working_system, false), + INITIAL_MAGISK(R.string.tools_installer_initial_magisk, true), + SUCCESS_MAGISK(R.string.tools_installer_success_magisk, false), + WORKING_MAGISK(R.string.tools_installer_working_magisk, false); private final int messageResourceId; private final boolean shouldEnableView; diff --git a/app/src/main/java/com/wireguard/android/util/ToolsInstaller.java b/app/src/main/java/com/wireguard/android/util/ToolsInstaller.java index de82e69c..0ce089fd 100644 --- a/app/src/main/java/com/wireguard/android/util/ToolsInstaller.java +++ b/app/src/main/java/com/wireguard/android/util/ToolsInstaller.java @@ -13,6 +13,7 @@ import android.util.Log; import com.wireguard.android.Application; import com.wireguard.android.Application.ApplicationContext; import com.wireguard.android.Application.ApplicationScope; +import com.wireguard.android.BuildConfig; import com.wireguard.android.util.RootShell.NoRootException; import java.io.File; @@ -48,6 +49,7 @@ public final class ToolsInstaller { private final File nativeLibraryDir; private final RootShell rootShell; private Boolean areToolsAvailable; + private Boolean installAsMagiskModule; @Inject public ToolsInstaller(@ApplicationContext final Context context, final RootShell rootShell) { @@ -114,7 +116,20 @@ public final class ToolsInstaller { } } - public int install() throws NoRootException { + public boolean willInstallAsMagiskModule() { + synchronized (lock) { + if (installAsMagiskModule == null) { + try { + installAsMagiskModule = rootShell.run(null, "[ -d /sbin/.core/mirror -a -d /sbin/.core/img -a ! -f /cache/.disable_magisk ]") == OsConstants.EXIT_SUCCESS; + } catch (final Exception ignored) { + installAsMagiskModule = false; + } + } + return installAsMagiskModule; + } + } + + private int installSystem() throws NoRootException { if (INSTALL_DIR == null) return OsConstants.ENOENT; final StringBuilder script = new StringBuilder("set -ex; "); @@ -131,6 +146,31 @@ public final class ToolsInstaller { } } + private int installMagisk() throws NoRootException { + final StringBuilder script = new StringBuilder("set -ex; "); + + script.append("trap 'rm -rf /sbin/.core/img/wireguard' INT TERM EXIT; "); + script.append(String.format("rm -rf /sbin/.core/img/wireguard/; mkdir -p /sbin/.core/img/wireguard%s; ", INSTALL_DIR)); + script.append(String.format("printf 'name=WireGuard Command Line Tools\nversion=%s\nversionCode=%s\nauthor=zx2c4\ndescription=Command line tools for WireGuard\nminMagisk=1500\n' > /sbin/.core/img/wireguard/module.prop; ", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)); + script.append("touch /sbin/.core/img/wireguard/auto_mount; "); + for (final String[] names : EXECUTABLES) { + final File destination = new File("/sbin/.core/img/wireguard" + INSTALL_DIR, names[1]); + script.append(String.format("cp '%s' '%s'; chmod 755 '%s'; restorecon '%s' || true; ", + new File(nativeLibraryDir, names[0]), destination, destination, destination)); + } + script.append("trap - INT TERM EXIT;"); + + try { + return rootShell.run(null, script.toString()); + } catch (final IOException ignored) { + return OsConstants.EXIT_FAILURE; + } + } + + public int install() throws NoRootException { + return willInstallAsMagiskModule() ? installMagisk() : installSystem(); + } + public int symlink() throws NoRootException { final StringBuilder script = new StringBuilder("set -x; "); for (final String[] names : EXECUTABLES) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 893f9a16..47c1e9a0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -69,10 +69,13 @@ Error toggling WireGuard tunnel: %s wg and wg-quick are already installed Unable to install command-line tools (no root?) - Install optional tools for scripting into the system partition - wg and wg-quick installed into the system partition + Install optional tools for scripting into the system partition + Install optional tools for scripting as Magisk module + wg and wg-quick installed into the system partition + wg and wg-quick installed as a Magisk module (reboot required) Install command line tools - Installing wg and wg-quick into the system partition + Installing wg and wg-quick into the system partition + Installing wg and wg-quick as a Magisk module Unable to create tunnel: %s Successfully created tunnel ā€œ%sā€ Unable to rename tunnel: %s