diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java
index 2f7ea5543..89bf2a321 100644
--- a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java
+++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java
@@ -1,10 +1,13 @@
package org.briarproject.bramble.system;
+import org.briarproject.bramble.api.event.EventExecutor;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.api.system.SecureRandomProvider;
+import java.util.concurrent.Executor;
+
import javax.inject.Singleton;
import dagger.Module;
@@ -32,6 +35,13 @@ public class AndroidSystemModule {
return androidExecutor;
}
+ @Provides
+ @Singleton
+ @EventExecutor
+ Executor provideEventExecutor(AndroidExecutor androidExecutor) {
+ return androidExecutor::runOnUiThread;
+ }
+
@Provides
@Singleton
ResourceProvider provideResourceProvider(AndroidResourceProvider provider) {
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/event/EventBus.java b/bramble-api/src/main/java/org/briarproject/bramble/api/event/EventBus.java
index af00f8b1b..d27449833 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/event/EventBus.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/event/EventBus.java
@@ -16,7 +16,8 @@ public interface EventBus {
void removeListener(EventListener l);
/**
- * Notifies all listeners of an event.
+ * Asynchronously notifies all listeners of an event. Listeners are
+ * notified on the {@link EventExecutor}.
*/
void broadcast(Event e);
}
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/event/EventExecutor.java b/bramble-api/src/main/java/org/briarproject/bramble/api/event/EventExecutor.java
new file mode 100644
index 000000000..3e1125f8f
--- /dev/null
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/event/EventExecutor.java
@@ -0,0 +1,25 @@
+package org.briarproject.bramble.api.event;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.inject.Qualifier;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Annotation for injecting the executor for broadcasting events. Also used for
+ * annotating methods that should run on the event executor.
+ *
+ * The contract of this executor is that tasks are run in the order they're
+ * submitted, tasks are not run concurrently, and submitting a task will never
+ * block. Tasks must not block. Tasks submitted during shutdown are discarded.
+ */
+@Qualifier
+@Target({FIELD, METHOD, PARAMETER})
+@Retention(RUNTIME)
+public @interface EventExecutor {
+}
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/event/EventListener.java b/bramble-api/src/main/java/org/briarproject/bramble/api/event/EventListener.java
index 6dd330ead..20989bfc3 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/event/EventListener.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/event/EventListener.java
@@ -12,5 +12,6 @@ public interface EventListener {
* Called when an event is broadcast. Implementations of this method must
* not block.
*/
+ @EventExecutor
void eventOccurred(Event e);
}
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java
index 97e7670c9..17525ed12 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java
@@ -160,13 +160,15 @@ class DatabaseComponentImpl implements DatabaseComponent {
public void endTransaction(Transaction transaction) {
try {
T txn = txnClass.cast(transaction.unbox());
- if (!transaction.isCommitted()) db.abortTransaction(txn);
+ if (transaction.isCommitted()) {
+ for (Event e : transaction.getEvents()) eventBus.broadcast(e);
+ } else {
+ db.abortTransaction(txn);
+ }
} finally {
if (transaction.isReadOnly()) lock.readLock().unlock();
else lock.writeLock().unlock();
}
- if (transaction.isCommitted())
- for (Event e : transaction.getEvents()) eventBus.broadcast(e);
}
@Override
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/event/DefaultEventExecutorModule.java b/bramble-core/src/main/java/org/briarproject/bramble/event/DefaultEventExecutorModule.java
new file mode 100644
index 000000000..5fc21cc86
--- /dev/null
+++ b/bramble-core/src/main/java/org/briarproject/bramble/event/DefaultEventExecutorModule.java
@@ -0,0 +1,32 @@
+package org.briarproject.bramble.event;
+
+import org.briarproject.bramble.api.event.EventExecutor;
+
+import java.util.concurrent.Executor;
+
+import javax.inject.Singleton;
+
+import dagger.Module;
+import dagger.Provides;
+
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+
+/**
+ * Default implementation of {@link EventExecutor} that uses a dedicated thread
+ * to notify listeners of events. Applications may prefer to supply an
+ * implementation that uses an existing thread, such as the UI thread.
+ */
+@Module
+public class DefaultEventExecutorModule {
+
+ @Provides
+ @Singleton
+ @EventExecutor
+ Executor provideEventExecutor() {
+ return newSingleThreadExecutor(r -> {
+ Thread t = new Thread(r);
+ t.setDaemon(true);
+ return t;
+ });
+ }
+}
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/event/EventBusImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/event/EventBusImpl.java
index b08493cd0..150852114 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/event/EventBusImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/event/EventBusImpl.java
@@ -7,6 +7,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Collection;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executor;
import javax.annotation.concurrent.ThreadSafe;
@@ -16,6 +17,11 @@ class EventBusImpl implements EventBus {
private final Collection listeners =
new CopyOnWriteArrayList<>();
+ private final Executor eventExecutor;
+
+ EventBusImpl(Executor eventExecutor) {
+ this.eventExecutor = eventExecutor;
+ }
@Override
public void addListener(EventListener l) {
@@ -29,6 +35,8 @@ class EventBusImpl implements EventBus {
@Override
public void broadcast(Event e) {
- for (EventListener l : listeners) l.eventOccurred(e);
+ eventExecutor.execute(() -> {
+ for (EventListener l : listeners) l.eventOccurred(e);
+ });
}
}
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/event/EventModule.java b/bramble-core/src/main/java/org/briarproject/bramble/event/EventModule.java
index 3cd8bcdef..8aa1fea06 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/event/EventModule.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/event/EventModule.java
@@ -1,6 +1,9 @@
package org.briarproject.bramble.event;
import org.briarproject.bramble.api.event.EventBus;
+import org.briarproject.bramble.api.event.EventExecutor;
+
+import java.util.concurrent.Executor;
import javax.inject.Singleton;
@@ -12,7 +15,7 @@ public class EventModule {
@Provides
@Singleton
- EventBus provideEventBus() {
- return new EventBusImpl();
+ EventBus provideEventBus(@EventExecutor Executor eventExecutor) {
+ return new EventBusImpl(eventExecutor);
}
}
diff --git a/bramble-java/src/test/java/org/briarproject/bramble/test/BrambleJavaIntegrationTestComponent.java b/bramble-java/src/test/java/org/briarproject/bramble/test/BrambleJavaIntegrationTestComponent.java
index 0b775f964..e16e71284 100644
--- a/bramble-java/src/test/java/org/briarproject/bramble/test/BrambleJavaIntegrationTestComponent.java
+++ b/bramble-java/src/test/java/org/briarproject/bramble/test/BrambleJavaIntegrationTestComponent.java
@@ -2,6 +2,7 @@ package org.briarproject.bramble.test;
import org.briarproject.bramble.BrambleJavaModule;
import org.briarproject.bramble.battery.DefaultBatteryManagerModule;
+import org.briarproject.bramble.event.DefaultEventExecutorModule;
import org.briarproject.bramble.event.EventModule;
import org.briarproject.bramble.plugin.PluginModule;
import org.briarproject.bramble.plugin.tor.BridgeTest;
@@ -17,8 +18,9 @@ import dagger.Component;
BrambleJavaModule.class,
TestLifecycleModule.class,
DefaultBatteryManagerModule.class,
- PluginModule.class, // needed for BackoffFactory
+ DefaultEventExecutorModule.class,
EventModule.class,
+ PluginModule.class, // needed for BackoffFactory
SystemModule.class,
})
public interface BrambleJavaIntegrationTestComponent {
diff --git a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTestComponent.java
index 11667b6d1..aefdf9360 100644
--- a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTestComponent.java
+++ b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTestComponent.java
@@ -8,6 +8,7 @@ import org.briarproject.bramble.crypto.CryptoExecutorModule;
import org.briarproject.bramble.crypto.CryptoModule;
import org.briarproject.bramble.data.DataModule;
import org.briarproject.bramble.db.DatabaseModule;
+import org.briarproject.bramble.event.DefaultEventExecutorModule;
import org.briarproject.bramble.event.EventModule;
import org.briarproject.bramble.identity.IdentityModule;
import org.briarproject.bramble.lifecycle.LifecycleModule;
@@ -46,6 +47,7 @@ import dagger.Component;
FeedModule.class,
DataModule.class,
DatabaseModule.class,
+ DefaultEventExecutorModule.class,
EventModule.class,
IdentityModule.class,
LifecycleModule.class,
diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java
index 1ef0a9210..815da25ea 100644
--- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java
+++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java
@@ -6,6 +6,7 @@ import org.briarproject.bramble.crypto.CryptoExecutorModule;
import org.briarproject.bramble.crypto.CryptoModule;
import org.briarproject.bramble.data.DataModule;
import org.briarproject.bramble.db.DatabaseModule;
+import org.briarproject.bramble.event.DefaultEventExecutorModule;
import org.briarproject.bramble.event.EventModule;
import org.briarproject.bramble.identity.IdentityModule;
import org.briarproject.bramble.lifecycle.LifecycleModule;
@@ -45,6 +46,7 @@ import dagger.Component;
CryptoExecutorModule.class,
DataModule.class,
DatabaseModule.class,
+ DefaultEventExecutorModule.class,
EventModule.class,
ForumModule.class,
GroupInvitationModule.class,
diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTestComponent.java
index f56035fb6..833aed5e2 100644
--- a/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTestComponent.java
+++ b/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTestComponent.java
@@ -6,6 +6,7 @@ import org.briarproject.bramble.crypto.CryptoExecutorModule;
import org.briarproject.bramble.crypto.CryptoModule;
import org.briarproject.bramble.data.DataModule;
import org.briarproject.bramble.db.DatabaseModule;
+import org.briarproject.bramble.event.DefaultEventExecutorModule;
import org.briarproject.bramble.event.EventModule;
import org.briarproject.bramble.identity.IdentityModule;
import org.briarproject.bramble.sync.SyncModule;
@@ -37,6 +38,7 @@ import dagger.Component;
CryptoExecutorModule.class,
DataModule.class,
DatabaseModule.class,
+ DefaultEventExecutorModule.class,
EventModule.class,
ForumModule.class,
IdentityModule.class,
diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java
index 6835add8c..efba3db0b 100644
--- a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java
+++ b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java
@@ -13,6 +13,7 @@ import org.briarproject.bramble.contact.ContactModule;
import org.briarproject.bramble.crypto.CryptoModule;
import org.briarproject.bramble.data.DataModule;
import org.briarproject.bramble.db.DatabaseModule;
+import org.briarproject.bramble.event.DefaultEventExecutorModule;
import org.briarproject.bramble.event.EventModule;
import org.briarproject.bramble.identity.IdentityModule;
import org.briarproject.bramble.lifecycle.LifecycleModule;
@@ -46,6 +47,7 @@ import dagger.Component;
CryptoModule.class,
DataModule.class,
DatabaseModule.class,
+ DefaultEventExecutorModule.class,
EventModule.class,
IdentityModule.class,
LifecycleModule.class,
diff --git a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java
index 11ef2fe81..f0c0e69ff 100644
--- a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java
+++ b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java
@@ -15,6 +15,7 @@ import org.briarproject.bramble.crypto.CryptoExecutorModule;
import org.briarproject.bramble.crypto.CryptoModule;
import org.briarproject.bramble.data.DataModule;
import org.briarproject.bramble.db.DatabaseModule;
+import org.briarproject.bramble.event.DefaultEventExecutorModule;
import org.briarproject.bramble.event.EventModule;
import org.briarproject.bramble.identity.IdentityModule;
import org.briarproject.bramble.lifecycle.LifecycleModule;
@@ -63,6 +64,7 @@ import dagger.Component;
CryptoExecutorModule.class,
DataModule.class,
DatabaseModule.class,
+ DefaultEventExecutorModule.class,
EventModule.class,
ForumModule.class,
GroupInvitationModule.class,
diff --git a/briar-headless/src/main/java/org/briarproject/briar/headless/HeadlessModule.kt b/briar-headless/src/main/java/org/briarproject/briar/headless/HeadlessModule.kt
index a5d567547..53ce493d3 100644
--- a/briar-headless/src/main/java/org/briarproject/briar/headless/HeadlessModule.kt
+++ b/briar-headless/src/main/java/org/briarproject/briar/headless/HeadlessModule.kt
@@ -21,6 +21,7 @@ import org.briarproject.bramble.api.system.Clock
import org.briarproject.bramble.api.system.LocationUtils
import org.briarproject.bramble.api.system.ResourceProvider
import org.briarproject.bramble.battery.DefaultBatteryManagerModule
+import org.briarproject.bramble.event.DefaultEventExecutorModule
import org.briarproject.bramble.network.JavaNetworkModule
import org.briarproject.bramble.plugin.tor.CircumventionModule
import org.briarproject.bramble.plugin.tor.CircumventionProvider
@@ -47,6 +48,7 @@ import javax.net.SocketFactory
JavaSystemModule::class,
CircumventionModule::class,
DefaultBatteryManagerModule::class,
+ DefaultEventExecutorModule::class,
HeadlessBlogModule::class,
HeadlessContactModule::class,
HeadlessEventModule::class,