Catch SecurityExceptions from all ConnectivityManager calls.

This issue occurs on Android 11 and no fix is expected. When the issue occurs, Tor connectivity and outgoing LAN connectivity will be broken until the app is restarted.
This commit is contained in:
akwizgran
2022-04-19 11:03:08 +01:00
parent 174ca3cfb8
commit e7fc37d81e
3 changed files with 101 additions and 71 deletions

View File

@@ -111,15 +111,21 @@ class AndroidNetworkManager implements NetworkManager, Service {
@Override @Override
public NetworkStatus getNetworkStatus() { public NetworkStatus getNetworkStatus() {
NetworkInfo net = connectivityManager.getActiveNetworkInfo(); // https://issuetracker.google.com/issues/175055271
boolean connected = net != null && net.isConnected(); try {
boolean wifi = false, ipv6Only = false; NetworkInfo net = connectivityManager.getActiveNetworkInfo();
if (connected) { boolean connected = net != null && net.isConnected();
wifi = net.getType() == TYPE_WIFI; boolean wifi = false, ipv6Only = false;
if (SDK_INT >= 23) ipv6Only = isActiveNetworkIpv6Only(); if (connected) {
else ipv6Only = areAllAvailableNetworksIpv6Only(); wifi = net.getType() == TYPE_WIFI;
if (SDK_INT >= 23) ipv6Only = isActiveNetworkIpv6Only();
else ipv6Only = areAllAvailableNetworksIpv6Only();
}
return new NetworkStatus(connected, wifi, ipv6Only);
} catch (SecurityException e) {
logException(LOG, WARNING, e);
return new NetworkStatus(false, false, false);
} }
return new NetworkStatus(connected, wifi, ipv6Only);
} }
/** /**
@@ -130,23 +136,29 @@ class AndroidNetworkManager implements NetworkManager, Service {
*/ */
@TargetApi(23) @TargetApi(23)
private boolean isActiveNetworkIpv6Only() { private boolean isActiveNetworkIpv6Only() {
Network net = connectivityManager.getActiveNetwork(); // https://issuetracker.google.com/issues/175055271
if (net == null) { try {
LOG.info("No active network"); Network net = connectivityManager.getActiveNetwork();
if (net == null) {
LOG.info("No active network");
return false;
}
LinkProperties props = connectivityManager.getLinkProperties(net);
if (props == null) {
LOG.info("No link properties for active network");
return false;
}
boolean hasIpv6Unicast = false;
for (LinkAddress linkAddress : props.getLinkAddresses()) {
InetAddress addr = linkAddress.getAddress();
if (addr instanceof Inet4Address) return false;
if (!addr.isMulticastAddress()) hasIpv6Unicast = true;
}
return hasIpv6Unicast;
} catch (SecurityException e) {
logException(LOG, WARNING, e);
return false; return false;
} }
LinkProperties props = connectivityManager.getLinkProperties(net);
if (props == null) {
LOG.info("No link properties for active network");
return false;
}
boolean hasIpv6Unicast = false;
for (LinkAddress linkAddress : props.getLinkAddresses()) {
InetAddress addr = linkAddress.getAddress();
if (addr instanceof Inet4Address) return false;
if (!addr.isMulticastAddress()) hasIpv6Unicast = true;
}
return hasIpv6Unicast;
} }
/** /**

View File

@@ -175,16 +175,24 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
@TargetApi(21) @TargetApi(21)
@Nullable @Nullable
private InetAddress getWifiClientIpv6Address() { private InetAddress getWifiClientIpv6Address() {
for (Network net : connectivityManager.getAllNetworks()) { // https://issuetracker.google.com/issues/175055271
NetworkCapabilities caps = try {
connectivityManager.getNetworkCapabilities(net); for (Network net : connectivityManager.getAllNetworks()) {
if (caps == null || !caps.hasTransport(TRANSPORT_WIFI)) continue; NetworkCapabilities caps =
LinkProperties props = connectivityManager.getLinkProperties(net); connectivityManager.getNetworkCapabilities(net);
if (props == null) continue; if (caps == null || !caps.hasTransport(TRANSPORT_WIFI)) {
for (LinkAddress linkAddress : props.getLinkAddresses()) { continue;
InetAddress addr = linkAddress.getAddress(); }
if (isIpv6LinkLocalAddress(addr)) return addr; LinkProperties props =
connectivityManager.getLinkProperties(net);
if (props == null) continue;
for (LinkAddress linkAddress : props.getLinkAddresses()) {
InetAddress addr = linkAddress.getAddress();
if (isIpv6LinkLocalAddress(addr)) return addr;
}
} }
} catch (SecurityException e) {
logException(LOG, WARNING, e);
} }
return null; return null;
} }
@@ -227,12 +235,17 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
// network's socket factory may try to connect via another network // network's socket factory may try to connect via another network
private SocketFactory getSocketFactory() { private SocketFactory getSocketFactory() {
if (SDK_INT < 21) return SocketFactory.getDefault(); if (SDK_INT < 21) return SocketFactory.getDefault();
for (Network net : connectivityManager.getAllNetworks()) { // https://issuetracker.google.com/issues/175055271
NetworkCapabilities caps = try {
connectivityManager.getNetworkCapabilities(net); for (Network net : connectivityManager.getAllNetworks()) {
if (caps != null && caps.hasTransport(TRANSPORT_WIFI)) { NetworkCapabilities caps =
return net.getSocketFactory(); connectivityManager.getNetworkCapabilities(net);
if (caps != null && caps.hasTransport(TRANSPORT_WIFI)) {
return net.getSocketFactory();
}
} }
} catch (SecurityException e) {
logException(LOG, WARNING, e);
} }
LOG.warning("Could not find suitable socket factory"); LOG.warning("Could not find suitable socket factory");
return SocketFactory.getDefault(); return SocketFactory.getDefault();

View File

@@ -198,38 +198,47 @@ class BriarReportCollector {
private ReportItem getConnectivity() { private ReportItem getConnectivity() {
MultiReportInfo connectivityInfo = new MultiReportInfo(); MultiReportInfo connectivityInfo = new MultiReportInfo();
// Is mobile data available? // https://issuetracker.google.com/issues/175055271
ConnectivityManager cm = requireNonNull(
getSystemService(ctx, ConnectivityManager.class));
NetworkInfo mobile = cm.getNetworkInfo(TYPE_MOBILE);
boolean mobileAvailable = mobile != null && mobile.isAvailable();
connectivityInfo.add("MobileDataAvailable", mobileAvailable);
// Is mobile data enabled?
boolean mobileEnabled = false;
try { try {
Class<?> clazz = Class.forName(cm.getClass().getName()); // Is mobile data available?
Method method = clazz.getDeclaredMethod("getMobileDataEnabled"); ConnectivityManager cm = requireNonNull(
method.setAccessible(true); getSystemService(ctx, ConnectivityManager.class));
mobileEnabled = (Boolean) requireNonNull(method.invoke(cm)); NetworkInfo mobile = cm.getNetworkInfo(TYPE_MOBILE);
} catch (ClassNotFoundException boolean mobileAvailable = mobile != null && mobile.isAvailable();
| NoSuchMethodException connectivityInfo.add("MobileDataAvailable", mobileAvailable);
| IllegalArgumentException
| InvocationTargetException // Is mobile data enabled?
| IllegalAccessException e) { boolean mobileEnabled = false;
connectivityInfo try {
.add("MobileDataReflectionException", e.toString()); Class<?> clazz = Class.forName(cm.getClass().getName());
Method method = clazz.getDeclaredMethod("getMobileDataEnabled");
method.setAccessible(true);
mobileEnabled = (Boolean) requireNonNull(method.invoke(cm));
} catch (ClassNotFoundException
| NoSuchMethodException
| IllegalArgumentException
| InvocationTargetException
| IllegalAccessException e) {
connectivityInfo
.add("MobileDataReflectionException", e.toString());
}
connectivityInfo.add("MobileDataEnabled", mobileEnabled);
// Is mobile data connected ?
boolean mobileConnected = mobile != null && mobile.isConnected();
connectivityInfo.add("MobileDataConnected", mobileConnected);
// Is wifi available?
NetworkInfo wifi = cm.getNetworkInfo(TYPE_WIFI);
boolean wifiAvailable = wifi != null && wifi.isAvailable();
connectivityInfo.add("WifiAvailable", wifiAvailable);
// Is wifi connected?
boolean wifiConnected = wifi != null && wifi.isConnected();
connectivityInfo.add("WifiConnected", wifiConnected);
} catch (SecurityException e) {
connectivityInfo.add("ConnectivityManagerException", e.toString());
} }
connectivityInfo.add("MobileDataEnabled", mobileEnabled);
// Is mobile data connected ?
boolean mobileConnected = mobile != null && mobile.isConnected();
connectivityInfo.add("MobileDataConnected", mobileConnected);
// Is wifi available?
NetworkInfo wifi = cm.getNetworkInfo(TYPE_WIFI);
boolean wifiAvailable = wifi != null && wifi.isAvailable();
connectivityInfo.add("WifiAvailable", wifiAvailable);
// Is wifi enabled? // Is wifi enabled?
WifiManager wm = getSystemService(ctx, WifiManager.class); WifiManager wm = getSystemService(ctx, WifiManager.class);
@@ -237,10 +246,6 @@ class BriarReportCollector {
wm.getWifiState() == WIFI_STATE_ENABLED; wm.getWifiState() == WIFI_STATE_ENABLED;
connectivityInfo.add("WifiEnabled", wifiEnabled); connectivityInfo.add("WifiEnabled", wifiEnabled);
// Is wifi connected?
boolean wifiConnected = wifi != null && wifi.isConnected();
connectivityInfo.add("WifiConnected", wifiConnected);
// Is wifi direct supported? // Is wifi direct supported?
boolean wifiDirect = ctx.getSystemService(WIFI_P2P_SERVICE) != null; boolean wifiDirect = ctx.getSystemService(WIFI_P2P_SERVICE) != null;
connectivityInfo.add("WiFiDirectSupported", wifiDirect); connectivityInfo.add("WiFiDirectSupported", wifiDirect);