Don't make Bluetooth connections when configured not to.

This commit is contained in:
akwizgran
2018-01-10 16:51:06 +00:00
parent f4ddc01641
commit b2e4de91a4
6 changed files with 112 additions and 85 deletions

View File

@@ -9,15 +9,12 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff; import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginException;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.plugin.event.DisableBluetoothEvent;
import org.briarproject.bramble.api.plugin.event.EnableBluetoothEvent;
import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.util.AndroidUtils; import org.briarproject.bramble.util.AndroidUtils;
@@ -44,8 +41,7 @@ import static java.util.logging.Level.WARNING;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
implements EventListener {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(AndroidBluetoothPlugin.class.getName()); Logger.getLogger(AndroidBluetoothPlugin.class.getName());
@@ -68,19 +64,8 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket>
} }
@Override @Override
void initialiseAdapter() throws IOException { public void start() throws PluginException {
// BluetoothAdapter.getDefaultAdapter() must be called on a thread super.start();
// with a message queue, so submit it to the AndroidExecutor
try {
adapter = androidExecutor.runOnBackgroundThread(
BluetoothAdapter::getDefaultAdapter).get();
} catch (InterruptedException | ExecutionException e) {
throw new IOException(e);
}
if (adapter == null) {
LOG.info("Bluetooth is not supported");
throw new IOException();
}
// Listen for changes to the Bluetooth state // Listen for changes to the Bluetooth state
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_STATE_CHANGED); filter.addAction(ACTION_STATE_CHANGED);
@@ -89,9 +74,29 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket>
appContext.registerReceiver(receiver, filter); appContext.registerReceiver(receiver, filter);
} }
@Override
public void stop() {
super.stop();
if (receiver != null) appContext.unregisterReceiver(receiver);
}
@Override
void initialiseAdapter() throws IOException {
// BluetoothAdapter.getDefaultAdapter() must be called on a thread
// with a message queue, so submit it to the AndroidExecutor
try {
adapter = androidExecutor.runOnBackgroundThread(
BluetoothAdapter::getDefaultAdapter).get();
} catch (InterruptedException | ExecutionException e) {
throw new IOException(e);
}
if (adapter == null)
throw new IOException("Bluetooth is not supported");
}
@Override @Override
boolean isAdapterEnabled() { boolean isAdapterEnabled() {
return adapter.isEnabled(); return adapter != null && adapter.isEnabled();
} }
@Override @Override
@@ -107,24 +112,14 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket>
} }
@Override @Override
public void stop() { void disableAdapterIfEnabledByUs() {
super.stop(); if (isAdapterEnabled() && wasEnabledByUs) {
if (receiver != null) appContext.unregisterReceiver(receiver);
disableAdapter();
}
private void disableAdapter() {
if (adapter != null && adapter.isEnabled() && wasEnabledByUs) {
if (adapter.disable()) LOG.info("Disabling Bluetooth"); if (adapter.disable()) LOG.info("Disabling Bluetooth");
else LOG.info("Could not disable Bluetooth"); else LOG.info("Could not disable Bluetooth");
wasEnabledByUs = false;
} }
} }
@Override
public boolean isRunning() {
return super.isRunning() && adapter != null && adapter.isEnabled();
}
@Override @Override
@Nullable @Nullable
String getBluetoothAddress() { String getBluetoothAddress() {
@@ -186,30 +181,18 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket>
} }
} }
@Override
public void eventOccurred(Event e) {
if (e instanceof EnableBluetoothEvent) {
enableAdapterAsync();
} else if (e instanceof DisableBluetoothEvent) {
disableAdapterAsync();
}
}
private void enableAdapterAsync() {
ioExecutor.execute(this::enableAdapter);
}
private void disableAdapterAsync() {
ioExecutor.execute(this::disableAdapter);
}
private class BluetoothStateReceiver extends BroadcastReceiver { private class BluetoothStateReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(Context ctx, Intent intent) { public void onReceive(Context ctx, Intent intent) {
int state = intent.getIntExtra(EXTRA_STATE, 0); int state = intent.getIntExtra(EXTRA_STATE, 0);
if (state == STATE_ON) onAdapterEnabled(); if (state == STATE_ON) {
else if (state == STATE_OFF) onAdapterDisabled(); ioExecutor.execute(
AndroidBluetoothPlugin.this::onAdapterEnabled);
} else if (state == STATE_OFF) {
ioExecutor.execute(
AndroidBluetoothPlugin.this::onAdapterDisabled);
}
int scanMode = intent.getIntExtra(EXTRA_SCAN_MODE, 0); int scanMode = intent.getIntExtra(EXTRA_SCAN_MODE, 0);
if (scanMode == SCAN_MODE_NONE) { if (scanMode == SCAN_MODE_NONE) {
LOG.info("Scan mode: None"); LOG.info("Scan mode: None");

View File

@@ -3,6 +3,8 @@ package org.briarproject.bramble.plugin.bluetooth;
import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection; import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener; import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
@@ -13,7 +15,10 @@ import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin; import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.plugin.event.DisableBluetoothEvent;
import org.briarproject.bramble.api.plugin.event.EnableBluetoothEvent;
import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
import org.briarproject.bramble.util.StringUtils; import org.briarproject.bramble.util.StringUtils;
import java.io.IOException; import java.io.IOException;
@@ -41,7 +46,7 @@ import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
abstract class BluetoothPlugin<SS> implements DuplexPlugin { abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(BluetoothPlugin.class.getName()); Logger.getLogger(BluetoothPlugin.class.getName());
@@ -54,7 +59,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
private final int maxLatency; private final int maxLatency;
private final AtomicBoolean used = new AtomicBoolean(false); private final AtomicBoolean used = new AtomicBoolean(false);
private volatile boolean running = false; private volatile boolean running = false, contactConnections = false;
private volatile SS socket = null; private volatile SS socket = null;
abstract void initialiseAdapter() throws IOException; abstract void initialiseAdapter() throws IOException;
@@ -63,6 +68,8 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
abstract void enableAdapter(); abstract void enableAdapter();
abstract void disableAdapterIfEnabledByUs();
@Nullable @Nullable
abstract String getBluetoothAddress(); abstract String getBluetoothAddress();
@@ -89,7 +96,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
void onAdapterEnabled() { void onAdapterEnabled() {
LOG.info("Bluetooth enabled"); LOG.info("Bluetooth enabled");
bind(); if (shouldAllowContactConnections()) bind();
} }
void onAdapterDisabled() { void onAdapterDisabled() {
@@ -123,22 +130,25 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
throw new PluginException(e); throw new PluginException(e);
} }
running = true; running = true;
// If Bluetooth is enabled, bind a socket loadSettings();
if (isAdapterEnabled()) { if (shouldAllowContactConnections()) {
bind(); if (isAdapterEnabled()) bind();
} else { else enableAdapter();
// Enable Bluetooth if settings allow
if (callback.getSettings().getBoolean(PREF_BT_ENABLE, false)) {
enableAdapter();
} else {
LOG.info("Not enabling Bluetooth");
}
} }
} }
private void loadSettings() {
contactConnections =
callback.getSettings().getBoolean(PREF_BT_ENABLE, false);
}
private boolean shouldAllowContactConnections() {
return contactConnections;
}
private void bind() { private void bind() {
ioExecutor.execute(() -> { ioExecutor.execute(() -> {
if (!isRunning()) return; if (!isRunning() || !shouldAllowContactConnections()) return;
String address = getBluetoothAddress(); String address = getBluetoothAddress();
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Local address " + scrubMacAddress(address)); LOG.info("Local address " + scrubMacAddress(address));
@@ -156,7 +166,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return; return;
} }
if (!isRunning()) { if (!isRunning() || !shouldAllowContactConnections()) {
tryToClose(ss); tryToClose(ss);
return; return;
} }
@@ -201,11 +211,12 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
running = false; running = false;
tryToClose(socket); tryToClose(socket);
callback.transportDisabled(); callback.transportDisabled();
disableAdapterIfEnabledByUs();
} }
@Override @Override
public boolean isRunning() { public boolean isRunning() {
return running; return running && isAdapterEnabled();
} }
@Override @Override
@@ -220,7 +231,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
@Override @Override
public void poll(Collection<ContactId> connected) { public void poll(Collection<ContactId> connected) {
if (!isRunning()) return; if (!isRunning() || !shouldAllowContactConnections()) return;
backoff.increment(); backoff.increment();
// Try to connect to known devices in parallel // Try to connect to known devices in parallel
Map<ContactId, TransportProperties> remote = Map<ContactId, TransportProperties> remote =
@@ -233,7 +244,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
String uuid = e.getValue().get(PROP_UUID); String uuid = e.getValue().get(PROP_UUID);
if (StringUtils.isNullOrEmpty(uuid)) continue; if (StringUtils.isNullOrEmpty(uuid)) continue;
ioExecutor.execute(() -> { ioExecutor.execute(() -> {
if (!isRunning()) return; if (!isRunning() || !shouldAllowContactConnections()) return;
DuplexTransportConnection conn = connect(address, uuid); DuplexTransportConnection conn = connect(address, uuid);
if (conn != null) { if (conn != null) {
backoff.reset(); backoff.reset();
@@ -276,7 +287,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
@Override @Override
public DuplexTransportConnection createConnection(ContactId c) { public DuplexTransportConnection createConnection(ContactId c) {
if (!isRunning()) return null; if (!isRunning() || !shouldAllowContactConnections()) return null;
TransportProperties p = callback.getRemoteProperties(c); TransportProperties p = callback.getRemoteProperties(c);
String address = p.get(PROP_ADDRESS); String address = p.get(PROP_ADDRESS);
if (StringUtils.isNullOrEmpty(address)) return null; if (StringUtils.isNullOrEmpty(address)) return null;
@@ -341,6 +352,35 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
return StringUtils.macToString(mac); return StringUtils.macToString(mac);
} }
@Override
public void eventOccurred(Event e) {
if (e instanceof EnableBluetoothEvent) {
ioExecutor.execute(this::enableAdapter);
} else if (e instanceof DisableBluetoothEvent) {
ioExecutor.execute(this::disableAdapterIfEnabledByUs);
} else if (e instanceof SettingsUpdatedEvent) {
SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
if (s.getNamespace().equals(ID.getString()))
ioExecutor.execute(this::onSettingsUpdated);
}
}
private void onSettingsUpdated() {
boolean wasAllowed = shouldAllowContactConnections();
loadSettings();
boolean isAllowed = shouldAllowContactConnections();
if (wasAllowed && !isAllowed) {
LOG.info("Contact connections disabled");
tryToClose(socket);
callback.transportDisabled();
disableAdapterIfEnabledByUs();
} else if (!wasAllowed && isAllowed) {
LOG.info("Contact connections enabled");
if (isAdapterEnabled()) bind();
else enableAdapter();
}
}
private class BluetoothKeyAgreementListener extends KeyAgreementListener { private class BluetoothKeyAgreementListener extends KeyAgreementListener {
private final SS ss; private final SS ss;

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.plugin; package org.briarproject.bramble.plugin;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.lifecycle.ShutdownManager; import org.briarproject.bramble.api.lifecycle.ShutdownManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -30,9 +31,9 @@ public class DesktopPluginModule extends PluginModule {
PluginConfig getPluginConfig(@IoExecutor Executor ioExecutor, PluginConfig getPluginConfig(@IoExecutor Executor ioExecutor,
SecureRandom random, BackoffFactory backoffFactory, SecureRandom random, BackoffFactory backoffFactory,
ReliabilityLayerFactory reliabilityFactory, ReliabilityLayerFactory reliabilityFactory,
ShutdownManager shutdownManager) { ShutdownManager shutdownManager, EventBus eventBus) {
DuplexPluginFactory bluetooth = DuplexPluginFactory bluetooth =
new JavaBluetoothPluginFactory(ioExecutor, random, new JavaBluetoothPluginFactory(ioExecutor, random, eventBus,
backoffFactory); backoffFactory);
DuplexPluginFactory modem = new ModemPluginFactory(ioExecutor, DuplexPluginFactory modem = new ModemPluginFactory(ioExecutor,
reliabilityFactory); reliabilityFactory);

View File

@@ -47,7 +47,7 @@ class JavaBluetoothPlugin extends BluetoothPlugin<StreamConnectionNotifier> {
@Override @Override
boolean isAdapterEnabled() { boolean isAdapterEnabled() {
return LocalDevice.isPowerOn(); return localDevice != null && LocalDevice.isPowerOn();
} }
@Override @Override
@@ -56,6 +56,11 @@ class JavaBluetoothPlugin extends BluetoothPlugin<StreamConnectionNotifier> {
LOG.info("Could not enable Bluetooth"); LOG.info("Could not enable Bluetooth");
} }
@Override
void disableAdapterIfEnabledByUs() {
// We didn't enable it so we don't need to disable it
}
@Nullable @Nullable
@Override @Override
String getBluetoothAddress() { String getBluetoothAddress() {

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.plugin.bluetooth; package org.briarproject.bramble.plugin.bluetooth;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff; import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory; import org.briarproject.bramble.api.plugin.BackoffFactory;
@@ -27,12 +28,15 @@ public class JavaBluetoothPluginFactory implements DuplexPluginFactory {
private final Executor ioExecutor; private final Executor ioExecutor;
private final SecureRandom secureRandom; private final SecureRandom secureRandom;
private final BackoffFactory backoffFactory; private final BackoffFactory backoffFactory;
private final EventBus eventBus;
public JavaBluetoothPluginFactory(Executor ioExecutor, public JavaBluetoothPluginFactory(Executor ioExecutor,
SecureRandom secureRandom, BackoffFactory backoffFactory) { SecureRandom secureRandom, EventBus eventBus,
BackoffFactory backoffFactory) {
this.ioExecutor = ioExecutor; this.ioExecutor = ioExecutor;
this.secureRandom = secureRandom; this.secureRandom = secureRandom;
this.backoffFactory = backoffFactory; this.backoffFactory = backoffFactory;
this.eventBus = eventBus;
} }
@Override @Override
@@ -49,7 +53,9 @@ public class JavaBluetoothPluginFactory implements DuplexPluginFactory {
public DuplexPlugin createPlugin(DuplexPluginCallback callback) { public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE); MAX_POLLING_INTERVAL, BACKOFF_BASE);
return new JavaBluetoothPlugin(ioExecutor, secureRandom, backoff, JavaBluetoothPlugin plugin = new JavaBluetoothPlugin(ioExecutor,
callback, MAX_LATENCY); secureRandom, backoff, callback, MAX_LATENCY);
eventBus.addListener(plugin);
return plugin;
} }
} }

View File

@@ -22,8 +22,6 @@ import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.BluetoothConstants; import org.briarproject.bramble.api.plugin.BluetoothConstants;
import org.briarproject.bramble.api.plugin.TorConstants; import org.briarproject.bramble.api.plugin.TorConstants;
import org.briarproject.bramble.api.plugin.event.DisableBluetoothEvent;
import org.briarproject.bramble.api.plugin.event.EnableBluetoothEvent;
import org.briarproject.bramble.api.settings.Settings; import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.bramble.api.settings.SettingsManager; import org.briarproject.bramble.api.settings.SettingsManager;
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent; import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
@@ -262,7 +260,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
public boolean onPreferenceChange(Preference preference, Object o) { public boolean onPreferenceChange(Preference preference, Object o) {
if (preference == enableBluetooth) { if (preference == enableBluetooth) {
boolean btSetting = Boolean.valueOf((String) o); boolean btSetting = Boolean.valueOf((String) o);
enableOrDisableBluetooth(btSetting);
storeBluetoothSettings(btSetting); storeBluetoothSettings(btSetting);
} else if (preference == torNetwork) { } else if (preference == torNetwork) {
int torSetting = Integer.valueOf((String) o); int torSetting = Integer.valueOf((String) o);
@@ -295,11 +292,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
return true; return true;
} }
private void enableOrDisableBluetooth(boolean enable) {
if (enable) eventBus.broadcast(new EnableBluetoothEvent());
else eventBus.broadcast(new DisableBluetoothEvent());
}
private void storeTorSettings(int torSetting) { private void storeTorSettings(int torSetting) {
listener.runOnDbThread(() -> { listener.runOnDbThread(() -> {
try { try {