Merge branch '1142-wakeful-tasks' into 'master'

Hold a wake lock while running scheduled tasks

See merge request briar/briar!1268
This commit is contained in:
akwizgran
2020-08-10 12:54:00 +00:00
25 changed files with 307 additions and 174 deletions

View File

@@ -1,9 +0,0 @@
package org.briarproject.bramble.api.system;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface AndroidWakeLockFactory {
AndroidWakeLock createWakeLock();
}

View File

@@ -0,0 +1,27 @@
package org.briarproject.bramble.api.system;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.concurrent.Executor;
@NotNullByDefault
public interface AndroidWakeLockManager {
/**
* Creates a wake lock with the given tag. The tag is only used for
* logging; the underlying OS wake lock will use its own tag.
*/
AndroidWakeLock createWakeLock(String tag);
/**
* Runs the given task while holding a wake lock.
*/
void runWakefully(Runnable r, String tag);
/**
* Submits the given task to the given executor while holding a wake lock.
* The lock is released when the task completes, or if an exception is
* thrown while submitting or running the task.
*/
void executeWakefully(Runnable r, Executor executor, String tag);
}

View File

@@ -9,6 +9,7 @@ import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventExecutor;
import org.briarproject.bramble.api.lifecycle.Service; import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.network.NetworkManager; import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.network.NetworkStatus; import org.briarproject.bramble.api.network.NetworkStatus;
@@ -17,6 +18,7 @@ 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.system.TaskScheduler; import org.briarproject.bramble.api.system.TaskScheduler;
import java.util.concurrent.Executor;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@@ -51,6 +53,7 @@ class AndroidNetworkManager implements NetworkManager, Service {
private final TaskScheduler scheduler; private final TaskScheduler scheduler;
private final EventBus eventBus; private final EventBus eventBus;
private final Executor eventExecutor;
private final Context appContext; private final Context appContext;
private final AtomicReference<Future<?>> connectivityCheck = private final AtomicReference<Future<?>> connectivityCheck =
new AtomicReference<>(); new AtomicReference<>();
@@ -60,9 +63,10 @@ class AndroidNetworkManager implements NetworkManager, Service {
@Inject @Inject
AndroidNetworkManager(TaskScheduler scheduler, EventBus eventBus, AndroidNetworkManager(TaskScheduler scheduler, EventBus eventBus,
Application app) { @EventExecutor Executor eventExecutor, Application app) {
this.scheduler = scheduler; this.scheduler = scheduler;
this.eventBus = eventBus; this.eventBus = eventBus;
this.eventExecutor = eventExecutor;
this.appContext = app.getApplicationContext(); this.appContext = app.getApplicationContext();
} }
@@ -104,7 +108,8 @@ class AndroidNetworkManager implements NetworkManager, Service {
private void scheduleConnectionStatusUpdate(int delay, TimeUnit unit) { private void scheduleConnectionStatusUpdate(int delay, TimeUnit unit) {
Future<?> newConnectivityCheck = Future<?> newConnectivityCheck =
scheduler.schedule(this::updateConnectionStatus, delay, unit); scheduler.schedule(this::updateConnectionStatus, eventExecutor,
delay, unit);
Future<?> oldConnectivityCheck = Future<?> oldConnectivityCheck =
connectivityCheck.getAndSet(newConnectivityCheck); connectivityCheck.getAndSet(newConnectivityCheck);
if (oldConnectivityCheck != null) oldConnectivityCheck.cancel(false); if (oldConnectivityCheck != null) oldConnectivityCheck.cancel(false);

View File

@@ -6,7 +6,7 @@ import org.briarproject.bramble.api.io.TimeoutMonitor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin; import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.system.AndroidWakeLockFactory; import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import java.io.IOException; import java.io.IOException;
@@ -15,15 +15,15 @@ class AndroidBluetoothConnectionFactory
implements BluetoothConnectionFactory<BluetoothSocket> { implements BluetoothConnectionFactory<BluetoothSocket> {
private final BluetoothConnectionLimiter connectionLimiter; private final BluetoothConnectionLimiter connectionLimiter;
private final AndroidWakeLockFactory wakeLockFactory; private final AndroidWakeLockManager wakeLockManager;
private final TimeoutMonitor timeoutMonitor; private final TimeoutMonitor timeoutMonitor;
AndroidBluetoothConnectionFactory( AndroidBluetoothConnectionFactory(
BluetoothConnectionLimiter connectionLimiter, BluetoothConnectionLimiter connectionLimiter,
AndroidWakeLockFactory wakeLockFactory, AndroidWakeLockManager wakeLockManager,
TimeoutMonitor timeoutMonitor) { TimeoutMonitor timeoutMonitor) {
this.connectionLimiter = connectionLimiter; this.connectionLimiter = connectionLimiter;
this.wakeLockFactory = wakeLockFactory; this.wakeLockManager = wakeLockManager;
this.timeoutMonitor = timeoutMonitor; this.timeoutMonitor = timeoutMonitor;
} }
@@ -31,6 +31,6 @@ class AndroidBluetoothConnectionFactory
public DuplexTransportConnection wrapSocket(DuplexPlugin plugin, public DuplexTransportConnection wrapSocket(DuplexPlugin plugin,
BluetoothSocket s) throws IOException { BluetoothSocket s) throws IOException {
return new AndroidBluetoothTransportConnection(plugin, return new AndroidBluetoothTransportConnection(plugin,
connectionLimiter, wakeLockFactory, timeoutMonitor, s); connectionLimiter, wakeLockManager, timeoutMonitor, s);
} }
} }

View File

@@ -13,7 +13,7 @@ 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.DuplexPluginFactory; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.AndroidWakeLockFactory; import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import java.security.SecureRandom; import java.security.SecureRandom;
@@ -35,7 +35,7 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
private final Executor ioExecutor; private final Executor ioExecutor;
private final AndroidExecutor androidExecutor; private final AndroidExecutor androidExecutor;
private final AndroidWakeLockFactory wakeLockFactory; private final AndroidWakeLockManager wakeLockManager;
private final Context appContext; private final Context appContext;
private final SecureRandom secureRandom; private final SecureRandom secureRandom;
private final EventBus eventBus; private final EventBus eventBus;
@@ -45,7 +45,7 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
public AndroidBluetoothPluginFactory(Executor ioExecutor, public AndroidBluetoothPluginFactory(Executor ioExecutor,
AndroidExecutor androidExecutor, AndroidExecutor androidExecutor,
AndroidWakeLockFactory wakeLockFactory, AndroidWakeLockManager wakeLockManager,
Context appContext, Context appContext,
SecureRandom secureRandom, SecureRandom secureRandom,
EventBus eventBus, EventBus eventBus,
@@ -54,7 +54,7 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
BackoffFactory backoffFactory) { BackoffFactory backoffFactory) {
this.ioExecutor = ioExecutor; this.ioExecutor = ioExecutor;
this.androidExecutor = androidExecutor; this.androidExecutor = androidExecutor;
this.wakeLockFactory = wakeLockFactory; this.wakeLockManager = wakeLockManager;
this.appContext = appContext; this.appContext = appContext;
this.secureRandom = secureRandom; this.secureRandom = secureRandom;
this.eventBus = eventBus; this.eventBus = eventBus;
@@ -79,7 +79,7 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
new BluetoothConnectionLimiterImpl(eventBus); new BluetoothConnectionLimiterImpl(eventBus);
BluetoothConnectionFactory<BluetoothSocket> connectionFactory = BluetoothConnectionFactory<BluetoothSocket> connectionFactory =
new AndroidBluetoothConnectionFactory(connectionLimiter, new AndroidBluetoothConnectionFactory(connectionLimiter,
wakeLockFactory, timeoutMonitor); wakeLockManager, timeoutMonitor);
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE); MAX_POLLING_INTERVAL, BACKOFF_BASE);
AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin( AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(

View File

@@ -7,7 +7,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Plugin; import org.briarproject.bramble.api.plugin.Plugin;
import org.briarproject.bramble.api.plugin.duplex.AbstractDuplexTransportConnection; import org.briarproject.bramble.api.plugin.duplex.AbstractDuplexTransportConnection;
import org.briarproject.bramble.api.system.AndroidWakeLock; import org.briarproject.bramble.api.system.AndroidWakeLock;
import org.briarproject.bramble.api.system.AndroidWakeLockFactory; import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@@ -27,7 +27,7 @@ class AndroidBluetoothTransportConnection
AndroidBluetoothTransportConnection(Plugin plugin, AndroidBluetoothTransportConnection(Plugin plugin,
BluetoothConnectionLimiter connectionLimiter, BluetoothConnectionLimiter connectionLimiter,
AndroidWakeLockFactory wakeLockFactory, AndroidWakeLockManager wakeLockManager,
TimeoutMonitor timeoutMonitor, TimeoutMonitor timeoutMonitor,
BluetoothSocket socket) throws IOException { BluetoothSocket socket) throws IOException {
super(plugin); super(plugin);
@@ -35,7 +35,7 @@ class AndroidBluetoothTransportConnection
this.socket = socket; this.socket = socket;
in = timeoutMonitor.createTimeoutInputStream( in = timeoutMonitor.createTimeoutInputStream(
socket.getInputStream(), plugin.getMaxIdleTime() * 2); socket.getInputStream(), plugin.getMaxIdleTime() * 2);
wakeLock = wakeLockFactory.createWakeLock(); wakeLock = wakeLockManager.createWakeLock("BluetoothConnection");
wakeLock.acquire(); wakeLock.acquire();
String address = socket.getRemoteDevice().getAddress(); String address = socket.getRemoteDevice().getAddress();
if (isValidBluetoothAddress(address)) remote.put(PROP_ADDRESS, address); if (isValidBluetoothAddress(address)) remote.put(PROP_ADDRESS, address);

View File

@@ -12,7 +12,7 @@ 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.PluginCallback; import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.system.AndroidWakeLock; import org.briarproject.bramble.api.system.AndroidWakeLock;
import org.briarproject.bramble.api.system.AndroidWakeLockFactory; import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils; import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider; import org.briarproject.bramble.api.system.ResourceProvider;
@@ -40,7 +40,7 @@ class AndroidTorPlugin extends TorPlugin {
ResourceProvider resourceProvider, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, CircumventionProvider circumventionProvider,
BatteryManager batteryManager, BatteryManager batteryManager,
AndroidWakeLockFactory wakeLockFactory, AndroidWakeLockManager wakeLockManager,
Backoff backoff, Backoff backoff,
TorRendezvousCrypto torRendezvousCrypto, TorRendezvousCrypto torRendezvousCrypto,
PluginCallback callback, PluginCallback callback,
@@ -53,7 +53,7 @@ class AndroidTorPlugin extends TorPlugin {
maxLatency, maxIdleTime, maxLatency, maxIdleTime,
appContext.getDir("tor", MODE_PRIVATE)); appContext.getDir("tor", MODE_PRIVATE));
this.appContext = appContext; this.appContext = appContext;
wakeLock = wakeLockFactory.createWakeLock(); wakeLock = wakeLockManager.createWakeLock("TorPlugin");
} }
@Override @Override

View File

@@ -13,7 +13,7 @@ import org.briarproject.bramble.api.plugin.TorConstants;
import org.briarproject.bramble.api.plugin.TransportId; 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.DuplexPluginFactory; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.AndroidWakeLockFactory; import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils; import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider; import org.briarproject.bramble.api.system.ResourceProvider;
@@ -48,7 +48,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
private final ResourceProvider resourceProvider; private final ResourceProvider resourceProvider;
private final CircumventionProvider circumventionProvider; private final CircumventionProvider circumventionProvider;
private final BatteryManager batteryManager; private final BatteryManager batteryManager;
private final AndroidWakeLockFactory wakeLockFactory; private final AndroidWakeLockManager wakeLockManager;
private final Clock clock; private final Clock clock;
public AndroidTorPluginFactory(Executor ioExecutor, public AndroidTorPluginFactory(Executor ioExecutor,
@@ -61,7 +61,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
ResourceProvider resourceProvider, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, CircumventionProvider circumventionProvider,
BatteryManager batteryManager, BatteryManager batteryManager,
AndroidWakeLockFactory wakeLockFactory, AndroidWakeLockManager wakeLockManager,
Clock clock) { Clock clock) {
this.ioExecutor = ioExecutor; this.ioExecutor = ioExecutor;
this.appContext = appContext; this.appContext = appContext;
@@ -73,7 +73,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
this.resourceProvider = resourceProvider; this.resourceProvider = resourceProvider;
this.circumventionProvider = circumventionProvider; this.circumventionProvider = circumventionProvider;
this.batteryManager = batteryManager; this.batteryManager = batteryManager;
this.wakeLockFactory = wakeLockFactory; this.wakeLockManager = wakeLockManager;
this.clock = clock; this.clock = clock;
} }
@@ -120,7 +120,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor,
appContext, networkManager, locationUtils, torSocketFactory, appContext, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, batteryManager, clock, resourceProvider, circumventionProvider, batteryManager,
wakeLockFactory, backoff, torRendezvousCrypto, callback, wakeLockManager, backoff, torRendezvousCrypto, callback,
architecture, MAX_LATENCY, MAX_IDLE_TIME); architecture, MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin); eventBus.addListener(plugin);
return plugin; return plugin;

View File

@@ -1,13 +1,17 @@
package org.briarproject.bramble.system; package org.briarproject.bramble.system;
import org.briarproject.bramble.api.event.EventExecutor; import org.briarproject.bramble.api.event.EventExecutor;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.AndroidWakeLockFactory; import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.LocationUtils; import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider; import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.api.system.SecureRandomProvider; import org.briarproject.bramble.api.system.SecureRandomProvider;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import javax.inject.Singleton; import javax.inject.Singleton;
@@ -17,6 +21,23 @@ import dagger.Provides;
@Module @Module
public class AndroidSystemModule { public class AndroidSystemModule {
private final ScheduledExecutorService scheduledExecutorService;
public AndroidSystemModule() {
// Discard tasks that are submitted during shutdown
RejectedExecutionHandler policy =
new ScheduledThreadPoolExecutor.DiscardPolicy();
scheduledExecutorService = new ScheduledThreadPoolExecutor(1, policy);
}
@Provides
@Singleton
ScheduledExecutorService provideScheduledExecutorService(
LifecycleManager lifecycleManager) {
lifecycleManager.registerForShutdown(scheduledExecutorService);
return scheduledExecutorService;
}
@Provides @Provides
@Singleton @Singleton
SecureRandomProvider provideSecureRandomProvider( SecureRandomProvider provideSecureRandomProvider(
@@ -51,8 +72,8 @@ public class AndroidSystemModule {
@Provides @Provides
@Singleton @Singleton
AndroidWakeLockFactory provideWakeLockFactory( AndroidWakeLockManager provideWakeLockManager(
AndroidWakeLockFactoryImpl wakeLockFactory) { AndroidWakeLockManagerImpl wakeLockManager) {
return wakeLockFactory; return wakeLockManager;
} }
} }

View File

@@ -11,12 +11,14 @@ import android.os.SystemClock;
import org.briarproject.bramble.api.lifecycle.Service; import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.AlarmListener; import org.briarproject.bramble.api.system.AlarmListener;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.TaskScheduler; import org.briarproject.bramble.api.system.TaskScheduler;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.PriorityQueue; import java.util.PriorityQueue;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.Executor;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.FutureTask; import java.util.concurrent.FutureTask;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
@@ -50,6 +52,7 @@ class AndroidTaskScheduler implements TaskScheduler, Service, AlarmListener {
private static final long ALARM_MS = INTERVAL_FIFTEEN_MINUTES; private static final long ALARM_MS = INTERVAL_FIFTEEN_MINUTES;
private final Application app; private final Application app;
private final AndroidWakeLockManager wakeLockManager;
private final ScheduledExecutorService scheduledExecutorService; private final ScheduledExecutorService scheduledExecutorService;
private final AlarmManager alarmManager; private final AlarmManager alarmManager;
@@ -58,8 +61,10 @@ class AndroidTaskScheduler implements TaskScheduler, Service, AlarmListener {
private final Queue<ScheduledTask> tasks = new PriorityQueue<>(); private final Queue<ScheduledTask> tasks = new PriorityQueue<>();
AndroidTaskScheduler(Application app, AndroidTaskScheduler(Application app,
AndroidWakeLockManager wakeLockManager,
ScheduledExecutorService scheduledExecutorService) { ScheduledExecutorService scheduledExecutorService) {
this.app = app; this.app = app;
this.wakeLockManager = wakeLockManager;
this.scheduledExecutorService = scheduledExecutorService; this.scheduledExecutorService = scheduledExecutorService;
alarmManager = (AlarmManager) alarmManager = (AlarmManager)
requireNonNull(app.getSystemService(ALARM_SERVICE)); requireNonNull(app.getSystemService(ALARM_SERVICE));
@@ -67,8 +72,9 @@ class AndroidTaskScheduler implements TaskScheduler, Service, AlarmListener {
@Override @Override
public void startService() { public void startService() {
scheduledExecutorService.scheduleAtFixedRate(this::runDueTasks, scheduledExecutorService.scheduleAtFixedRate(
TICK_MS, TICK_MS, MILLISECONDS); () -> wakeLockManager.runWakefully(this::runDueTasks,
"TaskTicker"), TICK_MS, TICK_MS, MILLISECONDS);
scheduleAlarm(); scheduleAlarm();
} }
@@ -78,10 +84,13 @@ class AndroidTaskScheduler implements TaskScheduler, Service, AlarmListener {
} }
@Override @Override
public Future<?> schedule(Runnable task, long delay, TimeUnit unit) { public Future<?> schedule(Runnable task, Executor executor, long delay,
TimeUnit unit) {
long now = SystemClock.elapsedRealtime(); long now = SystemClock.elapsedRealtime();
long dueMillis = now + MILLISECONDS.convert(delay, unit); long dueMillis = now + MILLISECONDS.convert(delay, unit);
ScheduledTask s = new ScheduledTask(task, dueMillis); Runnable wakeful = () ->
wakeLockManager.executeWakefully(task, executor, "TaskHandoff");
ScheduledTask s = new ScheduledTask(wakeful, dueMillis);
if (dueMillis <= now) { if (dueMillis <= now) {
scheduledExecutorService.execute(s); scheduledExecutorService.execute(s);
} else { } else {
@@ -93,27 +102,29 @@ class AndroidTaskScheduler implements TaskScheduler, Service, AlarmListener {
} }
@Override @Override
public Future<?> scheduleWithFixedDelay(Runnable task, long delay, public Future<?> scheduleWithFixedDelay(Runnable task, Executor executor,
long interval, TimeUnit unit) { long delay, long interval, TimeUnit unit) {
Runnable wrapped = () -> { Runnable wrapped = () -> {
task.run(); task.run();
scheduleWithFixedDelay(task, interval, interval, unit); scheduleWithFixedDelay(task, executor, interval, interval, unit);
}; };
return schedule(wrapped, delay, unit); return schedule(wrapped, executor, delay, unit);
} }
@Override @Override
public void onAlarm(Intent intent) { public void onAlarm(Intent intent) {
int extraPid = intent.getIntExtra(EXTRA_PID, -1); wakeLockManager.runWakefully(() -> {
int currentPid = Process.myPid(); int extraPid = intent.getIntExtra(EXTRA_PID, -1);
if (extraPid == currentPid) { int currentPid = Process.myPid();
LOG.info("Alarm"); if (extraPid == currentPid) {
rescheduleAlarm(); LOG.info("Alarm");
runDueTasks(); rescheduleAlarm();
} else if (LOG.isLoggable(INFO)) { runDueTasks();
LOG.info("Ignoring alarm with PID " + extraPid } else if (LOG.isLoggable(INFO)) {
+ ", current PID is " + currentPid); LOG.info("Ignoring alarm with PID " + extraPid
} + ", current PID is " + currentPid);
}
}, "TaskAlarm");
} }
private void runDueTasks() { private void runDueTasks() {

View File

@@ -4,11 +4,10 @@ import android.app.Application;
import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.system.AlarmListener; import org.briarproject.bramble.api.system.AlarmListener;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.TaskScheduler; import org.briarproject.bramble.api.system.TaskScheduler;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
@@ -24,22 +23,14 @@ public class AndroidTaskSchedulerModule {
AndroidTaskScheduler scheduler; AndroidTaskScheduler scheduler;
} }
private final ScheduledExecutorService scheduledExecutorService;
public AndroidTaskSchedulerModule() {
// Discard tasks that are submitted during shutdown
RejectedExecutionHandler policy =
new ScheduledThreadPoolExecutor.DiscardPolicy();
scheduledExecutorService = new ScheduledThreadPoolExecutor(1, policy);
}
@Provides @Provides
@Singleton @Singleton
AndroidTaskScheduler provideAndroidTaskScheduler( AndroidTaskScheduler provideAndroidTaskScheduler(
LifecycleManager lifecycleManager, Application app) { LifecycleManager lifecycleManager, Application app,
lifecycleManager.registerForShutdown(scheduledExecutorService); AndroidWakeLockManager wakeLockManager,
AndroidTaskScheduler scheduler = ScheduledExecutorService scheduledExecutorService) {
new AndroidTaskScheduler(app, scheduledExecutorService); AndroidTaskScheduler scheduler = new AndroidTaskScheduler(app,
wakeLockManager, scheduledExecutorService);
lifecycleManager.registerService(scheduler); lifecycleManager.registerService(scheduler);
return scheduler; return scheduler;
} }

View File

@@ -3,9 +3,15 @@ package org.briarproject.bramble.system;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.AndroidWakeLock; import org.briarproject.bramble.api.system.AndroidWakeLock;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
import static java.util.logging.Level.FINE;
import static java.util.logging.Logger.getLogger;
/** /**
* A wrapper around a {@link SharedWakeLock} that provides the more convenient * A wrapper around a {@link SharedWakeLock} that provides the more convenient
* semantics of {@link AndroidWakeLock} (i.e. calls to acquire() and release() * semantics of {@link AndroidWakeLock} (i.e. calls to acquire() and release()
@@ -15,19 +21,34 @@ import javax.annotation.concurrent.ThreadSafe;
@NotNullByDefault @NotNullByDefault
class AndroidWakeLockImpl implements AndroidWakeLock { class AndroidWakeLockImpl implements AndroidWakeLock {
private static final Logger LOG =
getLogger(AndroidWakeLockImpl.class.getName());
private static final AtomicInteger INSTANCE_ID = new AtomicInteger(0);
private final SharedWakeLock sharedWakeLock; private final SharedWakeLock sharedWakeLock;
private final String tag;
private final Object lock = new Object(); private final Object lock = new Object();
@GuardedBy("lock") @GuardedBy("lock")
private boolean held = false; private boolean held = false;
AndroidWakeLockImpl(SharedWakeLock sharedWakeLock) { AndroidWakeLockImpl(SharedWakeLock sharedWakeLock, String tag) {
this.sharedWakeLock = sharedWakeLock; this.sharedWakeLock = sharedWakeLock;
this.tag = tag + "_" + INSTANCE_ID.getAndIncrement();
} }
@Override @Override
public void acquire() { public void acquire() {
synchronized (lock) { synchronized (lock) {
if (!held) { if (held) {
if (LOG.isLoggable(FINE)) {
LOG.fine(tag + " already acquired");
}
} else {
if (LOG.isLoggable(FINE)) {
LOG.fine(tag + " acquiring shared wake lock");
}
held = true; held = true;
sharedWakeLock.acquire(); sharedWakeLock.acquire();
} }
@@ -38,8 +59,15 @@ class AndroidWakeLockImpl implements AndroidWakeLock {
public void release() { public void release() {
synchronized (lock) { synchronized (lock) {
if (held) { if (held) {
if (LOG.isLoggable(FINE)) {
LOG.fine(tag + " releasing shared wake lock");
}
held = false; held = false;
sharedWakeLock.release(); sharedWakeLock.release();
} else {
if (LOG.isLoggable(FINE)) {
LOG.fine(tag + " already released");
}
} }
} }
} }

View File

@@ -8,8 +8,10 @@ import android.os.PowerManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.AndroidWakeLock; import org.briarproject.bramble.api.system.AndroidWakeLock;
import org.briarproject.bramble.api.system.AndroidWakeLockFactory; import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.TaskScheduler;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import javax.inject.Inject; import javax.inject.Inject;
@@ -20,7 +22,7 @@ import static java.util.concurrent.TimeUnit.SECONDS;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull; import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
@NotNullByDefault @NotNullByDefault
class AndroidWakeLockFactoryImpl implements AndroidWakeLockFactory { class AndroidWakeLockManagerImpl implements AndroidWakeLockManager {
/** /**
* How often to replace the wake lock. * How often to replace the wake lock.
@@ -36,17 +38,52 @@ class AndroidWakeLockFactoryImpl implements AndroidWakeLockFactory {
private final SharedWakeLock sharedWakeLock; private final SharedWakeLock sharedWakeLock;
@Inject @Inject
AndroidWakeLockFactoryImpl(TaskScheduler scheduler, Application app) { AndroidWakeLockManagerImpl(Application app,
ScheduledExecutorService scheduledExecutorService) {
PowerManager powerManager = (PowerManager) PowerManager powerManager = (PowerManager)
requireNonNull(app.getSystemService(POWER_SERVICE)); requireNonNull(app.getSystemService(POWER_SERVICE));
String tag = getWakeLockTag(app); String tag = getWakeLockTag(app);
sharedWakeLock = new RenewableWakeLock(powerManager, scheduler, sharedWakeLock = new RenewableWakeLock(powerManager,
PARTIAL_WAKE_LOCK, tag, LOCK_DURATION_MS, SAFETY_MARGIN_MS); scheduledExecutorService, PARTIAL_WAKE_LOCK, tag,
LOCK_DURATION_MS, SAFETY_MARGIN_MS);
} }
@Override @Override
public AndroidWakeLock createWakeLock() { public AndroidWakeLock createWakeLock(String tag) {
return new AndroidWakeLockImpl(sharedWakeLock); return new AndroidWakeLockImpl(sharedWakeLock, tag);
}
@Override
public void runWakefully(Runnable r, String tag) {
AndroidWakeLock wakeLock = createWakeLock(tag);
wakeLock.acquire();
try {
r.run();
} finally {
wakeLock.release();
}
}
@Override
public void executeWakefully(Runnable r, Executor executor, String tag) {
AndroidWakeLock wakeLock = createWakeLock(tag);
wakeLock.acquire();
try {
executor.execute(() -> {
try {
r.run();
} finally {
// Release the wake lock if the task throws an exception
wakeLock.release();
}
});
} catch (Exception e) {
// Release the wake lock if the executor throws an exception when
// we submit the task (in which case the release() call above won't
// happen)
wakeLock.release();
throw e;
}
} }
private String getWakeLockTag(Context ctx) { private String getWakeLockTag(Context ctx) {

View File

@@ -4,9 +4,9 @@ import android.os.PowerManager;
import android.os.PowerManager.WakeLock; import android.os.PowerManager.WakeLock;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.TaskScheduler;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -14,6 +14,7 @@ import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; import static java.util.logging.Logger.getLogger;
@@ -27,7 +28,7 @@ class RenewableWakeLock implements SharedWakeLock {
getLogger(RenewableWakeLock.class.getName()); getLogger(RenewableWakeLock.class.getName());
private final PowerManager powerManager; private final PowerManager powerManager;
private final TaskScheduler scheduler; private final ScheduledExecutorService scheduledExecutorService;
private final int levelAndFlags; private final int levelAndFlags;
private final String tag; private final String tag;
private final long durationMs, safetyMarginMs; private final long durationMs, safetyMarginMs;
@@ -44,11 +45,14 @@ class RenewableWakeLock implements SharedWakeLock {
@GuardedBy("lock") @GuardedBy("lock")
private long acquired = 0; private long acquired = 0;
RenewableWakeLock(PowerManager powerManager, TaskScheduler scheduler, RenewableWakeLock(PowerManager powerManager,
int levelAndFlags, String tag, long durationMs, ScheduledExecutorService scheduledExecutorService,
int levelAndFlags,
String tag,
long durationMs,
long safetyMarginMs) { long safetyMarginMs) {
this.powerManager = powerManager; this.powerManager = powerManager;
this.scheduler = scheduler; this.scheduledExecutorService = scheduledExecutorService;
this.levelAndFlags = levelAndFlags; this.levelAndFlags = levelAndFlags;
this.tag = tag; this.tag = tag;
this.durationMs = durationMs; this.durationMs = durationMs;
@@ -69,9 +73,11 @@ class RenewableWakeLock implements SharedWakeLock {
// power management apps // power management apps
wakeLock.setReferenceCounted(false); wakeLock.setReferenceCounted(false);
wakeLock.acquire(durationMs + safetyMarginMs); wakeLock.acquire(durationMs + safetyMarginMs);
future = scheduler.schedule(this::renew, durationMs, future = scheduledExecutorService.schedule(this::renew,
MILLISECONDS); durationMs, MILLISECONDS);
acquired = android.os.SystemClock.elapsedRealtime(); acquired = android.os.SystemClock.elapsedRealtime();
} else if (LOG.isLoggable(FINE)) {
LOG.fine("Wake lock " + tag + " has " + refCount + " holders");
} }
} }
} }
@@ -83,6 +89,9 @@ class RenewableWakeLock implements SharedWakeLock {
LOG.info("Already released"); LOG.info("Already released");
return; return;
} }
if (LOG.isLoggable(FINE)) {
LOG.fine("Wake lock " + tag + " has " + refCount + " holders");
}
long now = android.os.SystemClock.elapsedRealtime(); long now = android.os.SystemClock.elapsedRealtime();
long expiry = acquired + durationMs + safetyMarginMs; long expiry = acquired + durationMs + safetyMarginMs;
if (now > expiry && LOG.isLoggable(WARNING)) { if (now > expiry && LOG.isLoggable(WARNING)) {
@@ -93,7 +102,8 @@ class RenewableWakeLock implements SharedWakeLock {
wakeLock.setReferenceCounted(false); wakeLock.setReferenceCounted(false);
wakeLock.acquire(durationMs + safetyMarginMs); wakeLock.acquire(durationMs + safetyMarginMs);
oldWakeLock.release(); oldWakeLock.release();
future = scheduler.schedule(this::renew, durationMs, MILLISECONDS); future = scheduledExecutorService.schedule(this::renew, durationMs,
MILLISECONDS);
acquired = now; acquired = now;
} }
} }
@@ -111,6 +121,8 @@ class RenewableWakeLock implements SharedWakeLock {
requireNonNull(wakeLock).release(); requireNonNull(wakeLock).release();
wakeLock = null; wakeLock = null;
acquired = 0; acquired = 0;
} else if (LOG.isLoggable(FINE)) {
LOG.fine("Wake lock " + tag + " has " + refCount + " holders");
} }
} }
} }

View File

@@ -2,27 +2,27 @@ package org.briarproject.bramble.api.system;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.concurrent.Executor;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
* A service that can be used to schedule the execution of tasks. * A service that can be used to schedule the execution of tasks.
* <p>
* The service should only be used for running tasks on other executors
* at scheduled times. No significant work should be run by the service itself.
*/ */
@NotNullByDefault @NotNullByDefault
public interface TaskScheduler { public interface TaskScheduler {
/** /**
* See {@link ScheduledExecutorService#schedule(Runnable, long, TimeUnit)}. * Submits the given task to the given executor after the given delay.
*/ */
Future<?> schedule(Runnable task, long delay, TimeUnit unit); Future<?> schedule(Runnable task, Executor executor, long delay,
TimeUnit unit);
/** /**
* See {@link ScheduledExecutorService#scheduleWithFixedDelay(Runnable, long, long, TimeUnit)}. * 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).
*/ */
Future<?> scheduleWithFixedDelay(Runnable task, long delay, Future<?> scheduleWithFixedDelay(Runnable task, Executor executor,
long interval, TimeUnit unit); long delay, long interval, TimeUnit unit);
} }

View File

@@ -55,7 +55,8 @@ class TimeoutMonitorImpl implements TimeoutMonitor {
synchronized (lock) { synchronized (lock) {
if (streams.isEmpty()) { if (streams.isEmpty()) {
task = scheduler.scheduleWithFixedDelay(this::checkTimeouts, task = scheduler.scheduleWithFixedDelay(this::checkTimeouts,
CHECK_INTERVAL_MS, CHECK_INTERVAL_MS, MILLISECONDS); ioExecutor, CHECK_INTERVAL_MS, CHECK_INTERVAL_MS,
MILLISECONDS);
} }
streams.add(stream); streams.add(stream);
} }
@@ -73,23 +74,21 @@ class TimeoutMonitorImpl implements TimeoutMonitor {
if (toCancel != null) toCancel.cancel(false); if (toCancel != null) toCancel.cancel(false);
} }
// Scheduler @IoExecutor
private void checkTimeouts() { private void checkTimeouts() {
ioExecutor.execute(() -> { List<TimeoutInputStream> snapshot;
List<TimeoutInputStream> snapshot; synchronized (lock) {
synchronized (lock) { snapshot = new ArrayList<>(streams);
snapshot = new ArrayList<>(streams); }
} for (TimeoutInputStream stream : snapshot) {
for (TimeoutInputStream stream : snapshot) { if (stream.hasTimedOut()) {
if (stream.hasTimedOut()) { LOG.info("Input stream has timed out");
LOG.info("Input stream has timed out"); try {
try { stream.close();
stream.close(); } catch (IOException e) {
} catch (IOException e) { logException(LOG, INFO, e);
logException(LOG, INFO, e);
}
} }
} }
}); }
} }
} }

View File

@@ -118,6 +118,7 @@ class PollerImpl implements Poller, EventListener {
} }
} }
// TODO: Make this wakeful
private void connectToContact(ContactId c) { private void connectToContact(ContactId c) {
for (SimplexPlugin s : pluginManager.getSimplexPlugins()) for (SimplexPlugin s : pluginManager.getSimplexPlugins())
if (s.shouldPoll()) connectToContact(c, s); if (s.shouldPoll()) connectToContact(c, s);
@@ -189,8 +190,8 @@ class PollerImpl implements Poller, EventListener {
// it will abort safely when it finds it's been replaced // it will abort safely when it finds it's been replaced
if (scheduled != null) scheduled.future.cancel(false); if (scheduled != null) scheduled.future.cancel(false);
PollTask task = new PollTask(p, due, randomiseNext); PollTask task = new PollTask(p, due, randomiseNext);
Future<?> future = scheduler.schedule(() -> Future<?> future = scheduler.schedule(task, ioExecutor, delay,
ioExecutor.execute(task), delay, MILLISECONDS); MILLISECONDS);
tasks.put(t, new ScheduledPollTask(task, future)); tasks.put(t, new ScheduledPollTask(task, future));
} }
} finally { } finally {
@@ -233,9 +234,9 @@ class PollerImpl implements Poller, EventListener {
private class ScheduledPollTask { private class ScheduledPollTask {
private final PollTask task; private final PollTask task;
private final Future future; private final Future<?> future;
private ScheduledPollTask(PollTask task, Future future) { private ScheduledPollTask(PollTask task, Future<?> future) {
this.task = task; this.task = task;
this.future = future; this.future = future;
} }

View File

@@ -143,8 +143,8 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
} catch (DbException e) { } catch (DbException e) {
throw new ServiceException(e); throw new ServiceException(e);
} }
scheduler.scheduleWithFixedDelay(this::poll, POLLING_INTERVAL_MS, scheduler.scheduleWithFixedDelay(this::poll, worker,
POLLING_INTERVAL_MS, MILLISECONDS); POLLING_INTERVAL_MS, POLLING_INTERVAL_MS, MILLISECONDS);
} }
@EventExecutor @EventExecutor
@@ -204,12 +204,10 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
return plugin.createRendezvousEndpoint(k, cs.alice, h); return plugin.createRendezvousEndpoint(k, cs.alice, h);
} }
// Scheduler // Worker
private void poll() { private void poll() {
worker.execute(() -> { removeExpiredPendingContacts();
removeExpiredPendingContacts(); for (PluginState ps : pluginStates.values()) poll(ps);
for (PluginState ps : pluginStates.values()) poll(ps);
});
} }
// Worker // Worker

View File

@@ -3,6 +3,7 @@ package org.briarproject.bramble.system;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.TaskScheduler; import org.briarproject.bramble.api.system.TaskScheduler;
import java.util.concurrent.Executor;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -10,27 +11,30 @@ import java.util.concurrent.TimeUnit;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
/** /**
* A {@link TaskScheduler} that delegates all calls to a * A {@link TaskScheduler} that uses a {@link ScheduledExecutorService}.
* {@link ScheduledExecutorService}.
*/ */
@ThreadSafe @ThreadSafe
@NotNullByDefault @NotNullByDefault
class TaskSchedulerImpl implements TaskScheduler { class TaskSchedulerImpl implements TaskScheduler {
private final ScheduledExecutorService delegate; private final ScheduledExecutorService scheduledExecutorService;
TaskSchedulerImpl(ScheduledExecutorService delegate) { TaskSchedulerImpl(ScheduledExecutorService scheduledExecutorService) {
this.delegate = delegate; this.scheduledExecutorService = scheduledExecutorService;
} }
@Override @Override
public Future<?> schedule(Runnable task, long delay, TimeUnit unit) { public Future<?> schedule(Runnable task, Executor executor, long delay,
return delegate.schedule(task, delay, unit); TimeUnit unit) {
Runnable execute = () -> executor.execute(task);
return scheduledExecutorService.schedule(execute, delay, unit);
} }
@Override @Override
public Future<?> scheduleWithFixedDelay(Runnable task, long delay, public Future<?> scheduleWithFixedDelay(Runnable task, Executor executor,
long interval, TimeUnit unit) { long delay, long interval, TimeUnit unit) {
return delegate.scheduleWithFixedDelay(task, delay, interval, unit); Runnable execute = () -> executor.execute(task);
return scheduledExecutorService.scheduleWithFixedDelay(execute, delay,
interval, unit);
} }
} }

View File

@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.crypto.TransportCrypto; import org.briarproject.bramble.api.crypto.TransportCrypto;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -198,17 +199,16 @@ class TransportKeyManagerImpl implements TransportKeyManager {
private void scheduleKeyUpdate(long now) { private void scheduleKeyUpdate(long now) {
long delay = timePeriodLength - now % timePeriodLength; long delay = timePeriodLength - now % timePeriodLength;
scheduler.schedule(this::updateKeys, delay, MILLISECONDS); scheduler.schedule(this::updateKeys, dbExecutor, delay, MILLISECONDS);
} }
@DatabaseExecutor
private void updateKeys() { private void updateKeys() {
dbExecutor.execute(() -> { try {
try { db.transaction(false, this::updateKeys);
db.transaction(false, this::updateKeys); } catch (DbException e) {
} catch (DbException e) { logException(LOG, WARNING, e);
logException(LOG, WARNING, e); }
}
});
} }
@Override @Override

View File

@@ -234,7 +234,8 @@ public class PollerImplTest extends BrambleMockTestCase {
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(now)); will(returnValue(now));
oneOf(scheduler).schedule(with(any(Runnable.class)), oneOf(scheduler).schedule(with(any(Runnable.class)),
with((long) pollingInterval), with(MILLISECONDS)); with(ioExecutor), with((long) pollingInterval),
with(MILLISECONDS));
will(returnValue(future)); will(returnValue(future));
}}); }});
@@ -262,7 +263,8 @@ public class PollerImplTest extends BrambleMockTestCase {
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(now)); will(returnValue(now));
oneOf(scheduler).schedule(with(any(Runnable.class)), oneOf(scheduler).schedule(with(any(Runnable.class)),
with((long) pollingInterval), with(MILLISECONDS)); with(ioExecutor), with((long) pollingInterval),
with(MILLISECONDS));
will(returnValue(future)); will(returnValue(future));
// Second event // Second event
// Get the plugin // Get the plugin
@@ -304,7 +306,8 @@ public class PollerImplTest extends BrambleMockTestCase {
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(now)); will(returnValue(now));
oneOf(scheduler).schedule(with(any(Runnable.class)), oneOf(scheduler).schedule(with(any(Runnable.class)),
with((long) pollingInterval), with(MILLISECONDS)); with(ioExecutor), with((long) pollingInterval),
with(MILLISECONDS));
will(returnValue(future)); will(returnValue(future));
// Second event // Second event
// Get the plugin // Get the plugin
@@ -320,7 +323,8 @@ public class PollerImplTest extends BrambleMockTestCase {
will(returnValue(now + 1)); will(returnValue(now + 1));
oneOf(future).cancel(false); oneOf(future).cancel(false);
oneOf(scheduler).schedule(with(any(Runnable.class)), oneOf(scheduler).schedule(with(any(Runnable.class)),
with((long) pollingInterval - 2), with(MILLISECONDS)); with(ioExecutor), with((long) pollingInterval - 2),
with(MILLISECONDS));
}}); }});
poller.eventOccurred(new ConnectionOpenedEvent(contactId, transportId, poller.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
@@ -345,8 +349,8 @@ public class PollerImplTest extends BrambleMockTestCase {
// Schedule a polling task immediately // Schedule a polling task immediately
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(now)); will(returnValue(now));
oneOf(scheduler).schedule(with(any(Runnable.class)), with(0L), oneOf(scheduler).schedule(with(any(Runnable.class)),
with(MILLISECONDS)); with(ioExecutor), with(0L), with(MILLISECONDS));
will(returnValue(future)); will(returnValue(future));
will(new RunAction()); will(new RunAction());
// Running the polling task schedules the next polling task // Running the polling task schedules the next polling task
@@ -357,7 +361,8 @@ public class PollerImplTest extends BrambleMockTestCase {
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(now)); will(returnValue(now));
oneOf(scheduler).schedule(with(any(Runnable.class)), oneOf(scheduler).schedule(with(any(Runnable.class)),
with((long) (pollingInterval * 0.5)), with(MILLISECONDS)); with(ioExecutor), with((long) (pollingInterval * 0.5)),
with(MILLISECONDS));
will(returnValue(future)); will(returnValue(future));
// Get the transport properties and connected contacts // Get the transport properties and connected contacts
oneOf(transportPropertyManager).getRemoteProperties(transportId); oneOf(transportPropertyManager).getRemoteProperties(transportId);
@@ -388,8 +393,8 @@ public class PollerImplTest extends BrambleMockTestCase {
// Schedule a polling task immediately // Schedule a polling task immediately
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(now)); will(returnValue(now));
oneOf(scheduler).schedule(with(any(Runnable.class)), with(0L), oneOf(scheduler).schedule(with(any(Runnable.class)),
with(MILLISECONDS)); with(ioExecutor), with(0L), with(MILLISECONDS));
will(returnValue(future)); will(returnValue(future));
will(new RunAction()); will(new RunAction());
// Running the polling task schedules the next polling task // Running the polling task schedules the next polling task
@@ -400,7 +405,8 @@ public class PollerImplTest extends BrambleMockTestCase {
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(now)); will(returnValue(now));
oneOf(scheduler).schedule(with(any(Runnable.class)), oneOf(scheduler).schedule(with(any(Runnable.class)),
with((long) (pollingInterval * 0.5)), with(MILLISECONDS)); with(ioExecutor), with((long) (pollingInterval * 0.5)),
with(MILLISECONDS));
will(returnValue(future)); will(returnValue(future));
// Get the transport properties and connected contacts // Get the transport properties and connected contacts
oneOf(transportPropertyManager).getRemoteProperties(transportId); oneOf(transportPropertyManager).getRemoteProperties(transportId);
@@ -429,8 +435,8 @@ public class PollerImplTest extends BrambleMockTestCase {
// Schedule a polling task immediately // Schedule a polling task immediately
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(now)); will(returnValue(now));
oneOf(scheduler).schedule(with(any(Runnable.class)), with(0L), oneOf(scheduler).schedule(with(any(Runnable.class)),
with(MILLISECONDS)); with(ioExecutor), with(0L), with(MILLISECONDS));
will(returnValue(future)); will(returnValue(future));
// The plugin is deactivated before the task runs - cancel the task // The plugin is deactivated before the task runs - cancel the task
oneOf(future).cancel(false); oneOf(future).cancel(false);
@@ -454,7 +460,8 @@ public class PollerImplTest extends BrambleMockTestCase {
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(now)); will(returnValue(now));
oneOf(scheduler).schedule(with(any(Runnable.class)), oneOf(scheduler).schedule(with(any(Runnable.class)),
with((long) pollingInterval), with(MILLISECONDS)); with(ioExecutor), with((long) pollingInterval),
with(MILLISECONDS));
will(returnValue(future)); will(returnValue(future));
}}); }});
} }

View File

@@ -123,8 +123,8 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
e.getPendingContactState() == OFFLINE))); e.getPendingContactState() == OFFLINE)));
// Capture the poll task // Capture the poll task
oneOf(scheduler).scheduleWithFixedDelay(with(any(Runnable.class)), oneOf(scheduler).scheduleWithFixedDelay(with(any(Runnable.class)),
with(POLLING_INTERVAL_MS), with(POLLING_INTERVAL_MS), with(any(Executor.class)), with(POLLING_INTERVAL_MS),
with(MILLISECONDS)); with(POLLING_INTERVAL_MS), with(MILLISECONDS));
will(new CaptureArgumentAction<>(capturePollTask, Runnable.class, will(new CaptureArgumentAction<>(capturePollTask, Runnable.class,
0)); 0));
}}); }});
@@ -159,8 +159,8 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
e.getPendingContactState() == FAILED))); e.getPendingContactState() == FAILED)));
// Schedule the poll task // Schedule the poll task
oneOf(scheduler).scheduleWithFixedDelay(with(any(Runnable.class)), oneOf(scheduler).scheduleWithFixedDelay(with(any(Runnable.class)),
with(POLLING_INTERVAL_MS), with(POLLING_INTERVAL_MS), with(any(Executor.class)), with(POLLING_INTERVAL_MS),
with(MILLISECONDS)); with(POLLING_INTERVAL_MS), with(MILLISECONDS));
}}); }});
rendezvousPoller.startService(); rendezvousPoller.startService();
@@ -468,8 +468,8 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
will(returnValue(emptyList())); will(returnValue(emptyList()));
// Capture the poll task // Capture the poll task
oneOf(scheduler).scheduleWithFixedDelay(with(any(Runnable.class)), oneOf(scheduler).scheduleWithFixedDelay(with(any(Runnable.class)),
with(POLLING_INTERVAL_MS), with(POLLING_INTERVAL_MS), with(any(Executor.class)), with(POLLING_INTERVAL_MS),
with(MILLISECONDS)); with(POLLING_INTERVAL_MS), with(MILLISECONDS));
will(new CaptureArgumentAction<>(capturePollTask, Runnable.class, will(new CaptureArgumentAction<>(capturePollTask, Runnable.class,
0)); 0));
}}); }});
@@ -545,8 +545,8 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
e.getPendingContactState() == OFFLINE))); e.getPendingContactState() == OFFLINE)));
// Capture the poll task // Capture the poll task
oneOf(scheduler).scheduleWithFixedDelay(with(any(Runnable.class)), oneOf(scheduler).scheduleWithFixedDelay(with(any(Runnable.class)),
with(POLLING_INTERVAL_MS), with(POLLING_INTERVAL_MS), with(any(Executor.class)), with(POLLING_INTERVAL_MS),
with(MILLISECONDS)); with(POLLING_INTERVAL_MS), with(MILLISECONDS));
will(new CaptureArgumentAction<>(capturePollTask, Runnable.class, will(new CaptureArgumentAction<>(capturePollTask, Runnable.class,
0)); 0));
}}); }});

View File

@@ -117,7 +117,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
new TransportKeySet(keySetId, contactId, null, updated))); new TransportKeySet(keySetId, contactId, null, updated)));
// Schedule a key update at the start of the next time period // Schedule a key update at the start of the next time period
oneOf(scheduler).schedule(with(any(Runnable.class)), oneOf(scheduler).schedule(with(any(Runnable.class)),
with(timePeriodLength - 1), with(MILLISECONDS)); with(dbExecutor), with(timePeriodLength - 1),
with(MILLISECONDS));
}}); }});
transportKeyManager.start(txn); transportKeyManager.start(txn);
@@ -420,9 +421,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
} }
// Schedule a key update at the start of the next time period // Schedule a key update at the start of the next time period
oneOf(scheduler).schedule(with(any(Runnable.class)), oneOf(scheduler).schedule(with(any(Runnable.class)),
with(timePeriodLength), with(MILLISECONDS)); with(dbExecutor), with(timePeriodLength),
will(new RunAction()); with(MILLISECONDS));
oneOf(dbExecutor).execute(with(any(Runnable.class)));
will(new RunAction()); will(new RunAction());
// Start a transaction for updating keys // Start a transaction for updating keys
oneOf(db).transaction(with(false), withDbRunnable(txn1)); oneOf(db).transaction(with(false), withDbRunnable(txn1));
@@ -445,7 +445,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
new TransportKeySet(keySetId, contactId, null, updated))); new TransportKeySet(keySetId, contactId, null, updated)));
// Schedule a key update at the start of the next time period // Schedule a key update at the start of the next time period
oneOf(scheduler).schedule(with(any(Runnable.class)), oneOf(scheduler).schedule(with(any(Runnable.class)),
with(timePeriodLength), with(MILLISECONDS)); with(dbExecutor), with(timePeriodLength),
with(MILLISECONDS));
}}); }});
transportKeyManager.start(txn); transportKeyManager.start(txn);

View File

@@ -28,7 +28,7 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory; import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
import org.briarproject.bramble.api.reporting.DevConfig; import org.briarproject.bramble.api.reporting.DevConfig;
import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.AndroidWakeLockFactory; import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils; import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider; import org.briarproject.bramble.api.system.ResourceProvider;
@@ -135,17 +135,17 @@ public class AppModule {
ResourceProvider resourceProvider, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, CircumventionProvider circumventionProvider,
BatteryManager batteryManager, BatteryManager batteryManager,
AndroidWakeLockFactory wakeLockFactory, AndroidWakeLockManager wakeLockManager,
Clock clock, Clock clock,
TimeoutMonitor timeoutMonitor) { TimeoutMonitor timeoutMonitor) {
Context appContext = app.getApplicationContext(); Context appContext = app.getApplicationContext();
DuplexPluginFactory bluetooth = new AndroidBluetoothPluginFactory( DuplexPluginFactory bluetooth = new AndroidBluetoothPluginFactory(
ioExecutor, androidExecutor, wakeLockFactory, appContext, ioExecutor, androidExecutor, wakeLockManager, appContext,
random, eventBus, clock, timeoutMonitor, backoffFactory); random, eventBus, clock, timeoutMonitor, backoffFactory);
DuplexPluginFactory tor = new AndroidTorPluginFactory(ioExecutor, DuplexPluginFactory tor = new AndroidTorPluginFactory(ioExecutor,
appContext, networkManager, locationUtils, eventBus, appContext, networkManager, locationUtils, eventBus,
torSocketFactory, backoffFactory, resourceProvider, torSocketFactory, backoffFactory, resourceProvider,
circumventionProvider, batteryManager, wakeLockFactory, clock); circumventionProvider, batteryManager, wakeLockManager, clock);
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor, DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
eventBus, backoffFactory, appContext); eventBus, backoffFactory, appContext);
Collection<DuplexPluginFactory> duplex = asList(bluetooth, tor, lan); Collection<DuplexPluginFactory> duplex = asList(bluetooth, tor, lan);

View File

@@ -146,9 +146,8 @@ class FeedManagerImpl implements FeedManager, EventListener, OpenDatabaseHook,
private void startFeedExecutor() { private void startFeedExecutor() {
if (fetcherStarted.getAndSet(true)) return; if (fetcherStarted.getAndSet(true)) return;
LOG.info("Tor started, scheduling RSS feed fetcher"); LOG.info("Tor started, scheduling RSS feed fetcher");
Runnable fetcher = () -> ioExecutor.execute(this::fetchFeeds); scheduler.scheduleWithFixedDelay(this::fetchFeeds, ioExecutor,
scheduler.scheduleWithFixedDelay(fetcher, FETCH_DELAY_INITIAL, FETCH_DELAY_INITIAL, FETCH_INTERVAL, FETCH_UNIT);
FETCH_INTERVAL, FETCH_UNIT);
} }
@Override @Override
@@ -471,6 +470,7 @@ class FeedManagerImpl implements FeedManager, EventListener, OpenDatabaseHook,
if (date == null) time = now; if (date == null) time = now;
else time = Math.max(0, Math.min(date.getTime(), now)); else time = Math.max(0, Math.min(date.getTime(), now));
String text = getPostText(b.toString()); String text = getPostText(b.toString());
//noinspection TryWithIdenticalCatches
try { try {
// create and store post // create and store post
LocalAuthor localAuthor = feed.getLocalAuthor(); LocalAuthor localAuthor = feed.getLocalAuthor();