Allow Plugin.start() to fail gracefully; removed unnecessary locking.

This commit is contained in:
akwizgran
2012-11-24 10:50:20 +00:00
parent 66c155e41c
commit d90b4f4bc5
8 changed files with 71 additions and 142 deletions

View File

@@ -14,8 +14,8 @@ public interface Plugin {
/** Returns a label for looking up the plugin's translated name. */
String getName();
/** Starts the plugin. */
void start() throws IOException;
/** Starts the plugin and returns true if it started successfully. */
boolean start() throws IOException;
/** Stops the plugin. */
void stop() throws IOException;

View File

@@ -53,8 +53,8 @@ class BluetoothPlugin implements DuplexPlugin {
private final Object discoveryLock = new Object();
private final ScheduledExecutorService scheduler;
private boolean running = false; // Locking: this
private StreamConnectionNotifier socket = null; // Locking: this
private volatile boolean running = false;
private volatile StreamConnectionNotifier socket = null;
// Non-null if running has ever been true
private volatile LocalDevice localDevice = null;
@@ -76,7 +76,7 @@ class BluetoothPlugin implements DuplexPlugin {
return "BLUETOOTH_PLUGIN_NAME";
}
public void start() throws IOException {
public boolean start() throws IOException {
// Initialise the Bluetooth stack
try {
localDevice = LocalDevice.getLocalDevice();
@@ -84,24 +84,21 @@ class BluetoothPlugin implements DuplexPlugin {
// On Linux the user may need to install libbluetooth-dev
if(OsUtils.isLinux())
callback.showMessage("BLUETOOTH_INSTALL_LIBS");
throw new IOException(e.toString());
return false;
}
if(LOG.isLoggable(INFO))
LOG.info("Local address " + localDevice.getBluetoothAddress());
synchronized(this) {
running = true;
}
running = true;
pluginExecutor.execute(new Runnable() {
public void run() {
bind();
}
});
return true;
}
private void bind() {
synchronized(this) {
if(!running) return;
}
if(!running) return;
// Advertise the Bluetooth address to contacts
TransportProperties p = new TransportProperties();
p.put("address", localDevice.getBluetoothAddress());
@@ -114,13 +111,11 @@ class BluetoothPlugin implements DuplexPlugin {
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
return;
}
synchronized(this) {
if(!running) {
tryToClose(scn);
return;
}
socket = scn;
if(!running) {
tryToClose(scn);
return;
}
socket = scn;
acceptContactConnections(scn);
}
@@ -155,20 +150,13 @@ class BluetoothPlugin implements DuplexPlugin {
BluetoothTransportConnection conn =
new BluetoothTransportConnection(s);
callback.incomingConnectionCreated(conn);
synchronized(this) {
if(!running) return;
}
if(!running) return;
}
}
public void stop() {
synchronized(this) {
running = false;
if(socket != null) {
tryToClose(socket);
socket = null;
}
}
running = false;
if(socket != null) tryToClose(socket);
scheduler.shutdownNow();
}
@@ -181,9 +169,7 @@ class BluetoothPlugin implements DuplexPlugin {
}
public void poll(final Collection<ContactId> connected) {
synchronized(this) {
if(!running) return;
}
if(!running) return;
// Try to connect to known devices in parallel
Map<ContactId, TransportProperties> remote =
callback.getRemoteProperties();
@@ -195,9 +181,7 @@ class BluetoothPlugin implements DuplexPlugin {
if(address != null && uuid != null) {
pluginExecutor.execute(new Runnable() {
public void run() {
synchronized(BluetoothPlugin.this) {
if(!running) return;
}
if(!running) return;
String url = makeUrl(address, uuid);
DuplexTransportConnection conn = connect(url);
if(conn != null)
@@ -219,9 +203,7 @@ class BluetoothPlugin implements DuplexPlugin {
}
public DuplexTransportConnection createConnection(ContactId c) {
synchronized(this) {
if(!running) return null;
}
if(!running) return null;
TransportProperties p = callback.getRemoteProperties().get(c);
if(p == null) return null;
String address = p.get("address");
@@ -237,9 +219,7 @@ class BluetoothPlugin implements DuplexPlugin {
public DuplexTransportConnection sendInvitation(PseudoRandom r,
long timeout) {
synchronized(this) {
if(!running) return null;
}
if(!running) return null;
// Use the same pseudo-random UUID as the contact
String uuid = generateUuid(r.nextBytes(16));
// Discover nearby devices and connect to any with the right UUID
@@ -265,9 +245,7 @@ class BluetoothPlugin implements DuplexPlugin {
return null;
}
}
synchronized(this) {
if(!running) return null;
}
if(!running) return null;
}
if(url == null) return null;
return connect(url);
@@ -280,9 +258,7 @@ class BluetoothPlugin implements DuplexPlugin {
public DuplexTransportConnection acceptInvitation(PseudoRandom r,
long timeout) {
synchronized(this) {
if(!running) return null;
}
if(!running) return null;
// Use the same pseudo-random UUID as the contact
String uuid = generateUuid(r.nextBytes(16));
String url = makeUrl("localhost", uuid);
@@ -296,11 +272,9 @@ class BluetoothPlugin implements DuplexPlugin {
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
return null;
}
synchronized(this) {
if(!running) {
tryToClose(scn);
return null;
}
if(!running) {
tryToClose(scn);
return null;
}
// Close the socket when the invitation times out
Runnable close = new Runnable() {
@@ -324,9 +298,7 @@ class BluetoothPlugin implements DuplexPlugin {
private void makeDeviceDiscoverable() {
// Try to make the device discoverable (requires root on Linux)
synchronized(this) {
if(!running) return;
}
if(!running) return;
try {
localDevice.setDiscoverable(GIAC);
} catch(BluetoothStateException e) {

View File

@@ -61,8 +61,8 @@ class DroidtoothPlugin implements DuplexPlugin {
private final DuplexPluginCallback callback;
private final long pollingInterval;
private boolean running = false; // Locking: this
private BluetoothServerSocket socket = null; // Locking: this
private volatile boolean running = false;
private volatile BluetoothServerSocket socket = null;
// Non-null if running has ever been true
private volatile BluetoothAdapter adapter = null;
@@ -86,7 +86,7 @@ class DroidtoothPlugin implements DuplexPlugin {
return "BLUETOOTH_PLUGIN_NAME";
}
public void start() throws IOException {
public boolean start() throws IOException {
// BluetoothAdapter.getDefaultAdapter() must be called on a thread
// with a message queue, so submit it to the AndroidExecutor
try {
@@ -100,21 +100,18 @@ class DroidtoothPlugin implements DuplexPlugin {
} catch(ExecutionException e) {
throw new IOException(e.toString());
}
if(adapter == null) throw new IOException(); // Bluetooth not supported
synchronized(this) {
running = true;
}
if(adapter == null) return false; // Bluetooth not supported
running = true;
pluginExecutor.execute(new Runnable() {
public void run() {
bind();
}
});
return true;
}
private void bind() {
synchronized(this) {
if(!running) return;
}
if(!running) return;
if(!enableBluetooth()) {
if(LOG.isLoggable(INFO)) LOG.info("Could not enable Bluetooth");
return;
@@ -133,20 +130,16 @@ class DroidtoothPlugin implements DuplexPlugin {
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
return;
}
synchronized(this) {
if(!running) {
tryToClose(ss);
return;
}
socket = ss;
if(!running) {
tryToClose(ss);
return;
}
socket = ss;
acceptContactConnections(ss);
}
private boolean enableBluetooth() {
synchronized(this) {
if(!running) return false;
}
if(!running) return false;
if(adapter.isEnabled()) return true;
// Try to enable the adapter and wait for the result
IntentFilter filter = new IntentFilter(ACTION_STATE_CHANGED);
@@ -190,20 +183,13 @@ class DroidtoothPlugin implements DuplexPlugin {
DroidtoothTransportConnection conn =
new DroidtoothTransportConnection(s);
callback.incomingConnectionCreated(conn);
synchronized(this) {
if(!running) return;
}
if(!running) return;
}
}
public void stop() throws IOException {
synchronized(this) {
running = false;
if(socket != null) {
tryToClose(socket);
socket = null;
}
}
running = false;
if(socket != null) tryToClose(socket);
}
public boolean shouldPoll() {
@@ -215,9 +201,7 @@ class DroidtoothPlugin implements DuplexPlugin {
}
public void poll(Collection<ContactId> connected) {
synchronized(this) {
if(!running) return;
}
if(!running) return;
// Try to connect to known devices in parallel
Map<ContactId, TransportProperties> remote =
callback.getRemoteProperties();
@@ -229,9 +213,7 @@ class DroidtoothPlugin implements DuplexPlugin {
if(address != null && uuid != null) {
pluginExecutor.execute(new Runnable() {
public void run() {
synchronized(DroidtoothPlugin.this) {
if(!running) return;
}
if(!running) return;
DuplexTransportConnection conn = connect(address, uuid);
if(conn != null)
callback.outgoingConnectionCreated(c, conn);
@@ -269,9 +251,7 @@ class DroidtoothPlugin implements DuplexPlugin {
}
public DuplexTransportConnection createConnection(ContactId c) {
synchronized(this) {
if(!running) return null;
}
if(!running) return null;
TransportProperties p = callback.getRemoteProperties().get(c);
if(p == null) return null;
String address = p.get("address");
@@ -286,9 +266,7 @@ class DroidtoothPlugin implements DuplexPlugin {
public DuplexTransportConnection sendInvitation(PseudoRandom r,
long timeout) {
synchronized(this) {
if(!running) return null;
}
if(!running) return null;
// Use the same pseudo-random UUID as the contact
String uuid = UUID.nameUUIDFromBytes(r.nextBytes(16)).toString();
// Register to receive Bluetooth discovery intents
@@ -311,9 +289,7 @@ class DroidtoothPlugin implements DuplexPlugin {
public DuplexTransportConnection acceptInvitation(PseudoRandom r,
long timeout) {
synchronized(this) {
if(!running) return null;
}
if(!running) return null;
// Use the same pseudo-random UUID as the contact
UUID uuid = UUID.nameUUIDFromBytes(r.nextBytes(16));
// Bind a new server socket to accept the invitation connection
@@ -394,9 +370,7 @@ class DroidtoothPlugin implements DuplexPlugin {
for(final String address : addresses) {
pluginExecutor.execute(new Runnable() {
public void run() {
synchronized(DroidtoothPlugin.this) {
if(!running) return;
}
if(!running) return;
DuplexTransportConnection conn = connect(address, uuid);
if(conn != null) {
connection = conn;

View File

@@ -47,9 +47,10 @@ implements RemovableDriveMonitor.Callback {
return "REMOVABLE_DRIVE_PLUGIN_NAME";
}
public void start() throws IOException {
public boolean start() throws IOException {
running = true;
monitor.start(this);
return true;
}
public void stop() throws IOException {

View File

@@ -43,8 +43,9 @@ class ModemPlugin implements DuplexPlugin {
return "MODEM_PLUGIN_NAME";
}
public void start() throws IOException {
public boolean start() throws IOException {
// FIXME
return false;
}
public void stop() throws IOException {

View File

@@ -110,9 +110,7 @@ class LanTcpPlugin extends TcpPlugin {
public DuplexTransportConnection sendInvitation(PseudoRandom r,
long timeout) {
synchronized(this) {
if(!running) return null;
}
if(!running) return null;
// Use the invitation code to choose the group address and port
InetSocketAddress mcast = chooseMulticastGroup(r);
// Bind a multicast socket for receiving packets
@@ -157,9 +155,7 @@ class LanTcpPlugin extends TcpPlugin {
break;
}
now = System.currentTimeMillis();
synchronized(this) {
if(!running) return null;
}
if(!running) return null;
}
if(LOG.isLoggable(INFO))
LOG.info("Timeout while sending invitation");
@@ -242,9 +238,7 @@ class LanTcpPlugin extends TcpPlugin {
public DuplexTransportConnection acceptInvitation(PseudoRandom r,
long timeout) {
synchronized(this) {
if(!running) return null;
}
if(!running) return null;
// Use the invitation code to choose the group address and port
InetSocketAddress mcast = chooseMulticastGroup(r);
// Bind a TCP socket for receiving connections
@@ -299,9 +293,7 @@ class LanTcpPlugin extends TcpPlugin {
interval += 1000;
}
}
synchronized(this) {
if(!running) return null;
}
if(!running) return null;
}
if(LOG.isLoggable(INFO))
LOG.info("Timeout while accepting invitation");

View File

@@ -32,8 +32,8 @@ abstract class TcpPlugin implements DuplexPlugin {
protected final DuplexPluginCallback callback;
protected final long pollingInterval;
protected boolean running = false; // Locking: this
private ServerSocket socket = null; // Locking: this
protected volatile boolean running = false;
private volatile ServerSocket socket = null;
/**
* Returns zero or more socket addresses on which the plugin should listen,
@@ -48,15 +48,14 @@ abstract class TcpPlugin implements DuplexPlugin {
this.pollingInterval = pollingInterval;
}
public void start() throws IOException {
synchronized(this) {
running = true;
}
public boolean start() throws IOException {
running = true;
pluginExecutor.execute(new Runnable() {
public void run() {
bind();
}
});
return true;
}
private void bind() {
@@ -83,13 +82,11 @@ abstract class TcpPlugin implements DuplexPlugin {
if(LOG.isLoggable(INFO)) LOG.info("Could not bind server socket");
return;
}
synchronized(this) {
if(!running) {
tryToClose(ss);
return;
}
socket = ss;
if(!running) {
tryToClose(ss);
return;
}
socket = ss;
if(LOG.isLoggable(INFO)) {
String addr = ss.getInetAddress().getHostAddress();
int port = ss.getLocalPort();
@@ -129,18 +126,13 @@ abstract class TcpPlugin implements DuplexPlugin {
}
TcpTransportConnection conn = new TcpTransportConnection(s);
callback.incomingConnectionCreated(conn);
synchronized(this) {
if(!running) return;
}
if(!running) return;
}
}
public synchronized void stop() throws IOException {
public void stop() throws IOException {
running = false;
if(socket != null) {
tryToClose(socket);
socket = null;
}
if(socket != null) tryToClose(socket);
}
public boolean shouldPoll() {
@@ -152,9 +144,7 @@ abstract class TcpPlugin implements DuplexPlugin {
}
public void poll(Collection<ContactId> connected) {
synchronized(this) {
if(!running) return;
}
if(!running) return;
Map<ContactId, TransportProperties> remote =
callback.getRemoteProperties();
for(final ContactId c : remote.keySet()) {
@@ -173,9 +163,7 @@ abstract class TcpPlugin implements DuplexPlugin {
}
public DuplexTransportConnection createConnection(ContactId c) {
synchronized(this) {
if(!running) return null;
}
if(!running) return null;
SocketAddress addr = getRemoteSocketAddress(c);
Socket s = new Socket();
if(addr == null || s == null) return null;

View File

@@ -66,7 +66,7 @@ class TorPlugin implements DuplexPlugin {
return "TOR_PLUGIN_NAME";
}
public void start() throws IOException {
public boolean start() throws IOException {
synchronized(this) {
running = true;
}
@@ -75,6 +75,7 @@ class TorPlugin implements DuplexPlugin {
bind();
}
});
return true;
}
private void bind() {