Backend: do not use singletons
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
314a0d124d
commit
7a4af834c2
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
package com.wireguard.android;
|
package com.wireguard.android;
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
@ -20,7 +19,6 @@ import androidx.preference.PreferenceManager;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AppCompatDelegate;
|
import androidx.appcompat.app.AppCompatDelegate;
|
||||||
|
|
||||||
import com.wireguard.android.activity.MainActivity;
|
|
||||||
import com.wireguard.android.backend.Backend;
|
import com.wireguard.android.backend.Backend;
|
||||||
import com.wireguard.android.backend.GoBackend;
|
import com.wireguard.android.backend.GoBackend;
|
||||||
import com.wireguard.android.backend.WgQuickBackend;
|
import com.wireguard.android.backend.WgQuickBackend;
|
||||||
@ -88,7 +86,7 @@ public class Application extends android.app.Application {
|
|||||||
try {
|
try {
|
||||||
if (!didStartRootShell)
|
if (!didStartRootShell)
|
||||||
app.rootShell.start();
|
app.rootShell.start();
|
||||||
backend = new WgQuickBackend(app.getApplicationContext());
|
backend = new WgQuickBackend(app.getApplicationContext(), app.rootShell, app.toolsInstaller);
|
||||||
} catch (final Exception ignored) {
|
} catch (final Exception ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,6 +117,7 @@ public class Application extends android.app.Application {
|
|||||||
public static ToolsInstaller getToolsInstaller() {
|
public static ToolsInstaller getToolsInstaller() {
|
||||||
return get().toolsInstaller;
|
return get().toolsInstaller;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ModuleLoader getModuleLoader() {
|
public static ModuleLoader getModuleLoader() {
|
||||||
return get().moduleLoader;
|
return get().moduleLoader;
|
||||||
}
|
}
|
||||||
@ -152,8 +151,8 @@ public class Application extends android.app.Application {
|
|||||||
|
|
||||||
asyncWorker = new AsyncWorker(AsyncTask.SERIAL_EXECUTOR, new Handler(Looper.getMainLooper()));
|
asyncWorker = new AsyncWorker(AsyncTask.SERIAL_EXECUTOR, new Handler(Looper.getMainLooper()));
|
||||||
rootShell = new RootShell(getApplicationContext());
|
rootShell = new RootShell(getApplicationContext());
|
||||||
toolsInstaller = new ToolsInstaller(getApplicationContext());
|
toolsInstaller = new ToolsInstaller(getApplicationContext(), rootShell);
|
||||||
moduleLoader = new ModuleLoader(getApplicationContext());
|
moduleLoader = new ModuleLoader(getApplicationContext(), rootShell, USER_AGENT);
|
||||||
|
|
||||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||||
|
@ -10,9 +10,10 @@ import androidx.annotation.Nullable;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.wireguard.android.Application;
|
|
||||||
import com.wireguard.android.backend.BackendException.Reason;
|
import com.wireguard.android.backend.BackendException.Reason;
|
||||||
import com.wireguard.android.backend.Tunnel.State;
|
import com.wireguard.android.backend.Tunnel.State;
|
||||||
|
import com.wireguard.android.util.RootShell;
|
||||||
|
import com.wireguard.android.util.ToolsInstaller;
|
||||||
import com.wireguard.config.Config;
|
import com.wireguard.config.Config;
|
||||||
import com.wireguard.crypto.Key;
|
import com.wireguard.crypto.Key;
|
||||||
|
|
||||||
@ -40,12 +41,16 @@ import java9.util.stream.Stream;
|
|||||||
public final class WgQuickBackend implements Backend {
|
public final class WgQuickBackend implements Backend {
|
||||||
private static final String TAG = "WireGuard/" + WgQuickBackend.class.getSimpleName();
|
private static final String TAG = "WireGuard/" + WgQuickBackend.class.getSimpleName();
|
||||||
|
|
||||||
|
private final RootShell rootShell;
|
||||||
|
private final ToolsInstaller toolsInstaller;
|
||||||
private final File localTemporaryDir;
|
private final File localTemporaryDir;
|
||||||
private final Map<Tunnel, Config> runningConfigs = new HashMap<>();
|
private final Map<Tunnel, Config> runningConfigs = new HashMap<>();
|
||||||
private final Set<TunnelStateChangeNotificationReceiver> notifiers = new HashSet<>();
|
private final Set<TunnelStateChangeNotificationReceiver> notifiers = new HashSet<>();
|
||||||
|
|
||||||
public WgQuickBackend(final Context context) {
|
public WgQuickBackend(final Context context, final RootShell rootShell, final ToolsInstaller toolsInstaller) {
|
||||||
localTemporaryDir = new File(context.getCacheDir(), "tmp");
|
localTemporaryDir = new File(context.getCacheDir(), "tmp");
|
||||||
|
this.rootShell = rootShell;
|
||||||
|
this.toolsInstaller = toolsInstaller;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -53,8 +58,8 @@ public final class WgQuickBackend implements Backend {
|
|||||||
final List<String> output = new ArrayList<>();
|
final List<String> output = new ArrayList<>();
|
||||||
// Don't throw an exception here or nothing will show up in the UI.
|
// Don't throw an exception here or nothing will show up in the UI.
|
||||||
try {
|
try {
|
||||||
Application.getToolsInstaller().ensureToolsAvailable();
|
toolsInstaller.ensureToolsAvailable();
|
||||||
if (Application.getRootShell().run(output, "wg show interfaces") != 0 || output.isEmpty())
|
if (rootShell.run(output, "wg show interfaces") != 0 || output.isEmpty())
|
||||||
return Collections.emptySet();
|
return Collections.emptySet();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
Log.w(TAG, "Unable to enumerate running tunnels", e);
|
Log.w(TAG, "Unable to enumerate running tunnels", e);
|
||||||
@ -74,7 +79,7 @@ public final class WgQuickBackend implements Backend {
|
|||||||
final Statistics stats = new Statistics();
|
final Statistics stats = new Statistics();
|
||||||
final Collection<String> output = new ArrayList<>();
|
final Collection<String> output = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
if (Application.getRootShell().run(output, String.format("wg show '%s' transfer", tunnel.getName())) != 0)
|
if (rootShell.run(output, String.format("wg show '%s' transfer", tunnel.getName())) != 0)
|
||||||
return stats;
|
return stats;
|
||||||
} catch (final Exception ignored) {
|
} catch (final Exception ignored) {
|
||||||
return stats;
|
return stats;
|
||||||
@ -94,8 +99,7 @@ public final class WgQuickBackend implements Backend {
|
|||||||
@Override
|
@Override
|
||||||
public String getVersion() throws Exception {
|
public String getVersion() throws Exception {
|
||||||
final List<String> output = new ArrayList<>();
|
final List<String> output = new ArrayList<>();
|
||||||
if (Application.getRootShell()
|
if (rootShell.run(output, "cat /sys/module/wireguard/version") != 0 || output.isEmpty())
|
||||||
.run(output, "cat /sys/module/wireguard/version") != 0 || output.isEmpty())
|
|
||||||
throw new BackendException(Reason.UNKNOWN_KERNEL_MODULE_NAME);
|
throw new BackendException(Reason.UNKNOWN_KERNEL_MODULE_NAME);
|
||||||
return output.get(0);
|
return output.get(0);
|
||||||
}
|
}
|
||||||
@ -111,7 +115,7 @@ public final class WgQuickBackend implements Backend {
|
|||||||
(state == State.DOWN && originalState == State.DOWN))
|
(state == State.DOWN && originalState == State.DOWN))
|
||||||
return originalState;
|
return originalState;
|
||||||
if (state == State.UP) {
|
if (state == State.UP) {
|
||||||
Application.getToolsInstaller().ensureToolsAvailable();
|
toolsInstaller.ensureToolsAvailable();
|
||||||
if (originalState == State.UP)
|
if (originalState == State.UP)
|
||||||
setStateInternal(tunnel, originalConfig == null ? config : originalConfig, State.DOWN);
|
setStateInternal(tunnel, originalConfig == null ? config : originalConfig, State.DOWN);
|
||||||
try {
|
try {
|
||||||
@ -140,7 +144,7 @@ public final class WgQuickBackend implements Backend {
|
|||||||
state.toString().toLowerCase(Locale.ENGLISH), tempFile.getAbsolutePath());
|
state.toString().toLowerCase(Locale.ENGLISH), tempFile.getAbsolutePath());
|
||||||
if (state == State.UP)
|
if (state == State.UP)
|
||||||
command = "cat /sys/module/wireguard/version && " + command;
|
command = "cat /sys/module/wireguard/version && " + command;
|
||||||
final int result = Application.getRootShell().run(null, command);
|
final int result = rootShell.run(null, command);
|
||||||
// noinspection ResultOfMethodCallIgnored
|
// noinspection ResultOfMethodCallIgnored
|
||||||
tempFile.delete();
|
tempFile.delete();
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
|
@ -9,7 +9,6 @@ import android.content.Context;
|
|||||||
import android.system.OsConstants;
|
import android.system.OsConstants;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
|
|
||||||
import com.wireguard.android.Application;
|
|
||||||
import com.wireguard.android.util.RootShell.RootShellException;
|
import com.wireguard.android.util.RootShell.RootShellException;
|
||||||
|
|
||||||
import net.i2p.crypto.eddsa.EdDSAEngine;
|
import net.i2p.crypto.eddsa.EdDSAEngine;
|
||||||
@ -43,12 +42,16 @@ public class ModuleLoader {
|
|||||||
private static final String MODULE_URL = "https://download.wireguard.com/android-module/%s";
|
private static final String MODULE_URL = "https://download.wireguard.com/android-module/%s";
|
||||||
private static final String MODULE_NAME = "wireguard-%s.ko";
|
private static final String MODULE_NAME = "wireguard-%s.ko";
|
||||||
|
|
||||||
|
private final RootShell rootShell;
|
||||||
|
private final String userAgent;
|
||||||
private final File moduleDir;
|
private final File moduleDir;
|
||||||
private final File tmpDir;
|
private final File tmpDir;
|
||||||
|
|
||||||
public ModuleLoader(final Context context) {
|
public ModuleLoader(final Context context, final RootShell rootShell, final String userAgent) {
|
||||||
moduleDir = new File(context.getCacheDir(), "kmod");
|
moduleDir = new File(context.getCacheDir(), "kmod");
|
||||||
tmpDir = new File(context.getCacheDir(), "tmp");
|
tmpDir = new File(context.getCacheDir(), "tmp");
|
||||||
|
this.rootShell = rootShell;
|
||||||
|
this.userAgent = userAgent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean moduleMightExist() {
|
public boolean moduleMightExist() {
|
||||||
@ -56,7 +59,7 @@ public class ModuleLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void loadModule() throws IOException, RootShellException {
|
public void loadModule() throws IOException, RootShellException {
|
||||||
Application.getRootShell().run(null, String.format("insmod \"%s/wireguard-$(sha256sum /proc/version|cut -d ' ' -f 1).ko\"", moduleDir.getAbsolutePath()));
|
rootShell.run(null, String.format("insmod \"%s/wireguard-$(sha256sum /proc/version|cut -d ' ' -f 1).ko\"", moduleDir.getAbsolutePath()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isModuleLoaded() {
|
public static boolean isModuleLoaded() {
|
||||||
@ -124,12 +127,12 @@ public class ModuleLoader {
|
|||||||
|
|
||||||
public Integer download() throws IOException, RootShellException, NoSuchAlgorithmException {
|
public Integer download() throws IOException, RootShellException, NoSuchAlgorithmException {
|
||||||
final List<String> output = new ArrayList<>();
|
final List<String> output = new ArrayList<>();
|
||||||
Application.getRootShell().run(output, "sha256sum /proc/version|cut -d ' ' -f 1");
|
rootShell.run(output, "sha256sum /proc/version|cut -d ' ' -f 1");
|
||||||
if (output.size() != 1 || output.get(0).length() != 64)
|
if (output.size() != 1 || output.get(0).length() != 64)
|
||||||
throw new InvalidParameterException("Invalid sha256 of /proc/version");
|
throw new InvalidParameterException("Invalid sha256 of /proc/version");
|
||||||
final String moduleName = String.format(MODULE_NAME, output.get(0));
|
final String moduleName = String.format(MODULE_NAME, output.get(0));
|
||||||
HttpURLConnection connection = (HttpURLConnection)new URL(MODULE_LIST_URL).openConnection();
|
HttpURLConnection connection = (HttpURLConnection)new URL(MODULE_LIST_URL).openConnection();
|
||||||
connection.setRequestProperty("User-Agent", Application.USER_AGENT);
|
connection.setRequestProperty("User-Agent", userAgent);
|
||||||
connection.connect();
|
connection.connect();
|
||||||
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK)
|
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK)
|
||||||
throw new IOException("Hash list could not be found");
|
throw new IOException("Hash list could not be found");
|
||||||
@ -146,7 +149,7 @@ public class ModuleLoader {
|
|||||||
if (!modules.containsKey(moduleName))
|
if (!modules.containsKey(moduleName))
|
||||||
return OsConstants.ENOENT;
|
return OsConstants.ENOENT;
|
||||||
connection = (HttpURLConnection)new URL(String.format(MODULE_URL, moduleName)).openConnection();
|
connection = (HttpURLConnection)new URL(String.format(MODULE_URL, moduleName)).openConnection();
|
||||||
connection.setRequestProperty("User-Agent", Application.USER_AGENT);
|
connection.setRequestProperty("User-Agent", userAgent);
|
||||||
connection.connect();
|
connection.connect();
|
||||||
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK)
|
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK)
|
||||||
throw new IOException("Module file could not be found, despite being on hash list");
|
throw new IOException("Module file could not be found, despite being on hash list");
|
||||||
|
@ -10,7 +10,6 @@ import androidx.annotation.Nullable;
|
|||||||
import android.system.OsConstants;
|
import android.system.OsConstants;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.wireguard.android.Application;
|
|
||||||
import com.wireguard.android.BuildConfig;
|
import com.wireguard.android.BuildConfig;
|
||||||
import com.wireguard.android.util.RootShell.RootShellException;
|
import com.wireguard.android.util.RootShell.RootShellException;
|
||||||
|
|
||||||
@ -39,14 +38,16 @@ public final class ToolsInstaller {
|
|||||||
private static final String TAG = "WireGuard/" + ToolsInstaller.class.getSimpleName();
|
private static final String TAG = "WireGuard/" + ToolsInstaller.class.getSimpleName();
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
private final RootShell rootShell;
|
||||||
private final File localBinaryDir;
|
private final File localBinaryDir;
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
@Nullable private Boolean areToolsAvailable;
|
@Nullable private Boolean areToolsAvailable;
|
||||||
@Nullable private Boolean installAsMagiskModule;
|
@Nullable private Boolean installAsMagiskModule;
|
||||||
|
|
||||||
public ToolsInstaller(final Context context) {
|
public ToolsInstaller(final Context context, final RootShell rootShell) {
|
||||||
localBinaryDir = new File(context.getCodeCacheDir(), "bin");
|
localBinaryDir = new File(context.getCodeCacheDir(), "bin");
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
this.rootShell = rootShell;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@ -73,7 +74,7 @@ public final class ToolsInstaller {
|
|||||||
}
|
}
|
||||||
script.append("exit ").append(OsConstants.EALREADY).append(';');
|
script.append("exit ").append(OsConstants.EALREADY).append(';');
|
||||||
try {
|
try {
|
||||||
final int ret = Application.getRootShell().run(null, script.toString());
|
final int ret = rootShell.run(null, script.toString());
|
||||||
if (ret == OsConstants.EALREADY)
|
if (ret == OsConstants.EALREADY)
|
||||||
return willInstallAsMagiskModule() ? YES | MAGISK : YES | SYSTEM;
|
return willInstallAsMagiskModule() ? YES | MAGISK : YES | SYSTEM;
|
||||||
else
|
else
|
||||||
@ -124,7 +125,7 @@ public final class ToolsInstaller {
|
|||||||
script.append("trap - INT TERM EXIT;");
|
script.append("trap - INT TERM EXIT;");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return Application.getRootShell().run(null, script.toString()) == 0 ? YES | MAGISK : ERROR;
|
return rootShell.run(null, script.toString()) == 0 ? YES | MAGISK : ERROR;
|
||||||
} catch (final IOException ignored) {
|
} catch (final IOException ignored) {
|
||||||
return ERROR;
|
return ERROR;
|
||||||
} catch (final RootShellException e) {
|
} catch (final RootShellException e) {
|
||||||
@ -146,7 +147,7 @@ public final class ToolsInstaller {
|
|||||||
new File(localBinaryDir, name), destination, destination, destination));
|
new File(localBinaryDir, name), destination, destination, destination));
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return Application.getRootShell().run(null, script.toString()) == 0 ? YES | SYSTEM : ERROR;
|
return rootShell.run(null, script.toString()) == 0 ? YES | SYSTEM : ERROR;
|
||||||
} catch (final IOException ignored) {
|
} catch (final IOException ignored) {
|
||||||
return ERROR;
|
return ERROR;
|
||||||
} catch (final RootShellException e) {
|
} catch (final RootShellException e) {
|
||||||
@ -183,7 +184,7 @@ public final class ToolsInstaller {
|
|||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
if (installAsMagiskModule == null) {
|
if (installAsMagiskModule == null) {
|
||||||
try {
|
try {
|
||||||
installAsMagiskModule = Application.getRootShell().run(null, "[ -d /sbin/.magisk/mirror -a -d /sbin/.magisk/img -a ! -f /cache/.disable_magisk ]") == OsConstants.EXIT_SUCCESS;
|
installAsMagiskModule = rootShell.run(null, "[ -d /sbin/.magisk/mirror -a -d /sbin/.magisk/img -a ! -f /cache/.disable_magisk ]") == OsConstants.EXIT_SUCCESS;
|
||||||
} catch (final Exception ignored) {
|
} catch (final Exception ignored) {
|
||||||
installAsMagiskModule = false;
|
installAsMagiskModule = false;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user