diff --git a/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLockManager.java b/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLockManager.java index 0ebf256a2..bd96ef61b 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLockManager.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLockManager.java @@ -24,4 +24,15 @@ public interface AndroidWakeLockManager { * thrown while submitting or running the task. */ void executeWakefully(Runnable r, Executor executor, String tag); + + /** + * Starts a dedicated thread to run the given task asynchronously. A wake + * lock is acquired before starting the thread and released when the task + * completes, or if an exception is thrown while starting the thread or + * running the task. + *

+ * This method should only be used for lifecycle management tasks that + * can't be run on an executor. + */ + void executeWakefully(Runnable r, String tag); } diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockManagerImpl.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockManagerImpl.java index bf80c5fc0..f976e518d 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockManagerImpl.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockManagerImpl.java @@ -86,6 +86,24 @@ class AndroidWakeLockManagerImpl implements AndroidWakeLockManager { } } + @Override + public void executeWakefully(Runnable r, String tag) { + AndroidWakeLock wakeLock = createWakeLock(tag); + wakeLock.acquire(); + try { + new Thread(() -> { + try { + r.run(); + } finally { + wakeLock.release(); + } + }).start(); + } catch (Exception e) { + wakeLock.release(); + throw e; + } + } + private String getWakeLockTag(Context ctx) { PackageManager pm = ctx.getPackageManager(); for (PackageInfo info : pm.getInstalledPackages(0)) { diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/LifecycleManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/LifecycleManager.java index b5980e4ba..ab14b669f 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/LifecycleManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/LifecycleManager.java @@ -5,6 +5,7 @@ import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.system.Wakeful; import java.util.concurrent.ExecutorService; @@ -65,6 +66,7 @@ public interface LifecycleManager { * Opens the {@link DatabaseComponent} using the given key and starts any * registered {@link Service Services}. */ + @Wakeful StartResult startServices(SecretKey dbKey); /** @@ -72,6 +74,7 @@ public interface LifecycleManager { * registered {@link ExecutorService ExecutorServices}, and closes the * {@link DatabaseComponent}. */ + @Wakeful void stopServices(); /** @@ -104,6 +107,7 @@ public interface LifecycleManager { * * @param txn A read-write transaction */ + @Wakeful void onDatabaseOpened(Transaction txn) throws DbException; } } \ No newline at end of file diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/Service.java b/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/Service.java index fcdcab912..849ebdd17 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/Service.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/Service.java @@ -1,16 +1,20 @@ package org.briarproject.bramble.api.lifecycle; +import org.briarproject.bramble.api.system.Wakeful; + public interface Service { /** - * Starts the service.This method must not be called concurrently with + * Starts the service. This method must not be called concurrently with * {@link #stopService()}. */ + @Wakeful void startService() throws ServiceException; /** * Stops the service. This method must not be called concurrently with * {@link #startService()}. */ + @Wakeful void stopService() throws ServiceException; } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/Plugin.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/Plugin.java index 9d2d50600..1318bcca4 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/Plugin.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/Plugin.java @@ -4,6 +4,7 @@ import org.briarproject.bramble.api.Pair; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.settings.SettingsManager; +import org.briarproject.bramble.api.system.Wakeful; import java.util.Collection; @@ -70,11 +71,13 @@ public interface Plugin { /** * Starts the plugin. */ + @Wakeful void start() throws PluginException; /** * Stops the plugin. */ + @Wakeful void stop() throws PluginException; /** @@ -106,6 +109,7 @@ public interface Plugin { * Attempts to create connections using the given transport properties, * passing any created connections to the corresponding handlers. */ + @Wakeful void poll(Collection> properties); } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/duplex/DuplexPlugin.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/duplex/DuplexPlugin.java index ce0e5787e..9e14e7ab5 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/duplex/DuplexPlugin.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/duplex/DuplexPlugin.java @@ -8,6 +8,7 @@ import org.briarproject.bramble.api.plugin.Plugin; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.rendezvous.KeyMaterialSource; import org.briarproject.bramble.api.rendezvous.RendezvousEndpoint; +import org.briarproject.bramble.api.system.Wakeful; import javax.annotation.Nullable; @@ -21,6 +22,7 @@ public interface DuplexPlugin extends Plugin { * Attempts to create and return a connection using the given transport * properties. Returns null if a connection cannot be created. */ + @Wakeful @Nullable DuplexTransportConnection createConnection(TransportProperties p); diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/simplex/SimplexPlugin.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/simplex/SimplexPlugin.java index 7f0ab0141..9df61968d 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/simplex/SimplexPlugin.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/simplex/SimplexPlugin.java @@ -5,6 +5,7 @@ import org.briarproject.bramble.api.plugin.Plugin; import org.briarproject.bramble.api.plugin.TransportConnectionReader; import org.briarproject.bramble.api.plugin.TransportConnectionWriter; import org.briarproject.bramble.api.properties.TransportProperties; +import org.briarproject.bramble.api.system.Wakeful; import javax.annotation.Nullable; @@ -18,6 +19,7 @@ public interface SimplexPlugin extends Plugin { * Attempts to create and return a reader for the given transport * properties. Returns null if a reader cannot be created. */ + @Wakeful @Nullable TransportConnectionReader createReader(TransportProperties p); @@ -25,6 +27,7 @@ public interface SimplexPlugin extends Plugin { * Attempts to create and return a writer for the given transport * properties. Returns null if a writer cannot be created. */ + @Wakeful @Nullable TransportConnectionWriter createWriter(TransportProperties p); } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/system/TaskScheduler.java b/bramble-api/src/main/java/org/briarproject/bramble/api/system/TaskScheduler.java index 9d72c4cfb..7e1490cfa 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/system/TaskScheduler.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/system/TaskScheduler.java @@ -14,6 +14,9 @@ public interface TaskScheduler { /** * Submits the given task to the given executor after the given delay. + *

+ * If the platform supports wake locks, a wake lock will be held while + * submitting and running the task. */ Future schedule(Runnable task, Executor executor, long delay, TimeUnit unit); @@ -22,6 +25,9 @@ public interface TaskScheduler { * Submits the given task to the given executor after the given delay, * and then repeatedly with the given interval between executions * (measured from the end of one execution to the beginning of the next). + *

+ * If the platform supports wake locks, a wake lock will be held while + * submitting and running the task. */ Future scheduleWithFixedDelay(Runnable task, Executor executor, long delay, long interval, TimeUnit unit); diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/system/Wakeful.java b/bramble-api/src/main/java/org/briarproject/bramble/api/system/Wakeful.java new file mode 100644 index 000000000..e0fa695c3 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/system/Wakeful.java @@ -0,0 +1,19 @@ +package org.briarproject.bramble.api.system; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.inject.Qualifier; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation for methods that must be called while holding a wake lock, if + * the platform supports wake locks. + */ +@Qualifier +@Target(METHOD) +@Retention(RUNTIME) +public @interface Wakeful { +} \ No newline at end of file diff --git a/bramble-core/src/main/java/org/briarproject/bramble/io/TimeoutMonitorImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/io/TimeoutMonitorImpl.java index e4bc71e1d..825ddc9da 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/io/TimeoutMonitorImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/io/TimeoutMonitorImpl.java @@ -4,6 +4,7 @@ import org.briarproject.bramble.api.io.TimeoutMonitor; import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.TaskScheduler; +import org.briarproject.bramble.api.system.Wakeful; import java.io.IOException; import java.io.InputStream; @@ -75,6 +76,7 @@ class TimeoutMonitorImpl implements TimeoutMonitor { } @IoExecutor + @Wakeful private void checkTimeouts() { List snapshot; synchronized (lock) { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java index 3b9479565..856103e18 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java @@ -29,6 +29,7 @@ import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportPropertyManager; import org.briarproject.bramble.api.settings.Settings; import org.briarproject.bramble.api.settings.SettingsManager; +import org.briarproject.bramble.api.system.WakefulIoExecutor; import java.util.ArrayList; import java.util.Collection; @@ -64,7 +65,7 @@ class PluginManagerImpl implements PluginManager, Service { private static final Logger LOG = getLogger(PluginManagerImpl.class.getName()); - private final Executor ioExecutor; + private final Executor ioExecutor, wakefulIoExecutor; private final EventBus eventBus; private final PluginConfig pluginConfig; private final ConnectionManager connectionManager; @@ -77,11 +78,15 @@ class PluginManagerImpl implements PluginManager, Service { private final AtomicBoolean used = new AtomicBoolean(false); @Inject - PluginManagerImpl(@IoExecutor Executor ioExecutor, EventBus eventBus, - PluginConfig pluginConfig, ConnectionManager connectionManager, + PluginManagerImpl(@IoExecutor Executor ioExecutor, + @WakefulIoExecutor Executor wakefulIoExecutor, + EventBus eventBus, + PluginConfig pluginConfig, + ConnectionManager connectionManager, SettingsManager settingsManager, TransportPropertyManager transportPropertyManager) { this.ioExecutor = ioExecutor; + this.wakefulIoExecutor = wakefulIoExecutor; this.eventBus = eventBus; this.pluginConfig = pluginConfig; this.connectionManager = connectionManager; @@ -109,7 +114,7 @@ class PluginManagerImpl implements PluginManager, Service { simplexPlugins.add(s); CountDownLatch startLatch = new CountDownLatch(1); startLatches.put(t, startLatch); - ioExecutor.execute(new PluginStarter(s, startLatch)); + wakefulIoExecutor.execute(new PluginStarter(s, startLatch)); } } // Instantiate the duplex plugins and start them asynchronously @@ -125,7 +130,7 @@ class PluginManagerImpl implements PluginManager, Service { duplexPlugins.add(d); CountDownLatch startLatch = new CountDownLatch(1); startLatches.put(t, startLatch); - ioExecutor.execute(new PluginStarter(d, startLatch)); + wakefulIoExecutor.execute(new PluginStarter(d, startLatch)); } } } @@ -137,12 +142,16 @@ class PluginManagerImpl implements PluginManager, Service { LOG.info("Stopping simplex plugins"); for (SimplexPlugin s : simplexPlugins) { CountDownLatch startLatch = startLatches.get(s.getId()); + // Don't need the wakeful executor here as we wait for the plugin + // to stop before returning ioExecutor.execute(new PluginStopper(s, startLatch, stopLatch)); } // Stop the duplex plugins LOG.info("Stopping duplex plugins"); for (DuplexPlugin d : duplexPlugins) { CountDownLatch startLatch = startLatches.get(d.getId()); + // Don't need the wakeful executor here as we wait for the plugin + // to stop before returning ioExecutor.execute(new PluginStopper(d, startLatch, stopLatch)); } // Wait for all the plugins to stop @@ -205,7 +214,7 @@ class PluginManagerImpl implements PluginManager, Service { } } - private class PluginStarter implements Runnable { + private static class PluginStarter implements Runnable { private final Plugin plugin; private final CountDownLatch startLatch; @@ -235,7 +244,7 @@ class PluginManagerImpl implements PluginManager, Service { } } - private class PluginStopper implements Runnable { + private static class PluginStopper implements Runnable { private final Plugin plugin; private final CountDownLatch startLatch, stopLatch; diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PollerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PollerImpl.java index 439e78efb..e687aa6aa 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PollerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PollerImpl.java @@ -27,6 +27,7 @@ import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportPropertyManager; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.TaskScheduler; +import org.briarproject.bramble.api.system.Wakeful; import org.briarproject.bramble.api.system.WakefulIoExecutor; import java.security.SecureRandom; @@ -57,7 +58,7 @@ class PollerImpl implements Poller, EventListener { private static final Logger LOG = getLogger(PollerImpl.class.getName()); - private final Executor wakefulIoExecutor; + private final Executor ioExecutor, wakefulIoExecutor; private final TaskScheduler scheduler; private final ConnectionManager connectionManager; private final ConnectionRegistry connectionRegistry; @@ -70,7 +71,8 @@ class PollerImpl implements Poller, EventListener { private final Map tasks; @Inject - PollerImpl(@WakefulIoExecutor Executor wakefulIoExecutor, + PollerImpl(@IoExecutor Executor ioExecutor, + @WakefulIoExecutor Executor wakefulIoExecutor, TaskScheduler scheduler, ConnectionManager connectionManager, ConnectionRegistry connectionRegistry, @@ -78,6 +80,7 @@ class PollerImpl implements Poller, EventListener { TransportPropertyManager transportPropertyManager, SecureRandom random, Clock clock) { + this.ioExecutor = ioExecutor; this.wakefulIoExecutor = wakefulIoExecutor; this.scheduler = scheduler; this.connectionManager = connectionManager; @@ -190,8 +193,8 @@ class PollerImpl implements Poller, EventListener { // it will abort safely when it finds it's been replaced if (scheduled != null) scheduled.future.cancel(false); PollTask task = new PollTask(p, due, randomiseNext); - Future future = scheduler.schedule(task, wakefulIoExecutor, - delay, MILLISECONDS); + Future future = scheduler.schedule(task, ioExecutor, delay, + MILLISECONDS); tasks.put(t, new ScheduledPollTask(task, future)); } } finally { @@ -256,6 +259,7 @@ class PollerImpl implements Poller, EventListener { @Override @IoExecutor + @Wakeful public void run() { lock.lock(); try { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/rendezvous/RendezvousPollerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/rendezvous/RendezvousPollerImpl.java index 22f781617..7b0f21e8b 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/rendezvous/RendezvousPollerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/rendezvous/RendezvousPollerImpl.java @@ -42,6 +42,7 @@ import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionOpenedE import org.briarproject.bramble.api.rendezvous.event.RendezvousPollEvent; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.TaskScheduler; +import org.briarproject.bramble.api.system.Wakeful; import java.security.GeneralSecurityException; import java.util.ArrayList; @@ -205,6 +206,7 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener { } // Worker + @Wakeful private void poll() { removeExpiredPendingContacts(); for (PluginState ps : pluginStates.values()) poll(ps); @@ -235,6 +237,7 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener { } // Worker + @Wakeful private void poll(PluginState ps) { if (ps.endpoints.isEmpty()) return; TransportId t = ps.plugin.getId(); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java index f15fd82c7..f55fa7998 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java @@ -13,6 +13,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.TaskScheduler; +import org.briarproject.bramble.api.system.Wakeful; import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.StreamContext; import org.briarproject.bramble.api.transport.TransportKeySet; @@ -203,6 +204,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { } @DatabaseExecutor + @Wakeful private void updateKeys() { try { db.transaction(false, this::updateKeys); @@ -441,6 +443,8 @@ class TransportKeyManagerImpl implements TransportKeyManager { } } + @DatabaseExecutor + @Wakeful private void updateKeys(Transaction txn) throws DbException { long now = clock.currentTimeMillis(); lock.lock(); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/plugin/PluginManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/plugin/PluginManagerImplTest.java index 02e896f27..faca469b1 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/plugin/PluginManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/plugin/PluginManagerImplTest.java @@ -109,8 +109,8 @@ public class PluginManagerImplTest extends BrambleTestCase { oneOf(duplexPlugin).stop(); }}); - PluginManagerImpl p = new PluginManagerImpl(ioExecutor, eventBus, - pluginConfig, connectionManager, settingsManager, + PluginManagerImpl p = new PluginManagerImpl(ioExecutor, ioExecutor, + eventBus, pluginConfig, connectionManager, settingsManager, transportPropertyManager); // Two plugins should be started and stopped diff --git a/bramble-core/src/test/java/org/briarproject/bramble/plugin/PollerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/plugin/PollerImplTest.java index 5d5db5497..2a93fd39e 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/plugin/PollerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/plugin/PollerImplTest.java @@ -58,6 +58,7 @@ public class PollerImplTest extends BrambleMockTestCase { private final Future future = context.mock(Future.class); private final SecureRandom random; + private final Executor ioExecutor = new ImmediateExecutor(); private final Executor wakefulIoExecutor = new ImmediateExecutor(); private final TransportId transportId = getTransportId(); private final ContactId contactId = getContactId(); @@ -74,9 +75,9 @@ public class PollerImplTest extends BrambleMockTestCase { @Before public void setUp() { - poller = new PollerImpl(wakefulIoExecutor, scheduler, connectionManager, - connectionRegistry, pluginManager, transportPropertyManager, - random, clock); + poller = new PollerImpl(ioExecutor, wakefulIoExecutor, scheduler, + connectionManager, connectionRegistry, pluginManager, + transportPropertyManager, random, clock); } @Test @@ -234,7 +235,7 @@ public class PollerImplTest extends BrambleMockTestCase { oneOf(clock).currentTimeMillis(); will(returnValue(now)); oneOf(scheduler).schedule(with(any(Runnable.class)), - with(wakefulIoExecutor), with((long) pollingInterval), + with(ioExecutor), with((long) pollingInterval), with(MILLISECONDS)); will(returnValue(future)); }}); @@ -263,7 +264,7 @@ public class PollerImplTest extends BrambleMockTestCase { oneOf(clock).currentTimeMillis(); will(returnValue(now)); oneOf(scheduler).schedule(with(any(Runnable.class)), - with(wakefulIoExecutor), with((long) pollingInterval), + with(ioExecutor), with((long) pollingInterval), with(MILLISECONDS)); will(returnValue(future)); // Second event @@ -306,7 +307,7 @@ public class PollerImplTest extends BrambleMockTestCase { oneOf(clock).currentTimeMillis(); will(returnValue(now)); oneOf(scheduler).schedule(with(any(Runnable.class)), - with(wakefulIoExecutor), with((long) pollingInterval), + with(ioExecutor), with((long) pollingInterval), with(MILLISECONDS)); will(returnValue(future)); // Second event @@ -323,7 +324,7 @@ public class PollerImplTest extends BrambleMockTestCase { will(returnValue(now + 1)); oneOf(future).cancel(false); oneOf(scheduler).schedule(with(any(Runnable.class)), - with(wakefulIoExecutor), with((long) pollingInterval - 2), + with(ioExecutor), with((long) pollingInterval - 2), with(MILLISECONDS)); }}); @@ -350,7 +351,7 @@ public class PollerImplTest extends BrambleMockTestCase { oneOf(clock).currentTimeMillis(); will(returnValue(now)); oneOf(scheduler).schedule(with(any(Runnable.class)), - with(wakefulIoExecutor), with(0L), with(MILLISECONDS)); + with(ioExecutor), with(0L), with(MILLISECONDS)); will(returnValue(future)); will(new RunAction()); // Running the polling task schedules the next polling task @@ -361,7 +362,7 @@ public class PollerImplTest extends BrambleMockTestCase { oneOf(clock).currentTimeMillis(); will(returnValue(now)); oneOf(scheduler).schedule(with(any(Runnable.class)), - with(wakefulIoExecutor), with((long) (pollingInterval * 0.5)), + with(ioExecutor), with((long) (pollingInterval * 0.5)), with(MILLISECONDS)); will(returnValue(future)); // Get the transport properties and connected contacts @@ -394,7 +395,7 @@ public class PollerImplTest extends BrambleMockTestCase { oneOf(clock).currentTimeMillis(); will(returnValue(now)); oneOf(scheduler).schedule(with(any(Runnable.class)), - with(wakefulIoExecutor), with(0L), with(MILLISECONDS)); + with(ioExecutor), with(0L), with(MILLISECONDS)); will(returnValue(future)); will(new RunAction()); // Running the polling task schedules the next polling task @@ -405,7 +406,7 @@ public class PollerImplTest extends BrambleMockTestCase { oneOf(clock).currentTimeMillis(); will(returnValue(now)); oneOf(scheduler).schedule(with(any(Runnable.class)), - with(wakefulIoExecutor), with((long) (pollingInterval * 0.5)), + with(ioExecutor), with((long) (pollingInterval * 0.5)), with(MILLISECONDS)); will(returnValue(future)); // Get the transport properties and connected contacts @@ -436,7 +437,7 @@ public class PollerImplTest extends BrambleMockTestCase { oneOf(clock).currentTimeMillis(); will(returnValue(now)); oneOf(scheduler).schedule(with(any(Runnable.class)), - with(wakefulIoExecutor), with(0L), with(MILLISECONDS)); + with(ioExecutor), with(0L), with(MILLISECONDS)); will(returnValue(future)); // The plugin is deactivated before the task runs - cancel the task oneOf(future).cancel(false); @@ -460,7 +461,7 @@ public class PollerImplTest extends BrambleMockTestCase { oneOf(clock).currentTimeMillis(); will(returnValue(now)); oneOf(scheduler).schedule(with(any(Runnable.class)), - with(wakefulIoExecutor), with((long) pollingInterval), + with(ioExecutor), with((long) pollingInterval), with(MILLISECONDS)); will(returnValue(future)); }}); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java index 0c4de76ee..fedf33ba3 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java @@ -24,6 +24,7 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.plugin.PluginManager; import org.briarproject.bramble.api.settings.SettingsManager; import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.bramble.api.system.AndroidWakeLockManager; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.LocationUtils; import org.briarproject.bramble.plugin.tor.CircumventionProvider; @@ -166,6 +167,8 @@ public interface AndroidComponent FeatureFlags featureFlags(); + AndroidWakeLockManager wakeLockManager(); + void inject(SignInReminderReceiver briarService); void inject(BriarService briarService); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java b/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java index 355df4b8a..a949161e9 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java @@ -19,6 +19,7 @@ import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult; import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.bramble.api.system.AndroidWakeLockManager; import org.briarproject.briar.R; import org.briarproject.briar.android.logout.HideUiActivity; import org.briarproject.briar.api.android.AndroidNotificationManager; @@ -48,6 +49,7 @@ import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING; import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS; +import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull; import static org.briarproject.briar.android.BriarApplication.ENTRY_ACTIVITY; import static org.briarproject.briar.api.android.AndroidNotificationManager.FAILURE_CHANNEL_ID; import static org.briarproject.briar.api.android.AndroidNotificationManager.FAILURE_NOTIFICATION_ID; @@ -80,6 +82,8 @@ public class BriarService extends Service { AccountManager accountManager; @Inject LockManager lockManager; + @Inject + AndroidWakeLockManager wakeLockManager; // Fields that are accessed from background threads must be volatile @Inject @@ -108,54 +112,57 @@ public class BriarService extends Service { return; } - // Create notification channels - if (SDK_INT >= 26) { - NotificationManager nm = (NotificationManager) - getSystemService(NOTIFICATION_SERVICE); - NotificationChannel ongoingChannel = new NotificationChannel( - ONGOING_CHANNEL_ID, - getString(R.string.ongoing_notification_title), - IMPORTANCE_NONE); - ongoingChannel.setLockscreenVisibility(VISIBILITY_SECRET); - nm.createNotificationChannel(ongoingChannel); - NotificationChannel failureChannel = new NotificationChannel( - FAILURE_CHANNEL_ID, - getString(R.string.startup_failed_notification_title), - IMPORTANCE_DEFAULT); - failureChannel.setLockscreenVisibility(VISIBILITY_SECRET); - nm.createNotificationChannel(failureChannel); - } - Notification foregroundNotification = - notificationManager.getForegroundNotification(); - startForeground(ONGOING_NOTIFICATION_ID, foregroundNotification); - // Start the services in a background thread - new Thread(() -> { - StartResult result = lifecycleManager.startServices(dbKey); - if (result == SUCCESS) { - started = true; - } else if (result == ALREADY_RUNNING) { - LOG.info("Already running"); - stopSelf(); - } else { - if (LOG.isLoggable(WARNING)) - LOG.warning("Startup failed: " + result); - showStartupFailureNotification(result); - stopSelf(); + // Hold a wake lock during startup + wakeLockManager.runWakefully(() -> { + // Create notification channels + if (SDK_INT >= 26) { + NotificationManager nm = (NotificationManager) + requireNonNull(getSystemService(NOTIFICATION_SERVICE)); + NotificationChannel ongoingChannel = new NotificationChannel( + ONGOING_CHANNEL_ID, + getString(R.string.ongoing_notification_title), + IMPORTANCE_NONE); + ongoingChannel.setLockscreenVisibility(VISIBILITY_SECRET); + nm.createNotificationChannel(ongoingChannel); + NotificationChannel failureChannel = new NotificationChannel( + FAILURE_CHANNEL_ID, + getString(R.string.startup_failed_notification_title), + IMPORTANCE_DEFAULT); + failureChannel.setLockscreenVisibility(VISIBILITY_SECRET); + nm.createNotificationChannel(failureChannel); } - }).start(); - // Register for device shutdown broadcasts - receiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - LOG.info("Device is shutting down"); - shutdownFromBackground(); - } - }; - IntentFilter filter = new IntentFilter(); - filter.addAction(ACTION_SHUTDOWN); - filter.addAction("android.intent.action.QUICKBOOT_POWEROFF"); - filter.addAction("com.htc.intent.action.QUICKBOOT_POWEROFF"); - registerReceiver(receiver, filter); + Notification foregroundNotification = + notificationManager.getForegroundNotification(); + startForeground(ONGOING_NOTIFICATION_ID, foregroundNotification); + // Start the services in a background thread + wakeLockManager.executeWakefully(() -> { + StartResult result = lifecycleManager.startServices(dbKey); + if (result == SUCCESS) { + started = true; + } else if (result == ALREADY_RUNNING) { + LOG.info("Already running"); + stopSelf(); + } else { + if (LOG.isLoggable(WARNING)) + LOG.warning("Startup failed: " + result); + showStartupFailureNotification(result); + stopSelf(); + } + }, "LifecycleStartup"); + // Register for device shutdown broadcasts + receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + LOG.info("Device is shutting down"); + shutdownFromBackground(); + } + }; + IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_SHUTDOWN); + filter.addAction("android.intent.action.QUICKBOOT_POWEROFF"); + filter.addAction("com.htc.intent.action.QUICKBOOT_POWEROFF"); + registerReceiver(receiver, filter); + }, "LifecycleStartup"); } @Override @@ -179,8 +186,8 @@ public class BriarService extends Service { i.putExtra(EXTRA_NOTIFICATION_ID, FAILURE_NOTIFICATION_ID); b.setContentIntent(PendingIntent.getActivity(BriarService.this, 0, i, FLAG_UPDATE_CURRENT)); - Object o = getSystemService(NOTIFICATION_SERVICE); - NotificationManager nm = (NotificationManager) o; + NotificationManager nm = (NotificationManager) + requireNonNull(getSystemService(NOTIFICATION_SERVICE)); nm.notify(FAILURE_NOTIFICATION_ID, b.build()); // Bring the dashboard to the front to clear the back stack i = new Intent(BriarService.this, ENTRY_ACTIVITY); @@ -205,14 +212,17 @@ public class BriarService extends Service { @Override public void onDestroy() { - super.onDestroy(); - LOG.info("Destroyed"); - stopForeground(true); - if (receiver != null) unregisterReceiver(receiver); - // Stop the services in a background thread - new Thread(() -> { - if (started) lifecycleManager.stopServices(); - }).start(); + // Hold a wake lock during shutdown + wakeLockManager.runWakefully(() -> { + super.onDestroy(); + LOG.info("Destroyed"); + stopForeground(true); + if (receiver != null) unregisterReceiver(receiver); + // Stop the services in a background thread + wakeLockManager.executeWakefully(() -> { + if (started) lifecycleManager.stopServices(); + }, "LifecycleShutdown"); + }, "LifecycleShutdown"); } @Override @@ -257,20 +267,23 @@ public class BriarService extends Service { } private void shutdownFromBackground() { - // Stop the service - stopSelf(); - // Hide the UI - hideUi(); - // Wait for shutdown to complete, then exit - new Thread(() -> { - try { - if (started) lifecycleManager.waitForShutdown(); - } catch (InterruptedException e) { - LOG.info("Interrupted while waiting for shutdown"); - } - LOG.info("Exiting"); - System.exit(0); - }).start(); + // Hold a wake lock during shutdown + wakeLockManager.runWakefully(() -> { + // Stop the service + stopSelf(); + // Hide the UI + hideUi(); + // Wait for shutdown to complete, then exit + wakeLockManager.executeWakefully(() -> { + try { + if (started) lifecycleManager.waitForShutdown(); + } catch (InterruptedException e) { + LOG.info("Interrupted while waiting for shutdown"); + } + LOG.info("Exiting"); + System.exit(0); + }, "BackgroundShutdown"); + }, "BackgroundShutdown"); } /** diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java index 60edec57d..02c18b341 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java @@ -82,13 +82,19 @@ import org.briarproject.briar.android.test.TestDataActivity; import dagger.Component; @ActivityScope -@Component( - modules = {ActivityModule.class, ForumModule.class, SharingModule.class, - BlogModule.class, ContactModule.class, GroupListModule.class, - CreateGroupModule.class, GroupInvitationModule.class, - GroupConversationModule.class, GroupMemberModule.class, - GroupRevealModule.class}, - dependencies = AndroidComponent.class) +@Component(modules = { + ActivityModule.class, + BlogModule.class, + ContactModule.class, + CreateGroupModule.class, + ForumModule.class, + GroupInvitationModule.class, + GroupConversationModule.class, + GroupListModule.class, + GroupMemberModule.class, + GroupRevealModule.class, + SharingModule.class +}, dependencies = AndroidComponent.class) public interface ActivityComponent { Activity activity(); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java index 15de79805..91aece926 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java @@ -7,6 +7,8 @@ import android.widget.CheckBox; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.bramble.api.system.AndroidWakeLockManager; +import org.briarproject.bramble.api.system.Wakeful; import org.briarproject.briar.R; import org.briarproject.briar.android.account.UnlockActivity; import org.briarproject.briar.android.controller.BriarController; @@ -32,6 +34,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION; import static android.os.Build.VERSION.SDK_INT; import static java.util.logging.Level.INFO; +import static java.util.logging.Logger.getLogger; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PASSWORD; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_UNLOCK; @@ -47,7 +50,7 @@ public abstract class BriarActivity extends BaseActivity { public static final String GROUP_NAME = "briar.GROUP_NAME"; private static final Logger LOG = - Logger.getLogger(BriarActivity.class.getName()); + getLogger(BriarActivity.class.getName()); @Inject BriarController briarController; @@ -56,6 +59,8 @@ public abstract class BriarActivity extends BaseActivity { DbController dbController; @Inject protected LockManager lockManager; + @Inject + AndroidWakeLockManager wakeLockManager; @Override public void onStart() { @@ -130,6 +135,7 @@ public abstract class BriarActivity extends BaseActivity { /** * Sets the transition animations. + * * @param enterTransition used to move views into initial positions * @param exitTransition used to move views out when starting a new activity. * @param returnTransition used when window is closing, because the activity is finishing. @@ -197,22 +203,30 @@ public abstract class BriarActivity extends BaseActivity { protected void signOut(boolean removeFromRecentApps, boolean deleteAccount) { - if (briarController.accountSignedIn()) { - // Don't use UiResultHandler because we want the result even if - // this activity has been destroyed - briarController.signOut(result -> runOnUiThread( - () -> exit(removeFromRecentApps)), deleteAccount); - } else { - if (deleteAccount) briarController.deleteAccount(); - exit(removeFromRecentApps); - } + // Hold a wake lock to ensure we exit before the device goes to sleep + wakeLockManager.runWakefully(() -> { + if (briarController.accountSignedIn()) { + // Don't use UiResultHandler because we want the result even if + // this activity has been destroyed + briarController.signOut(result -> { + Runnable exit = () -> exit(removeFromRecentApps); + wakeLockManager.executeWakefully(exit, + this::runOnUiThread, "SignOut"); + }, deleteAccount); + } else { + if (deleteAccount) briarController.deleteAccount(); + exit(removeFromRecentApps); + } + }, "SignOut"); } + @Wakeful private void exit(boolean removeFromRecentApps) { if (removeFromRecentApps) startExitActivity(); else finishAndExit(); } + @Wakeful private void startExitActivity() { Intent i = new Intent(this, ExitActivity.class); i.addFlags(FLAG_ACTIVITY_NEW_TASK @@ -222,6 +236,7 @@ public abstract class BriarActivity extends BaseActivity { startActivity(i); } + @Wakeful private void finishAndExit() { if (SDK_INT >= 21) finishAndRemoveTask(); else supportFinishAfterTransition(); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarController.java b/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarController.java index c86e6f905..33cbb9e64 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarController.java @@ -1,7 +1,10 @@ package org.briarproject.briar.android.controller; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.system.Wakeful; import org.briarproject.briar.android.controller.handler.ResultHandler; +@NotNullByDefault public interface BriarController extends ActivityLifecycleController { void startAndBindService(); @@ -16,7 +19,8 @@ public interface BriarController extends ActivityLifecycleController { void doNotAskAgainForDozeWhiteListing(); - void signOut(ResultHandler eventHandler, boolean deleteAccount); + @Wakeful + void signOut(ResultHandler handler, boolean deleteAccount); void deleteAccount(); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarControllerImpl.java index 2e4479716..65c3efec4 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarControllerImpl.java @@ -8,8 +8,10 @@ import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.settings.Settings; import org.briarproject.bramble.api.settings.SettingsManager; +import org.briarproject.bramble.api.system.AndroidWakeLockManager; import org.briarproject.briar.android.BriarService; import org.briarproject.briar.android.BriarService.BriarServiceConnection; import org.briarproject.briar.android.controller.handler.ResultHandler; @@ -23,15 +25,17 @@ import javax.inject.Inject; import androidx.annotation.CallSuper; import static java.util.logging.Level.WARNING; +import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING_SERVICES; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE; import static org.briarproject.briar.android.util.UiUtils.needsDozeWhitelisting; +@NotNullByDefault public class BriarControllerImpl implements BriarController { private static final Logger LOG = - Logger.getLogger(BriarControllerImpl.class.getName()); + getLogger(BriarControllerImpl.class.getName()); public static final String DOZE_ASK_AGAIN = "dozeAskAgain"; @@ -41,6 +45,7 @@ public class BriarControllerImpl implements BriarController { private final Executor databaseExecutor; private final SettingsManager settingsManager; private final DozeWatchdog dozeWatchdog; + private final AndroidWakeLockManager wakeLockManager; private final Activity activity; private boolean bound = false; @@ -50,7 +55,9 @@ public class BriarControllerImpl implements BriarController { AccountManager accountManager, LifecycleManager lifecycleManager, @DatabaseExecutor Executor databaseExecutor, - SettingsManager settingsManager, DozeWatchdog dozeWatchdog, + SettingsManager settingsManager, + DozeWatchdog dozeWatchdog, + AndroidWakeLockManager wakeLockManager, Activity activity) { this.serviceConnection = serviceConnection; this.accountManager = accountManager; @@ -58,6 +65,7 @@ public class BriarControllerImpl implements BriarController { this.databaseExecutor = databaseExecutor; this.settingsManager = settingsManager; this.dozeWatchdog = dozeWatchdog; + this.wakeLockManager = wakeLockManager; this.activity = activity; } @@ -127,9 +135,8 @@ public class BriarControllerImpl implements BriarController { } @Override - public void signOut(ResultHandler eventHandler, - boolean deleteAccount) { - new Thread(() -> { + public void signOut(ResultHandler handler, boolean deleteAccount) { + wakeLockManager.executeWakefully(() -> { try { // Wait for the service to finish starting up IBinder binder = serviceConnection.waitForBinder(); @@ -145,8 +152,8 @@ public class BriarControllerImpl implements BriarController { } finally { if (deleteAccount) accountManager.deleteAccount(); } - eventHandler.onResult(null); - }).start(); + handler.onResult(null); + }, "SignOut"); } @Override diff --git a/briar-android/src/main/java/org/briarproject/briar/android/panic/PanicResponderActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/panic/PanicResponderActivity.java index b1ca57ee6..f75167fb4 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/panic/PanicResponderActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/panic/PanicResponderActivity.java @@ -4,17 +4,14 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; -import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; -import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.BriarActivity; import java.util.logging.Logger; import javax.annotation.Nullable; -import javax.inject.Inject; import androidx.preference.PreferenceManager; import info.guardianproject.GuardianProjectRSA4096; @@ -23,6 +20,7 @@ import info.guardianproject.panic.PanicResponder; import info.guardianproject.trustedintents.TrustedIntents; import static android.os.Build.VERSION.SDK_INT; +import static java.util.logging.Logger.getLogger; import static org.briarproject.briar.android.panic.PanicPreferencesFragment.KEY_LOCK; import static org.briarproject.briar.android.panic.PanicPreferencesFragment.KEY_PURGE; @@ -31,12 +29,7 @@ import static org.briarproject.briar.android.panic.PanicPreferencesFragment.KEY_ public class PanicResponderActivity extends BriarActivity { private static final Logger LOG = - Logger.getLogger(PanicResponderActivity.class.getName()); - - @Inject - protected LifecycleManager lifecycleManager; - @Inject - protected AndroidExecutor androidExecutor; + getLogger(PanicResponderActivity.class.getName()); @Override public void onCreate(@Nullable Bundle savedInstanceState) { @@ -63,13 +56,20 @@ public class PanicResponderActivity extends BriarActivity { // Performing panic responses if (sharedPref.getBoolean(KEY_PURGE, false)) { LOG.info("Purging all data..."); - deleteAllData(); + signOut(true, true); + } else if (sharedPref.getBoolean(KEY_LOCK, true)) { + LOG.info("Signing out..."); + signOut(true, false); + } else { + LOG.info("Configured not to purge or lock"); } - } - // non-destructive actions are allowed by non-connected trusted apps - if (sharedPref.getBoolean(KEY_LOCK, true)) { + } else if (sharedPref.getBoolean(KEY_LOCK, true)) { + // non-destructive actions are allowed by non-connected + // trusted apps LOG.info("Signing out..."); signOut(true, false); + } else { + LOG.info("Configured not to lock"); } } } @@ -85,11 +85,4 @@ public class PanicResponderActivity extends BriarActivity { public void injectActivity(ActivityComponent component) { component.inject(this); } - - private void deleteAllData() { - androidExecutor.runOnBackgroundThread(() -> { - LOG.info("Signing out..."); - signOut(true, true); - }); - } } diff --git a/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java index 713e2c090..b2ac62c83 100644 --- a/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java @@ -30,6 +30,7 @@ import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.TaskScheduler; +import org.briarproject.bramble.api.system.Wakeful; import org.briarproject.bramble.util.StringUtils; import org.briarproject.briar.api.blog.Blog; import org.briarproject.briar.api.blog.BlogManager; @@ -284,7 +285,7 @@ class FeedManagerImpl implements FeedManager, EventListener, OpenDatabaseHook, } /** - * This method is called periodically from a background service. + * This method is called periodically by the task scheduler. * It fetches all available feeds and posts new entries to the respective * blog. *

@@ -292,6 +293,7 @@ class FeedManagerImpl implements FeedManager, EventListener, OpenDatabaseHook, * because fetching can take a long time * and we can not block the database that long. */ + @Wakeful void fetchFeeds() { if (!torActive) return; LOG.info("Updating RSS feeds...");