ErrorMessages: do not use R from backend
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
453a1aaa65
commit
afd75cc4cf
@ -41,13 +41,6 @@ public interface Backend {
|
|||||||
*/
|
*/
|
||||||
Statistics getStatistics(Tunnel tunnel) throws Exception;
|
Statistics getStatistics(Tunnel tunnel) throws Exception;
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine type name of underlying backend.
|
|
||||||
*
|
|
||||||
* @return Type name
|
|
||||||
*/
|
|
||||||
String getTypePrettyName();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine version of underlying backend.
|
* Determine version of underlying backend.
|
||||||
*
|
*
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.wireguard.android.backend;
|
||||||
|
|
||||||
|
public final class BackendException extends Exception {
|
||||||
|
public enum Reason {
|
||||||
|
UNKNOWN_KERNEL_MODULE_NAME,
|
||||||
|
WG_QUICK_CONFIG_ERROR_CODE,
|
||||||
|
TUNNEL_MISSING_CONFIG,
|
||||||
|
VPN_NOT_AUTHORIZED,
|
||||||
|
UNABLE_TO_START_VPN,
|
||||||
|
TUN_CREATION_ERROR,
|
||||||
|
GO_ACTIVATION_ERROR_CODE
|
||||||
|
|
||||||
|
}
|
||||||
|
private final Reason reason;
|
||||||
|
private final Object[] format;
|
||||||
|
public BackendException(final Reason reason, final Object ...format) {
|
||||||
|
this.reason = reason;
|
||||||
|
this.format = format;
|
||||||
|
}
|
||||||
|
public Reason getReason() {
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
public Object[] getFormat() {
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
}
|
@ -14,10 +14,8 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.collection.ArraySet;
|
import androidx.collection.ArraySet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.wireguard.android.Application;
|
import com.wireguard.android.backend.BackendException.Reason;
|
||||||
import com.wireguard.android.R;
|
|
||||||
import com.wireguard.android.backend.Tunnel.State;
|
import com.wireguard.android.backend.Tunnel.State;
|
||||||
import com.wireguard.android.util.ExceptionLoggers;
|
|
||||||
import com.wireguard.android.util.SharedLibraryLoader;
|
import com.wireguard.android.util.SharedLibraryLoader;
|
||||||
import com.wireguard.config.Config;
|
import com.wireguard.config.Config;
|
||||||
import com.wireguard.config.InetNetwork;
|
import com.wireguard.config.InetNetwork;
|
||||||
@ -28,7 +26,6 @@ import com.wireguard.crypto.KeyFormatException;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
@ -130,11 +127,6 @@ public final class GoBackend implements Backend {
|
|||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getTypePrettyName() {
|
|
||||||
return context.getString(R.string.type_name_go_userspace);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getVersion() {
|
public String getVersion() {
|
||||||
return wgVersion();
|
return wgVersion();
|
||||||
@ -171,10 +163,11 @@ public final class GoBackend implements Backend {
|
|||||||
Log.i(TAG, "Bringing tunnel " + tunnel.getName() + " " + state);
|
Log.i(TAG, "Bringing tunnel " + tunnel.getName() + " " + state);
|
||||||
|
|
||||||
if (state == State.UP) {
|
if (state == State.UP) {
|
||||||
Objects.requireNonNull(config, context.getString(R.string.no_config_error));
|
if (config == null)
|
||||||
|
throw new BackendException(Reason.TUNNEL_MISSING_CONFIG);
|
||||||
|
|
||||||
if (VpnService.prepare(context) != null)
|
if (VpnService.prepare(context) != null)
|
||||||
throw new Exception(context.getString(R.string.vpn_not_authorized_error));
|
throw new BackendException(Reason.VPN_NOT_AUTHORIZED);
|
||||||
|
|
||||||
final VpnService service;
|
final VpnService service;
|
||||||
if (!vpnService.isDone())
|
if (!vpnService.isDone())
|
||||||
@ -183,7 +176,9 @@ public final class GoBackend implements Backend {
|
|||||||
try {
|
try {
|
||||||
service = vpnService.get(2, TimeUnit.SECONDS);
|
service = vpnService.get(2, TimeUnit.SECONDS);
|
||||||
} catch (final TimeoutException e) {
|
} catch (final TimeoutException e) {
|
||||||
throw new Exception(context.getString(R.string.vpn_start_error), e);
|
final Exception be = new BackendException(Reason.UNABLE_TO_START_VPN);
|
||||||
|
be.initCause(e);
|
||||||
|
throw be;
|
||||||
}
|
}
|
||||||
service.setOwner(this);
|
service.setOwner(this);
|
||||||
|
|
||||||
@ -225,12 +220,12 @@ public final class GoBackend implements Backend {
|
|||||||
builder.setBlocking(true);
|
builder.setBlocking(true);
|
||||||
try (final ParcelFileDescriptor tun = builder.establish()) {
|
try (final ParcelFileDescriptor tun = builder.establish()) {
|
||||||
if (tun == null)
|
if (tun == null)
|
||||||
throw new Exception(context.getString(R.string.tun_create_error));
|
throw new BackendException(Reason.TUN_CREATION_ERROR);
|
||||||
Log.d(TAG, "Go backend v" + wgVersion());
|
Log.d(TAG, "Go backend v" + wgVersion());
|
||||||
currentTunnelHandle = wgTurnOn(tunnel.getName(), tun.detachFd(), goConfig);
|
currentTunnelHandle = wgTurnOn(tunnel.getName(), tun.detachFd(), goConfig);
|
||||||
}
|
}
|
||||||
if (currentTunnelHandle < 0)
|
if (currentTunnelHandle < 0)
|
||||||
throw new Exception(context.getString(R.string.tunnel_on_error, currentTunnelHandle));
|
throw new BackendException(Reason.GO_ACTIVATION_ERROR_CODE, currentTunnelHandle);
|
||||||
|
|
||||||
currentTunnel = tunnel;
|
currentTunnel = tunnel;
|
||||||
currentConfig = config;
|
currentConfig = config;
|
||||||
|
@ -5,12 +5,13 @@
|
|||||||
|
|
||||||
package com.wireguard.android.backend;
|
package com.wireguard.android.backend;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.wireguard.android.Application;
|
import com.wireguard.android.Application;
|
||||||
import com.wireguard.android.R;
|
import com.wireguard.android.backend.BackendException.Reason;
|
||||||
import com.wireguard.android.backend.Tunnel.State;
|
import com.wireguard.android.backend.Tunnel.State;
|
||||||
import com.wireguard.config.Config;
|
import com.wireguard.config.Config;
|
||||||
import com.wireguard.crypto.Key;
|
import com.wireguard.crypto.Key;
|
||||||
@ -40,13 +41,11 @@ 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 File localTemporaryDir;
|
private final File localTemporaryDir;
|
||||||
private final Context context;
|
|
||||||
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) {
|
||||||
localTemporaryDir = new File(context.getCacheDir(), "tmp");
|
localTemporaryDir = new File(context.getCacheDir(), "tmp");
|
||||||
this.context = context;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -92,17 +91,12 @@ public final class WgQuickBackend implements Backend {
|
|||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getTypePrettyName() {
|
|
||||||
return context.getString(R.string.type_name_kernel_module);
|
|
||||||
}
|
|
||||||
|
|
||||||
@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 (Application.getRootShell()
|
||||||
.run(output, "cat /sys/module/wireguard/version") != 0 || output.isEmpty())
|
.run(output, "cat /sys/module/wireguard/version") != 0 || output.isEmpty())
|
||||||
throw new Exception(context.getString(R.string.module_version_error));
|
throw new BackendException(Reason.UNKNOWN_KERNEL_MODULE_NAME);
|
||||||
return output.get(0);
|
return output.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +144,7 @@ public final class WgQuickBackend implements Backend {
|
|||||||
// noinspection ResultOfMethodCallIgnored
|
// noinspection ResultOfMethodCallIgnored
|
||||||
tempFile.delete();
|
tempFile.delete();
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
throw new Exception(context.getString(R.string.tunnel_config_error, result));
|
throw new BackendException(Reason.WG_QUICK_CONFIG_ERROR_CODE, result);
|
||||||
|
|
||||||
if (state == State.UP)
|
if (state == State.UP)
|
||||||
runningConfigs.put(tunnel, config);
|
runningConfigs.put(tunnel, config);
|
||||||
|
@ -16,21 +16,32 @@ import android.util.AttributeSet;
|
|||||||
import com.wireguard.android.Application;
|
import com.wireguard.android.Application;
|
||||||
import com.wireguard.android.BuildConfig;
|
import com.wireguard.android.BuildConfig;
|
||||||
import com.wireguard.android.R;
|
import com.wireguard.android.R;
|
||||||
|
import com.wireguard.android.backend.Backend;
|
||||||
|
import com.wireguard.android.backend.GoBackend;
|
||||||
|
import com.wireguard.android.backend.WgQuickBackend;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public class VersionPreference extends Preference {
|
public class VersionPreference extends Preference {
|
||||||
@Nullable private String versionSummary;
|
@Nullable private String versionSummary;
|
||||||
|
|
||||||
|
private String getBackendPrettyName(final Context context, final Backend backend) {
|
||||||
|
if (backend instanceof GoBackend)
|
||||||
|
return context.getString(R.string.type_name_kernel_module);
|
||||||
|
if (backend instanceof WgQuickBackend)
|
||||||
|
return context.getString(R.string.type_name_go_userspace);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
public VersionPreference(final Context context, final AttributeSet attrs) {
|
public VersionPreference(final Context context, final AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
|
|
||||||
Application.getBackendAsync().thenAccept(backend -> {
|
Application.getBackendAsync().thenAccept(backend -> {
|
||||||
versionSummary = getContext().getString(R.string.version_summary_checking, backend.getTypePrettyName().toLowerCase(Locale.ENGLISH));
|
versionSummary = getContext().getString(R.string.version_summary_checking, getBackendPrettyName(context, backend).toLowerCase(Locale.ENGLISH));
|
||||||
Application.getAsyncWorker().supplyAsync(backend::getVersion).whenComplete((version, exception) -> {
|
Application.getAsyncWorker().supplyAsync(backend::getVersion).whenComplete((version, exception) -> {
|
||||||
versionSummary = exception == null
|
versionSummary = exception == null
|
||||||
? getContext().getString(R.string.version_summary, backend.getTypePrettyName(), version)
|
? getContext().getString(R.string.version_summary, getBackendPrettyName(context, backend), version)
|
||||||
: getContext().getString(R.string.version_summary_unknown, backend.getTypePrettyName().toLowerCase(Locale.ENGLISH));
|
: getContext().getString(R.string.version_summary_unknown, getBackendPrettyName(context, backend).toLowerCase(Locale.ENGLISH));
|
||||||
notifyChanged();
|
notifyChanged();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -12,9 +12,9 @@ import androidx.annotation.Nullable;
|
|||||||
|
|
||||||
import com.wireguard.android.Application;
|
import com.wireguard.android.Application;
|
||||||
import com.wireguard.android.R;
|
import com.wireguard.android.R;
|
||||||
|
import com.wireguard.android.backend.BackendException;
|
||||||
import com.wireguard.config.BadConfigException;
|
import com.wireguard.config.BadConfigException;
|
||||||
import com.wireguard.config.BadConfigException.Location;
|
import com.wireguard.config.BadConfigException.Location;
|
||||||
import com.wireguard.config.BadConfigException.Reason;
|
|
||||||
import com.wireguard.config.InetEndpoint;
|
import com.wireguard.config.InetEndpoint;
|
||||||
import com.wireguard.config.InetNetwork;
|
import com.wireguard.config.InetNetwork;
|
||||||
import com.wireguard.config.ParseException;
|
import com.wireguard.config.ParseException;
|
||||||
@ -29,16 +29,25 @@ import java.util.Map;
|
|||||||
import java9.util.Maps;
|
import java9.util.Maps;
|
||||||
|
|
||||||
public final class ErrorMessages {
|
public final class ErrorMessages {
|
||||||
private static final Map<Reason, Integer> BCE_REASON_MAP = new EnumMap<>(Maps.of(
|
private static final Map<BadConfigException.Reason, Integer> BCE_REASON_MAP = new EnumMap<>(Maps.of(
|
||||||
Reason.INVALID_KEY, R.string.bad_config_reason_invalid_key,
|
BadConfigException.Reason.INVALID_KEY, R.string.bad_config_reason_invalid_key,
|
||||||
Reason.INVALID_NUMBER, R.string.bad_config_reason_invalid_number,
|
BadConfigException.Reason.INVALID_NUMBER, R.string.bad_config_reason_invalid_number,
|
||||||
Reason.INVALID_VALUE, R.string.bad_config_reason_invalid_value,
|
BadConfigException.Reason.INVALID_VALUE, R.string.bad_config_reason_invalid_value,
|
||||||
Reason.MISSING_ATTRIBUTE, R.string.bad_config_reason_missing_attribute,
|
BadConfigException.Reason.MISSING_ATTRIBUTE, R.string.bad_config_reason_missing_attribute,
|
||||||
Reason.MISSING_SECTION, R.string.bad_config_reason_missing_section,
|
BadConfigException.Reason.MISSING_SECTION, R.string.bad_config_reason_missing_section,
|
||||||
Reason.MISSING_VALUE, R.string.bad_config_reason_missing_value,
|
BadConfigException.Reason.MISSING_VALUE, R.string.bad_config_reason_missing_value,
|
||||||
Reason.SYNTAX_ERROR, R.string.bad_config_reason_syntax_error,
|
BadConfigException.Reason.SYNTAX_ERROR, R.string.bad_config_reason_syntax_error,
|
||||||
Reason.UNKNOWN_ATTRIBUTE, R.string.bad_config_reason_unknown_attribute,
|
BadConfigException.Reason.UNKNOWN_ATTRIBUTE, R.string.bad_config_reason_unknown_attribute,
|
||||||
Reason.UNKNOWN_SECTION, R.string.bad_config_reason_unknown_section
|
BadConfigException.Reason.UNKNOWN_SECTION, R.string.bad_config_reason_unknown_section
|
||||||
|
));
|
||||||
|
private static final Map<BackendException.Reason, Integer> BE_REASON_MAP = new EnumMap<>(Maps.of(
|
||||||
|
BackendException.Reason.UNKNOWN_KERNEL_MODULE_NAME, R.string.module_version_error,
|
||||||
|
BackendException.Reason.WG_QUICK_CONFIG_ERROR_CODE, R.string.tunnel_config_error,
|
||||||
|
BackendException.Reason.TUNNEL_MISSING_CONFIG, R.string.no_config_error,
|
||||||
|
BackendException.Reason.VPN_NOT_AUTHORIZED, R.string.vpn_not_authorized_error,
|
||||||
|
BackendException.Reason.UNABLE_TO_START_VPN, R.string.vpn_start_error,
|
||||||
|
BackendException.Reason.TUN_CREATION_ERROR, R.string.tun_create_error,
|
||||||
|
BackendException.Reason.GO_ACTIVATION_ERROR_CODE, R.string.tunnel_on_error
|
||||||
));
|
));
|
||||||
private static final Map<Format, Integer> KFE_FORMAT_MAP = new EnumMap<>(Maps.of(
|
private static final Map<Format, Integer> KFE_FORMAT_MAP = new EnumMap<>(Maps.of(
|
||||||
Format.BASE64, R.string.key_length_explanation_base64,
|
Format.BASE64, R.string.key_length_explanation_base64,
|
||||||
@ -77,6 +86,9 @@ public final class ErrorMessages {
|
|||||||
bce.getLocation().getName());
|
bce.getLocation().getName());
|
||||||
final String explanation = getBadConfigExceptionExplanation(resources, bce);
|
final String explanation = getBadConfigExceptionExplanation(resources, bce);
|
||||||
message = resources.getString(R.string.bad_config_error, reason, context) + explanation;
|
message = resources.getString(R.string.bad_config_error, reason, context) + explanation;
|
||||||
|
} else if (rootCause instanceof BackendException) {
|
||||||
|
final BackendException be = (BackendException) rootCause;
|
||||||
|
message = resources.getString(BE_REASON_MAP.get(be.getReason()), be.getFormat());
|
||||||
} else if (rootCause.getMessage() != null) {
|
} else if (rootCause.getMessage() != null) {
|
||||||
message = rootCause.getMessage();
|
message = rootCause.getMessage();
|
||||||
} else {
|
} else {
|
||||||
@ -123,7 +135,7 @@ public final class ErrorMessages {
|
|||||||
private static Throwable rootCause(final Throwable throwable) {
|
private static Throwable rootCause(final Throwable throwable) {
|
||||||
Throwable cause = throwable;
|
Throwable cause = throwable;
|
||||||
while (cause.getCause() != null) {
|
while (cause.getCause() != null) {
|
||||||
if (cause instanceof BadConfigException)
|
if (cause instanceof BadConfigException || cause instanceof BackendException)
|
||||||
break;
|
break;
|
||||||
final Throwable nextCause = cause.getCause();
|
final Throwable nextCause = cause.getCause();
|
||||||
if (nextCause instanceof RemoteException)
|
if (nextCause instanceof RemoteException)
|
||||||
|
Loading…
Reference in New Issue
Block a user