From d794777eb2b91ae87e737b365ac7ba80f3a28a55 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 4 Aug 2020 12:47:35 +0100 Subject: [PATCH 1/8] Refactor wake lock creation. --- .../bramble/api/system/AndroidWakeLock.java | 19 ++++++++ .../api/system/AndroidWakeLockFactory.java | 16 +++++++ .../AndroidBluetoothConnectionFactory.java | 36 +++++++++++++++ .../bluetooth/AndroidBluetoothPlugin.java | 22 +++------- .../AndroidBluetoothPluginFactory.java | 18 +++++--- .../AndroidBluetoothTransportConnection.java | 21 +++------ .../bramble/plugin/tor/AndroidTorPlugin.java | 18 +++----- .../plugin/tor/AndroidTorPluginFactory.java | 14 +++--- .../bramble/system/AndroidSystemModule.java | 7 +++ .../system/AndroidWakeLockFactoryImpl.java | 44 +++++++++++++++++++ .../{util => system}/RenewableWakeLock.java | 15 ++++--- .../bluetooth/BluetoothConnectionFactory.java | 14 ++++++ .../plugin/bluetooth/BluetoothPlugin.java | 17 ++++--- .../JavaBluetoothConnectionFactory.java | 34 ++++++++++++++ .../plugin/bluetooth/JavaBluetoothPlugin.java | 21 ++++----- .../bluetooth/JavaBluetoothPluginFactory.java | 6 ++- .../JavaBluetoothTransportConnection.java | 12 ++--- .../briarproject/briar/android/AppModule.java | 12 ++--- 18 files changed, 248 insertions(+), 98 deletions(-) create mode 100644 bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLock.java create mode 100644 bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLockFactory.java create mode 100644 bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothConnectionFactory.java create mode 100644 bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java rename bramble-android/src/main/java/org/briarproject/bramble/{util => system}/RenewableWakeLock.java (85%) create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothConnectionFactory.java create mode 100644 bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothConnectionFactory.java diff --git a/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLock.java b/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLock.java new file mode 100644 index 000000000..307a86086 --- /dev/null +++ b/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLock.java @@ -0,0 +1,19 @@ +package org.briarproject.bramble.api.system; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +@NotNullByDefault +public interface AndroidWakeLock { + + /** + * Acquires the wake lock. This has no effect if the wake lock has already + * been acquired. + */ + void acquire(); + + /** + * Releases the wake lock. This has no effect if the wake lock has already + * been released. + */ + void release(); +} diff --git a/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLockFactory.java b/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLockFactory.java new file mode 100644 index 000000000..d0aa27f04 --- /dev/null +++ b/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLockFactory.java @@ -0,0 +1,16 @@ +package org.briarproject.bramble.api.system; + +import android.os.PowerManager; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +@NotNullByDefault +public interface AndroidWakeLockFactory { + + /** + * Creates and returns a wake lock. + * + * @param levelAndFlags See {@link PowerManager#newWakeLock(int, String)} + */ + AndroidWakeLock createWakeLock(int levelAndFlags); +} diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothConnectionFactory.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothConnectionFactory.java new file mode 100644 index 000000000..61d543414 --- /dev/null +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothConnectionFactory.java @@ -0,0 +1,36 @@ +package org.briarproject.bramble.plugin.bluetooth; + +import android.bluetooth.BluetoothSocket; + +import org.briarproject.bramble.api.io.TimeoutMonitor; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin; +import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; +import org.briarproject.bramble.api.system.AndroidWakeLockFactory; + +import java.io.IOException; + +@NotNullByDefault +class AndroidBluetoothConnectionFactory + implements BluetoothConnectionFactory { + + private final BluetoothConnectionLimiter connectionLimiter; + private final AndroidWakeLockFactory wakeLockFactory; + private final TimeoutMonitor timeoutMonitor; + + AndroidBluetoothConnectionFactory( + BluetoothConnectionLimiter connectionLimiter, + AndroidWakeLockFactory wakeLockFactory, + TimeoutMonitor timeoutMonitor) { + this.connectionLimiter = connectionLimiter; + this.wakeLockFactory = wakeLockFactory; + this.timeoutMonitor = timeoutMonitor; + } + + @Override + public DuplexTransportConnection wrapSocket(DuplexPlugin plugin, + BluetoothSocket s) throws IOException { + return new AndroidBluetoothTransportConnection(plugin, + connectionLimiter, wakeLockFactory, timeoutMonitor, s); + } +} diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPlugin.java index 5c51b4c61..68df9233a 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPlugin.java @@ -9,7 +9,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import org.briarproject.bramble.api.io.TimeoutMonitor; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.plugin.Backoff; @@ -18,7 +17,6 @@ import org.briarproject.bramble.api.plugin.PluginException; import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.bramble.api.system.Clock; -import org.briarproject.bramble.api.system.TaskScheduler; import org.briarproject.bramble.util.AndroidUtils; import org.briarproject.bramble.util.IoUtils; @@ -60,14 +58,14 @@ import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress; @MethodsNotNullByDefault @ParametersNotNullByDefault -class AndroidBluetoothPlugin extends BluetoothPlugin { +class AndroidBluetoothPlugin + extends BluetoothPlugin { private static final Logger LOG = getLogger(AndroidBluetoothPlugin.class.getName()); private static final int MAX_DISCOVERY_MS = 10_000; - private final TaskScheduler scheduler; private final AndroidExecutor androidExecutor; private final Context appContext; private final Clock clock; @@ -79,10 +77,9 @@ class AndroidBluetoothPlugin extends BluetoothPlugin { private volatile BluetoothAdapter adapter = null; AndroidBluetoothPlugin(BluetoothConnectionLimiter connectionLimiter, - TimeoutMonitor timeoutMonitor, + BluetoothConnectionFactory connectionFactory, Executor ioExecutor, SecureRandom secureRandom, - TaskScheduler scheduler, AndroidExecutor androidExecutor, Context appContext, Clock clock, @@ -90,9 +87,8 @@ class AndroidBluetoothPlugin extends BluetoothPlugin { PluginCallback callback, int maxLatency, int maxIdleTime) { - super(connectionLimiter, timeoutMonitor, ioExecutor, secureRandom, + super(connectionLimiter, connectionFactory, ioExecutor, secureRandom, backoff, callback, maxLatency, maxIdleTime); - this.scheduler = scheduler; this.androidExecutor = androidExecutor; this.appContext = appContext; this.clock = clock; @@ -187,13 +183,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin { @Override DuplexTransportConnection acceptConnection(BluetoothServerSocket ss) throws IOException { - return wrapSocket(ss.accept()); - } - - private DuplexTransportConnection wrapSocket(BluetoothSocket s) - throws IOException { - return new AndroidBluetoothTransportConnection(this, connectionLimiter, - timeoutMonitor, appContext, scheduler, s); + return connectionFactory.wrapSocket(this, ss.accept()); } @Override @@ -210,7 +200,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin { try { s = d.createInsecureRfcommSocketToServiceRecord(u); s.connect(); - return wrapSocket(s); + return connectionFactory.wrapSocket(this, s); } catch (IOException e) { IoUtils.tryToClose(s, LOG, WARNING); throw e; diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPluginFactory.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPluginFactory.java index 265a98339..590117345 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPluginFactory.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPluginFactory.java @@ -1,5 +1,6 @@ package org.briarproject.bramble.plugin.bluetooth; +import android.bluetooth.BluetoothSocket; import android.content.Context; import org.briarproject.bramble.api.event.EventBus; @@ -12,8 +13,8 @@ import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory; import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.bramble.api.system.AndroidWakeLockFactory; import org.briarproject.bramble.api.system.Clock; -import org.briarproject.bramble.api.system.TaskScheduler; import java.security.SecureRandom; import java.util.concurrent.Executor; @@ -33,8 +34,8 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory { private static final double BACKOFF_BASE = 1.2; private final Executor ioExecutor; - private final TaskScheduler scheduler; private final AndroidExecutor androidExecutor; + private final AndroidWakeLockFactory wakeLockFactory; private final Context appContext; private final SecureRandom secureRandom; private final EventBus eventBus; @@ -43,8 +44,8 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory { private final BackoffFactory backoffFactory; public AndroidBluetoothPluginFactory(Executor ioExecutor, - TaskScheduler scheduler, AndroidExecutor androidExecutor, + AndroidWakeLockFactory wakeLockFactory, Context appContext, SecureRandom secureRandom, EventBus eventBus, @@ -52,8 +53,8 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory { TimeoutMonitor timeoutMonitor, BackoffFactory backoffFactory) { this.ioExecutor = ioExecutor; - this.scheduler = scheduler; this.androidExecutor = androidExecutor; + this.wakeLockFactory = wakeLockFactory; this.appContext = appContext; this.secureRandom = secureRandom; this.eventBus = eventBus; @@ -76,12 +77,15 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory { public DuplexPlugin createPlugin(PluginCallback callback) { BluetoothConnectionLimiter connectionLimiter = new BluetoothConnectionLimiterImpl(eventBus); + BluetoothConnectionFactory connectionFactory = + new AndroidBluetoothConnectionFactory(connectionLimiter, + wakeLockFactory, timeoutMonitor); Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, MAX_POLLING_INTERVAL, BACKOFF_BASE); AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin( - connectionLimiter, timeoutMonitor, ioExecutor, secureRandom, - scheduler, androidExecutor, appContext, clock, backoff, - callback, MAX_LATENCY, MAX_IDLE_TIME); + connectionLimiter, connectionFactory, ioExecutor, secureRandom, + androidExecutor, appContext, clock, backoff, callback, + MAX_LATENCY, MAX_IDLE_TIME); eventBus.addListener(plugin); return plugin; } diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothTransportConnection.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothTransportConnection.java index 7a82ff8a3..0d2498f25 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothTransportConnection.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothTransportConnection.java @@ -1,26 +1,20 @@ package org.briarproject.bramble.plugin.bluetooth; import android.bluetooth.BluetoothSocket; -import android.content.Context; -import android.os.PowerManager; import org.briarproject.bramble.api.io.TimeoutMonitor; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.Plugin; import org.briarproject.bramble.api.plugin.duplex.AbstractDuplexTransportConnection; -import org.briarproject.bramble.api.system.TaskScheduler; -import org.briarproject.bramble.util.RenewableWakeLock; +import org.briarproject.bramble.api.system.AndroidWakeLock; +import org.briarproject.bramble.api.system.AndroidWakeLockFactory; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import static android.content.Context.POWER_SERVICE; import static android.os.PowerManager.PARTIAL_WAKE_LOCK; -import static java.util.concurrent.TimeUnit.MINUTES; -import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull; import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_ADDRESS; -import static org.briarproject.bramble.util.AndroidUtils.getWakeLockTag; import static org.briarproject.bramble.util.AndroidUtils.isValidBluetoothAddress; @NotNullByDefault @@ -28,26 +22,21 @@ class AndroidBluetoothTransportConnection extends AbstractDuplexTransportConnection { private final BluetoothConnectionLimiter connectionLimiter; - private final RenewableWakeLock wakeLock; private final BluetoothSocket socket; private final InputStream in; + private final AndroidWakeLock wakeLock; AndroidBluetoothTransportConnection(Plugin plugin, BluetoothConnectionLimiter connectionLimiter, + AndroidWakeLockFactory wakeLockFactory, TimeoutMonitor timeoutMonitor, - Context appContext, - TaskScheduler scheduler, BluetoothSocket socket) throws IOException { super(plugin); this.connectionLimiter = connectionLimiter; this.socket = socket; in = timeoutMonitor.createTimeoutInputStream( socket.getInputStream(), plugin.getMaxIdleTime() * 2); - PowerManager powerManager = (PowerManager) - requireNonNull(appContext.getSystemService(POWER_SERVICE)); - String tag = getWakeLockTag(appContext); - wakeLock = new RenewableWakeLock(powerManager, scheduler, - PARTIAL_WAKE_LOCK, tag, 1, MINUTES); + wakeLock = wakeLockFactory.createWakeLock(PARTIAL_WAKE_LOCK); wakeLock.acquire(); String address = socket.getRemoteDevice().getAddress(); if (isValidBluetoothAddress(address)) remote.put(PROP_ADDRESS, address); diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java index 4f8b01b09..2d26a9abf 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java @@ -4,7 +4,6 @@ import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; -import android.os.PowerManager; import org.briarproject.bramble.api.battery.BatteryManager; import org.briarproject.bramble.api.network.NetworkManager; @@ -12,11 +11,11 @@ import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.plugin.Backoff; import org.briarproject.bramble.api.plugin.PluginCallback; +import org.briarproject.bramble.api.system.AndroidWakeLock; +import org.briarproject.bramble.api.system.AndroidWakeLockFactory; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.LocationUtils; import org.briarproject.bramble.api.system.ResourceProvider; -import org.briarproject.bramble.api.system.TaskScheduler; -import org.briarproject.bramble.util.RenewableWakeLock; import java.io.IOException; import java.util.concurrent.Executor; @@ -24,20 +23,16 @@ import java.util.concurrent.Executor; import javax.net.SocketFactory; import static android.content.Context.MODE_PRIVATE; -import static android.content.Context.POWER_SERVICE; import static android.os.PowerManager.PARTIAL_WAKE_LOCK; -import static java.util.concurrent.TimeUnit.MINUTES; -import static org.briarproject.bramble.util.AndroidUtils.getWakeLockTag; @MethodsNotNullByDefault @ParametersNotNullByDefault class AndroidTorPlugin extends TorPlugin { private final Context appContext; - private final RenewableWakeLock wakeLock; + private final AndroidWakeLock wakeLock; AndroidTorPlugin(Executor ioExecutor, - TaskScheduler scheduler, Context appContext, NetworkManager networkManager, LocationUtils locationUtils, @@ -46,6 +41,7 @@ class AndroidTorPlugin extends TorPlugin { ResourceProvider resourceProvider, CircumventionProvider circumventionProvider, BatteryManager batteryManager, + AndroidWakeLockFactory wakeLockFactory, Backoff backoff, TorRendezvousCrypto torRendezvousCrypto, PluginCallback callback, @@ -58,11 +54,7 @@ class AndroidTorPlugin extends TorPlugin { maxLatency, maxIdleTime, appContext.getDir("tor", MODE_PRIVATE)); this.appContext = appContext; - PowerManager pm = (PowerManager) - appContext.getSystemService(POWER_SERVICE); - if (pm == null) throw new AssertionError(); - wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK, - getWakeLockTag(appContext), 1, MINUTES); + wakeLock = wakeLockFactory.createWakeLock(PARTIAL_WAKE_LOCK); } @Override diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPluginFactory.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPluginFactory.java index 71482e1f2..7f477a4d5 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPluginFactory.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPluginFactory.java @@ -13,10 +13,10 @@ import org.briarproject.bramble.api.plugin.TorConstants; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory; +import org.briarproject.bramble.api.system.AndroidWakeLockFactory; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.LocationUtils; import org.briarproject.bramble.api.system.ResourceProvider; -import org.briarproject.bramble.api.system.TaskScheduler; import org.briarproject.bramble.util.AndroidUtils; import java.util.concurrent.Executor; @@ -39,7 +39,6 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory { private static final double BACKOFF_BASE = 1.2; private final Executor ioExecutor; - private final TaskScheduler scheduler; private final Context appContext; private final NetworkManager networkManager; private final LocationUtils locationUtils; @@ -49,10 +48,10 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory { private final ResourceProvider resourceProvider; private final CircumventionProvider circumventionProvider; private final BatteryManager batteryManager; + private final AndroidWakeLockFactory wakeLockFactory; private final Clock clock; public AndroidTorPluginFactory(Executor ioExecutor, - TaskScheduler scheduler, Context appContext, NetworkManager networkManager, LocationUtils locationUtils, @@ -62,9 +61,9 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory { ResourceProvider resourceProvider, CircumventionProvider circumventionProvider, BatteryManager batteryManager, + AndroidWakeLockFactory wakeLockFactory, Clock clock) { this.ioExecutor = ioExecutor; - this.scheduler = scheduler; this.appContext = appContext; this.networkManager = networkManager; this.locationUtils = locationUtils; @@ -74,6 +73,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory { this.resourceProvider = resourceProvider; this.circumventionProvider = circumventionProvider; this.batteryManager = batteryManager; + this.wakeLockFactory = wakeLockFactory; this.clock = clock; } @@ -117,11 +117,11 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory { Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, MAX_POLLING_INTERVAL, BACKOFF_BASE); TorRendezvousCrypto torRendezvousCrypto = new TorRendezvousCryptoImpl(); - AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler, + AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, appContext, networkManager, locationUtils, torSocketFactory, clock, resourceProvider, circumventionProvider, batteryManager, - backoff, torRendezvousCrypto, callback, architecture, - MAX_LATENCY, MAX_IDLE_TIME); + wakeLockFactory, backoff, torRendezvousCrypto, callback, + architecture, MAX_LATENCY, MAX_IDLE_TIME); eventBus.addListener(plugin); return plugin; } diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java index 89bf2a321..deb30e871 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java @@ -2,6 +2,7 @@ package org.briarproject.bramble.system; import org.briarproject.bramble.api.event.EventExecutor; import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.bramble.api.system.AndroidWakeLockFactory; import org.briarproject.bramble.api.system.LocationUtils; import org.briarproject.bramble.api.system.ResourceProvider; import org.briarproject.bramble.api.system.SecureRandomProvider; @@ -47,4 +48,10 @@ public class AndroidSystemModule { ResourceProvider provideResourceProvider(AndroidResourceProvider provider) { return provider; } + + @Provides + AndroidWakeLockFactory provideWakeLockFactory( + AndroidWakeLockFactoryImpl wakeLockFactory) { + return wakeLockFactory; + } } diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java new file mode 100644 index 000000000..15fff8844 --- /dev/null +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java @@ -0,0 +1,44 @@ +package org.briarproject.bramble.system; + +import android.app.Application; +import android.os.PowerManager; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.system.AndroidWakeLock; +import org.briarproject.bramble.api.system.AndroidWakeLockFactory; +import org.briarproject.bramble.api.system.TaskScheduler; + +import javax.annotation.concurrent.Immutable; +import javax.inject.Inject; + +import static android.content.Context.POWER_SERVICE; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.MINUTES; +import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull; +import static org.briarproject.bramble.util.AndroidUtils.getWakeLockTag; + +@Immutable +@NotNullByDefault +class AndroidWakeLockFactoryImpl implements AndroidWakeLockFactory { + + private static final long LOCK_DURATION_MS = MINUTES.toMillis(1); + + private final TaskScheduler scheduler; + private final Application app; + private final PowerManager powerManager; + + @Inject + AndroidWakeLockFactoryImpl(TaskScheduler scheduler, Application app) { + this.scheduler = scheduler; + this.app = app; + powerManager = (PowerManager) + requireNonNull(app.getSystemService(POWER_SERVICE)); + } + + @Override + public AndroidWakeLock createWakeLock(int levelAndFlags) { + String tag = getWakeLockTag(app); + return new RenewableWakeLock(powerManager, scheduler, levelAndFlags, + tag, LOCK_DURATION_MS, MILLISECONDS); + } +} diff --git a/bramble-android/src/main/java/org/briarproject/bramble/util/RenewableWakeLock.java b/bramble-android/src/main/java/org/briarproject/bramble/system/RenewableWakeLock.java similarity index 85% rename from bramble-android/src/main/java/org/briarproject/bramble/util/RenewableWakeLock.java rename to bramble-android/src/main/java/org/briarproject/bramble/system/RenewableWakeLock.java index 68ed14f72..d145a587e 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/util/RenewableWakeLock.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/RenewableWakeLock.java @@ -1,8 +1,9 @@ -package org.briarproject.bramble.util; +package org.briarproject.bramble.system; import android.os.PowerManager; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.system.AndroidWakeLock; import org.briarproject.bramble.api.system.TaskScheduler; import java.util.concurrent.Future; @@ -14,13 +15,14 @@ import javax.annotation.concurrent.ThreadSafe; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.logging.Level.INFO; +import static java.util.logging.Logger.getLogger; @ThreadSafe @NotNullByDefault -public class RenewableWakeLock { +class RenewableWakeLock implements AndroidWakeLock { private static final Logger LOG = - Logger.getLogger(RenewableWakeLock.class.getName()); + getLogger(RenewableWakeLock.class.getName()); /** * Automatically release the lock this many milliseconds after it's due @@ -41,9 +43,8 @@ public class RenewableWakeLock { @Nullable private Future future; // Locking: lock - public RenewableWakeLock(PowerManager powerManager, - TaskScheduler scheduler, int levelAndFlags, String tag, - long duration, TimeUnit timeUnit) { + RenewableWakeLock(PowerManager powerManager, TaskScheduler scheduler, + int levelAndFlags, String tag, long duration, TimeUnit timeUnit) { this.powerManager = powerManager; this.scheduler = scheduler; this.levelAndFlags = levelAndFlags; @@ -52,6 +53,7 @@ public class RenewableWakeLock { renewTask = this::renew; } + @Override public void acquire() { if (LOG.isLoggable(INFO)) LOG.info("Acquiring wake lock " + tag); synchronized (lock) { @@ -82,6 +84,7 @@ public class RenewableWakeLock { } } + @Override public void release() { if (LOG.isLoggable(INFO)) LOG.info("Releasing wake lock " + tag); synchronized (lock) { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothConnectionFactory.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothConnectionFactory.java new file mode 100644 index 000000000..27689f979 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothConnectionFactory.java @@ -0,0 +1,14 @@ +package org.briarproject.bramble.plugin.bluetooth; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin; +import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; + +import java.io.IOException; + +@NotNullByDefault +interface BluetoothConnectionFactory { + + DuplexTransportConnection wrapSocket(DuplexPlugin plugin, S socket) + throws IOException; +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java index 956dc293b..160368152 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java @@ -6,7 +6,6 @@ import org.briarproject.bramble.api.Pair; import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.EventListener; -import org.briarproject.bramble.api.io.TimeoutMonitor; import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection; import org.briarproject.bramble.api.keyagreement.KeyAgreementListener; import org.briarproject.bramble.api.keyagreement.event.KeyAgreementListeningEvent; @@ -70,13 +69,13 @@ import static org.briarproject.bramble.util.StringUtils.macToString; @MethodsNotNullByDefault @ParametersNotNullByDefault -abstract class BluetoothPlugin implements DuplexPlugin, EventListener { +abstract class BluetoothPlugin implements DuplexPlugin, EventListener { private static final Logger LOG = getLogger(BluetoothPlugin.class.getName()); final BluetoothConnectionLimiter connectionLimiter; - final TimeoutMonitor timeoutMonitor; + final BluetoothConnectionFactory connectionFactory; private final Executor ioExecutor; private final SecureRandom secureRandom; @@ -123,11 +122,15 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { abstract DuplexTransportConnection discoverAndConnect(String uuid); BluetoothPlugin(BluetoothConnectionLimiter connectionLimiter, - TimeoutMonitor timeoutMonitor, Executor ioExecutor, - SecureRandom secureRandom, Backoff backoff, - PluginCallback callback, int maxLatency, int maxIdleTime) { + BluetoothConnectionFactory connectionFactory, + Executor ioExecutor, + SecureRandom secureRandom, + Backoff backoff, + PluginCallback callback, + int maxLatency, + int maxIdleTime) { this.connectionLimiter = connectionLimiter; - this.timeoutMonitor = timeoutMonitor; + this.connectionFactory = connectionFactory; this.ioExecutor = ioExecutor; this.secureRandom = secureRandom; this.backoff = backoff; diff --git a/bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothConnectionFactory.java b/bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothConnectionFactory.java new file mode 100644 index 000000000..50f1514f2 --- /dev/null +++ b/bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothConnectionFactory.java @@ -0,0 +1,34 @@ +package org.briarproject.bramble.plugin.bluetooth; + +import org.briarproject.bramble.api.io.TimeoutMonitor; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin; +import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; + +import java.io.IOException; + +import javax.annotation.concurrent.Immutable; +import javax.microedition.io.StreamConnection; + +@Immutable +@NotNullByDefault +class JavaBluetoothConnectionFactory + implements BluetoothConnectionFactory { + + private final BluetoothConnectionLimiter connectionLimiter; + private final TimeoutMonitor timeoutMonitor; + + JavaBluetoothConnectionFactory( + BluetoothConnectionLimiter connectionLimiter, + TimeoutMonitor timeoutMonitor) { + this.connectionLimiter = connectionLimiter; + this.timeoutMonitor = timeoutMonitor; + } + + @Override + public DuplexTransportConnection wrapSocket(DuplexPlugin plugin, + StreamConnection socket) throws IOException { + return new JavaBluetoothTransportConnection(plugin, connectionLimiter, + timeoutMonitor, socket); + } +} diff --git a/bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothPlugin.java b/bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothPlugin.java index ff9b7ee79..9115900ad 100644 --- a/bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothPlugin.java +++ b/bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothPlugin.java @@ -1,6 +1,5 @@ package org.briarproject.bramble.plugin.bluetooth; -import org.briarproject.bramble.api.io.TimeoutMonitor; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.plugin.Backoff; @@ -26,7 +25,8 @@ import static org.briarproject.bramble.util.StringUtils.isValidMac; @MethodsNotNullByDefault @ParametersNotNullByDefault -class JavaBluetoothPlugin extends BluetoothPlugin { +class JavaBluetoothPlugin + extends BluetoothPlugin { private static final Logger LOG = getLogger(JavaBluetoothPlugin.class.getName()); @@ -35,10 +35,10 @@ class JavaBluetoothPlugin extends BluetoothPlugin { private volatile LocalDevice localDevice = null; JavaBluetoothPlugin(BluetoothConnectionLimiter connectionManager, - TimeoutMonitor timeoutMonitor, Executor ioExecutor, - SecureRandom secureRandom, Backoff backoff, + BluetoothConnectionFactory connectionFactory, + Executor ioExecutor, SecureRandom secureRandom, Backoff backoff, PluginCallback callback, int maxLatency, int maxIdleTime) { - super(connectionManager, timeoutMonitor, ioExecutor, secureRandom, + super(connectionManager, connectionFactory, ioExecutor, secureRandom, backoff, callback, maxLatency, maxIdleTime); } @@ -96,7 +96,7 @@ class JavaBluetoothPlugin extends BluetoothPlugin { @Override DuplexTransportConnection acceptConnection(StreamConnectionNotifier ss) throws IOException { - return wrapSocket(ss.acceptAndOpen()); + return connectionFactory.wrapSocket(this, ss.acceptAndOpen()); } @Override @@ -108,7 +108,8 @@ class JavaBluetoothPlugin extends BluetoothPlugin { DuplexTransportConnection connectTo(String address, String uuid) throws IOException { String url = makeUrl(address, uuid); - return wrapSocket((StreamConnection) Connector.open(url)); + StreamConnection s = (StreamConnection) Connector.open(url); + return connectionFactory.wrapSocket(this, s); } @Override @@ -120,10 +121,4 @@ class JavaBluetoothPlugin extends BluetoothPlugin { private String makeUrl(String address, String uuid) { return "btspp://" + address + ":" + uuid + ";name=RFCOMM"; } - - private DuplexTransportConnection wrapSocket(StreamConnection s) - throws IOException { - return new JavaBluetoothTransportConnection(this, connectionLimiter, - timeoutMonitor, s); - } } diff --git a/bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothPluginFactory.java b/bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothPluginFactory.java index c931061cd..4f1bb93fd 100644 --- a/bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothPluginFactory.java +++ b/bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothPluginFactory.java @@ -14,6 +14,7 @@ import java.security.SecureRandom; import java.util.concurrent.Executor; import javax.annotation.concurrent.Immutable; +import javax.microedition.io.StreamConnection; import static org.briarproject.bramble.api.plugin.BluetoothConstants.ID; @@ -57,10 +58,13 @@ public class JavaBluetoothPluginFactory implements DuplexPluginFactory { public DuplexPlugin createPlugin(PluginCallback callback) { BluetoothConnectionLimiter connectionLimiter = new BluetoothConnectionLimiterImpl(eventBus); + BluetoothConnectionFactory connectionFactory = + new JavaBluetoothConnectionFactory(connectionLimiter, + timeoutMonitor); Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, MAX_POLLING_INTERVAL, BACKOFF_BASE); JavaBluetoothPlugin plugin = new JavaBluetoothPlugin(connectionLimiter, - timeoutMonitor, ioExecutor, secureRandom, backoff, callback, + connectionFactory, ioExecutor, secureRandom, backoff, callback, MAX_LATENCY, MAX_IDLE_TIME); eventBus.addListener(plugin); return plugin; diff --git a/bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothTransportConnection.java b/bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothTransportConnection.java index 319d9af76..18f4526ae 100644 --- a/bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothTransportConnection.java +++ b/bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothTransportConnection.java @@ -16,18 +16,18 @@ class JavaBluetoothTransportConnection extends AbstractDuplexTransportConnection { private final BluetoothConnectionLimiter connectionLimiter; - private final StreamConnection stream; + private final StreamConnection socket; private final InputStream in; JavaBluetoothTransportConnection(Plugin plugin, BluetoothConnectionLimiter connectionLimiter, TimeoutMonitor timeoutMonitor, - StreamConnection stream) throws IOException { + StreamConnection socket) throws IOException { super(plugin); this.connectionLimiter = connectionLimiter; - this.stream = stream; + this.socket = socket; in = timeoutMonitor.createTimeoutInputStream( - stream.openInputStream(), plugin.getMaxIdleTime() * 2); + socket.openInputStream(), plugin.getMaxIdleTime() * 2); } @Override @@ -37,13 +37,13 @@ class JavaBluetoothTransportConnection @Override protected OutputStream getOutputStream() throws IOException { - return stream.openOutputStream(); + return socket.openOutputStream(); } @Override protected void closeConnection(boolean exception) throws IOException { try { - stream.close(); + socket.close(); } finally { connectionLimiter.connectionClosed(this); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java b/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java index f16773b4d..b8ba76a9e 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java @@ -28,10 +28,10 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory; import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory; import org.briarproject.bramble.api.reporting.DevConfig; import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.bramble.api.system.AndroidWakeLockFactory; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.LocationUtils; import org.briarproject.bramble.api.system.ResourceProvider; -import org.briarproject.bramble.api.system.TaskScheduler; import org.briarproject.bramble.plugin.bluetooth.AndroidBluetoothPluginFactory; import org.briarproject.bramble.plugin.tcp.AndroidLanTcpPluginFactory; import org.briarproject.bramble.plugin.tor.AndroidTorPluginFactory; @@ -124,7 +124,6 @@ public class AppModule { @Provides PluginConfig providePluginConfig(@IoExecutor Executor ioExecutor, - TaskScheduler scheduler, AndroidExecutor androidExecutor, SecureRandom random, SocketFactory torSocketFactory, @@ -136,16 +135,17 @@ public class AppModule { ResourceProvider resourceProvider, CircumventionProvider circumventionProvider, BatteryManager batteryManager, + AndroidWakeLockFactory wakeLockFactory, Clock clock, TimeoutMonitor timeoutMonitor) { Context appContext = app.getApplicationContext(); DuplexPluginFactory bluetooth = new AndroidBluetoothPluginFactory( - ioExecutor, scheduler, androidExecutor, appContext, random, - eventBus, clock, timeoutMonitor, backoffFactory); + ioExecutor, androidExecutor, wakeLockFactory, appContext, + random, eventBus, clock, timeoutMonitor, backoffFactory); DuplexPluginFactory tor = new AndroidTorPluginFactory(ioExecutor, - scheduler, appContext, networkManager, locationUtils, eventBus, + appContext, networkManager, locationUtils, eventBus, torSocketFactory, backoffFactory, resourceProvider, - circumventionProvider, batteryManager, clock); + circumventionProvider, batteryManager, wakeLockFactory, clock); DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor, eventBus, backoffFactory, appContext); Collection duplex = asList(bluetooth, tor, lan); From adb657a5b69834c29d00f231e89608c21d848c03 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 4 Aug 2020 12:48:15 +0100 Subject: [PATCH 2/8] Ensure we only call openOutputStream() once. --- .../plugin/bluetooth/JavaBluetoothTransportConnection.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothTransportConnection.java b/bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothTransportConnection.java index 18f4526ae..2ac917c7b 100644 --- a/bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothTransportConnection.java +++ b/bramble-java/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothTransportConnection.java @@ -18,6 +18,7 @@ class JavaBluetoothTransportConnection private final BluetoothConnectionLimiter connectionLimiter; private final StreamConnection socket; private final InputStream in; + private final OutputStream out; JavaBluetoothTransportConnection(Plugin plugin, BluetoothConnectionLimiter connectionLimiter, @@ -28,6 +29,7 @@ class JavaBluetoothTransportConnection this.socket = socket; in = timeoutMonitor.createTimeoutInputStream( socket.openInputStream(), plugin.getMaxIdleTime() * 2); + out = socket.openOutputStream(); } @Override @@ -36,8 +38,8 @@ class JavaBluetoothTransportConnection } @Override - protected OutputStream getOutputStream() throws IOException { - return socket.openOutputStream(); + protected OutputStream getOutputStream() { + return out; } @Override From eb6b4aa85056ea99c80332eed2360f377d17747f Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 4 Aug 2020 16:45:08 +0100 Subject: [PATCH 3/8] Move wake lock properties into factory. --- .../system/AndroidWakeLockFactoryImpl.java | 35 +++++++++++++++---- .../bramble/system/RenewableWakeLock.java | 30 +++++++--------- .../bramble/util/AndroidUtils.java | 15 -------- 3 files changed, 41 insertions(+), 39 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java index 15fff8844..0ddb3ed90 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java @@ -1,6 +1,9 @@ package org.briarproject.bramble.system; import android.app.Application; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.os.PowerManager; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; @@ -12,33 +15,53 @@ import javax.annotation.concurrent.Immutable; import javax.inject.Inject; import static android.content.Context.POWER_SERVICE; -import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MINUTES; +import static java.util.concurrent.TimeUnit.SECONDS; import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull; -import static org.briarproject.bramble.util.AndroidUtils.getWakeLockTag; @Immutable @NotNullByDefault class AndroidWakeLockFactoryImpl implements AndroidWakeLockFactory { + /** + * How often to replace the wake lock. + */ private static final long LOCK_DURATION_MS = MINUTES.toMillis(1); + /** + * Automatically release the lock this many milliseconds after it's due + * to have been replaced and released. + */ + private static final long SAFETY_MARGIN_MS = SECONDS.toMillis(10); + private final TaskScheduler scheduler; - private final Application app; private final PowerManager powerManager; + private final String tag; @Inject AndroidWakeLockFactoryImpl(TaskScheduler scheduler, Application app) { this.scheduler = scheduler; - this.app = app; powerManager = (PowerManager) requireNonNull(app.getSystemService(POWER_SERVICE)); + tag = getWakeLockTag(app); } @Override public AndroidWakeLock createWakeLock(int levelAndFlags) { - String tag = getWakeLockTag(app); return new RenewableWakeLock(powerManager, scheduler, levelAndFlags, - tag, LOCK_DURATION_MS, MILLISECONDS); + tag, LOCK_DURATION_MS, SAFETY_MARGIN_MS); + } + + private String getWakeLockTag(Context ctx) { + PackageManager pm = ctx.getPackageManager(); + for (PackageInfo info : pm.getInstalledPackages(0)) { + String name = info.packageName.toLowerCase(); + if (name.startsWith("com.huawei.powergenie")) { + return "LocationManagerService"; + } else if (name.startsWith("com.evenwell.powermonitor")) { + return "AudioIn"; + } + } + return ctx.getPackageName(); } } diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/RenewableWakeLock.java b/bramble-android/src/main/java/org/briarproject/bramble/system/RenewableWakeLock.java index d145a587e..a4cc520f2 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/RenewableWakeLock.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/RenewableWakeLock.java @@ -1,13 +1,13 @@ package org.briarproject.bramble.system; import android.os.PowerManager; +import android.os.PowerManager.WakeLock; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.system.AndroidWakeLock; import org.briarproject.bramble.api.system.TaskScheduler; import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; import java.util.logging.Logger; import javax.annotation.Nullable; @@ -24,33 +24,27 @@ class RenewableWakeLock implements AndroidWakeLock { private static final Logger LOG = getLogger(RenewableWakeLock.class.getName()); - /** - * Automatically release the lock this many milliseconds after it's due - * to have been replaced and released. - */ - private static final int SAFETY_MARGIN_MS = 10_000; - private final PowerManager powerManager; private final TaskScheduler scheduler; private final int levelAndFlags; private final String tag; - private final long durationMs; - private final Runnable renewTask; + private final long durationMs, safetyMarginMs; private final Object lock = new Object(); @Nullable - private PowerManager.WakeLock wakeLock; // Locking: lock + private WakeLock wakeLock; // Locking: lock @Nullable private Future future; // Locking: lock RenewableWakeLock(PowerManager powerManager, TaskScheduler scheduler, - int levelAndFlags, String tag, long duration, TimeUnit timeUnit) { + int levelAndFlags, String tag, long durationMs, + long safetyMarginMs) { this.powerManager = powerManager; this.scheduler = scheduler; this.levelAndFlags = levelAndFlags; this.tag = tag; - durationMs = MILLISECONDS.convert(duration, timeUnit); - renewTask = this::renew; + this.durationMs = durationMs; + this.safetyMarginMs = safetyMarginMs; } @Override @@ -63,8 +57,8 @@ class RenewableWakeLock implements AndroidWakeLock { } wakeLock = powerManager.newWakeLock(levelAndFlags, tag); wakeLock.setReferenceCounted(false); - wakeLock.acquire(durationMs + SAFETY_MARGIN_MS); - future = scheduler.schedule(renewTask, durationMs, MILLISECONDS); + wakeLock.acquire(durationMs + safetyMarginMs); + future = scheduler.schedule(this::renew, durationMs, MILLISECONDS); } } @@ -75,12 +69,12 @@ class RenewableWakeLock implements AndroidWakeLock { LOG.info("Already released"); return; } - PowerManager.WakeLock oldWakeLock = wakeLock; + WakeLock oldWakeLock = wakeLock; wakeLock = powerManager.newWakeLock(levelAndFlags, tag); wakeLock.setReferenceCounted(false); - wakeLock.acquire(durationMs + SAFETY_MARGIN_MS); + wakeLock.acquire(durationMs + safetyMarginMs); oldWakeLock.release(); - future = scheduler.schedule(renewTask, durationMs, MILLISECONDS); + future = scheduler.schedule(this::renew, durationMs, MILLISECONDS); } } diff --git a/bramble-android/src/main/java/org/briarproject/bramble/util/AndroidUtils.java b/bramble-android/src/main/java/org/briarproject/bramble/util/AndroidUtils.java index 00ee3ea19..4d5c8ea13 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/util/AndroidUtils.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/util/AndroidUtils.java @@ -3,8 +3,6 @@ package org.briarproject.bramble.util; import android.annotation.SuppressLint; import android.bluetooth.BluetoothAdapter; import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; import android.os.Build; import android.provider.Settings; @@ -119,17 +117,4 @@ public class AndroidUtils { if (SDK_INT < 24) return new String[] {"image/jpeg", "image/png"}; else return new String[] {"image/jpeg", "image/png", "image/gif"}; } - - public static String getWakeLockTag(Context ctx) { - PackageManager pm = ctx.getPackageManager(); - for (PackageInfo info : pm.getInstalledPackages(0)) { - String name = info.packageName.toLowerCase(); - if (name.startsWith("com.huawei.powergenie")) { - return "LocationManagerService"; - } else if (name.startsWith("com.evenwell.powermonitor")) { - return "AudioIn"; - } - } - return ctx.getPackageName(); - } } From 286f6f492cdfdab055575fd681f9e95b3745f80a Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 4 Aug 2020 17:24:24 +0100 Subject: [PATCH 4/8] Share a single OS wake lock among all holders. --- .../api/system/AndroidWakeLockFactory.java | 9 +--- .../AndroidBluetoothTransportConnection.java | 3 +- .../bramble/plugin/tor/AndroidTorPlugin.java | 3 +- .../system/AndroidWakeLockFactoryImpl.java | 17 +++--- .../bramble/system/AndroidWakeLockImpl.java | 46 ++++++++++++++++ .../bramble/system/RenewableWakeLock.java | 52 +++++++++++-------- .../bramble/system/SharedWakeLock.java | 22 ++++++++ 7 files changed, 110 insertions(+), 42 deletions(-) create mode 100644 bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockImpl.java create mode 100644 bramble-android/src/main/java/org/briarproject/bramble/system/SharedWakeLock.java diff --git a/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLockFactory.java b/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLockFactory.java index d0aa27f04..7d7be15d0 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLockFactory.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLockFactory.java @@ -1,16 +1,9 @@ package org.briarproject.bramble.api.system; -import android.os.PowerManager; - import org.briarproject.bramble.api.nullsafety.NotNullByDefault; @NotNullByDefault public interface AndroidWakeLockFactory { - /** - * Creates and returns a wake lock. - * - * @param levelAndFlags See {@link PowerManager#newWakeLock(int, String)} - */ - AndroidWakeLock createWakeLock(int levelAndFlags); + AndroidWakeLock createWakeLock(); } diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothTransportConnection.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothTransportConnection.java index 0d2498f25..ad0f4f038 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothTransportConnection.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothTransportConnection.java @@ -13,7 +13,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import static android.os.PowerManager.PARTIAL_WAKE_LOCK; import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_ADDRESS; import static org.briarproject.bramble.util.AndroidUtils.isValidBluetoothAddress; @@ -36,7 +35,7 @@ class AndroidBluetoothTransportConnection this.socket = socket; in = timeoutMonitor.createTimeoutInputStream( socket.getInputStream(), plugin.getMaxIdleTime() * 2); - wakeLock = wakeLockFactory.createWakeLock(PARTIAL_WAKE_LOCK); + wakeLock = wakeLockFactory.createWakeLock(); wakeLock.acquire(); String address = socket.getRemoteDevice().getAddress(); if (isValidBluetoothAddress(address)) remote.put(PROP_ADDRESS, address); diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java index 2d26a9abf..391416019 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java @@ -23,7 +23,6 @@ import java.util.concurrent.Executor; import javax.net.SocketFactory; import static android.content.Context.MODE_PRIVATE; -import static android.os.PowerManager.PARTIAL_WAKE_LOCK; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -54,7 +53,7 @@ class AndroidTorPlugin extends TorPlugin { maxLatency, maxIdleTime, appContext.getDir("tor", MODE_PRIVATE)); this.appContext = appContext; - wakeLock = wakeLockFactory.createWakeLock(PARTIAL_WAKE_LOCK); + wakeLock = wakeLockFactory.createWakeLock(); } @Override diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java index 0ddb3ed90..e174052d5 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java @@ -15,6 +15,7 @@ import javax.annotation.concurrent.Immutable; import javax.inject.Inject; import static android.content.Context.POWER_SERVICE; +import static android.os.PowerManager.PARTIAL_WAKE_LOCK; import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.SECONDS; import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull; @@ -34,22 +35,20 @@ class AndroidWakeLockFactoryImpl implements AndroidWakeLockFactory { */ private static final long SAFETY_MARGIN_MS = SECONDS.toMillis(10); - private final TaskScheduler scheduler; - private final PowerManager powerManager; - private final String tag; + private final SharedWakeLock sharedWakeLock; @Inject AndroidWakeLockFactoryImpl(TaskScheduler scheduler, Application app) { - this.scheduler = scheduler; - powerManager = (PowerManager) + PowerManager powerManager = (PowerManager) requireNonNull(app.getSystemService(POWER_SERVICE)); - tag = getWakeLockTag(app); + String tag = getWakeLockTag(app); + sharedWakeLock = new RenewableWakeLock(powerManager, scheduler, + PARTIAL_WAKE_LOCK, tag, LOCK_DURATION_MS, SAFETY_MARGIN_MS); } @Override - public AndroidWakeLock createWakeLock(int levelAndFlags) { - return new RenewableWakeLock(powerManager, scheduler, levelAndFlags, - tag, LOCK_DURATION_MS, SAFETY_MARGIN_MS); + public AndroidWakeLock createWakeLock() { + return new AndroidWakeLockImpl(sharedWakeLock); } private String getWakeLockTag(Context ctx) { diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockImpl.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockImpl.java new file mode 100644 index 000000000..d3d9a7c4b --- /dev/null +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockImpl.java @@ -0,0 +1,46 @@ +package org.briarproject.bramble.system; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.system.AndroidWakeLock; + +import javax.annotation.concurrent.GuardedBy; +import javax.annotation.concurrent.ThreadSafe; + +/** + * A wrapper around a {@link SharedWakeLock} that provides the more convenient + * semantics of {@link AndroidWakeLock} (i.e. calls to acquire() and release() + * don't need to be balanced). + */ +@ThreadSafe +@NotNullByDefault +class AndroidWakeLockImpl implements AndroidWakeLock { + + private final SharedWakeLock sharedWakeLock; + private final Object lock = new Object(); + @GuardedBy("lock") + private boolean held = false; + + AndroidWakeLockImpl(SharedWakeLock sharedWakeLock) { + this.sharedWakeLock = sharedWakeLock; + } + + @Override + public void acquire() { + synchronized (lock) { + if (!held) { + held = true; + sharedWakeLock.acquire(); + } + } + } + + @Override + public void release() { + synchronized (lock) { + if (held) { + held = false; + sharedWakeLock.release(); + } + } + } +} diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/RenewableWakeLock.java b/bramble-android/src/main/java/org/briarproject/bramble/system/RenewableWakeLock.java index a4cc520f2..5dcca9ce5 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/RenewableWakeLock.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/RenewableWakeLock.java @@ -4,22 +4,23 @@ import android.os.PowerManager; import android.os.PowerManager.WakeLock; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.system.AndroidWakeLock; import org.briarproject.bramble.api.system.TaskScheduler; import java.util.concurrent.Future; import java.util.logging.Logger; import javax.annotation.Nullable; +import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.ThreadSafe; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.logging.Level.INFO; import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull; @ThreadSafe @NotNullByDefault -class RenewableWakeLock implements AndroidWakeLock { +class RenewableWakeLock implements SharedWakeLock { private static final Logger LOG = getLogger(RenewableWakeLock.class.getName()); @@ -31,10 +32,14 @@ class RenewableWakeLock implements AndroidWakeLock { private final long durationMs, safetyMarginMs; private final Object lock = new Object(); + @GuardedBy("lock") @Nullable - private WakeLock wakeLock; // Locking: lock + private WakeLock wakeLock; + @GuardedBy("lock") @Nullable - private Future future; // Locking: lock + private Future future; + @GuardedBy("lock") + private int refCount = 0; RenewableWakeLock(PowerManager powerManager, TaskScheduler scheduler, int levelAndFlags, String tag, long durationMs, @@ -49,16 +54,21 @@ class RenewableWakeLock implements AndroidWakeLock { @Override public void acquire() { - if (LOG.isLoggable(INFO)) LOG.info("Acquiring wake lock " + tag); synchronized (lock) { - if (wakeLock != null) { - LOG.info("Already acquired"); - return; + refCount++; + if (refCount == 1) { + if (LOG.isLoggable(INFO)) { + LOG.info("Acquiring wake lock " + tag); + } + wakeLock = powerManager.newWakeLock(levelAndFlags, tag); + // We do our own reference counting so we can replace the lock + // TODO: Check whether using a ref-counted wake lock affects + // power management apps + wakeLock.setReferenceCounted(false); + wakeLock.acquire(durationMs + safetyMarginMs); + future = scheduler.schedule(this::renew, durationMs, + MILLISECONDS); } - wakeLock = powerManager.newWakeLock(levelAndFlags, tag); - wakeLock.setReferenceCounted(false); - wakeLock.acquire(durationMs + safetyMarginMs); - future = scheduler.schedule(this::renew, durationMs, MILLISECONDS); } } @@ -80,17 +90,17 @@ class RenewableWakeLock implements AndroidWakeLock { @Override public void release() { - if (LOG.isLoggable(INFO)) LOG.info("Releasing wake lock " + tag); synchronized (lock) { - if (wakeLock == null) { - LOG.info("Already released"); - return; + refCount--; + if (refCount == 0) { + if (LOG.isLoggable(INFO)) { + LOG.info("Releasing wake lock " + tag); + } + requireNonNull(future).cancel(false); + future = null; + requireNonNull(wakeLock).release(); + wakeLock = null; } - if (future == null) throw new AssertionError(); - future.cancel(false); - future = null; - wakeLock.release(); - wakeLock = null; } } } diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/SharedWakeLock.java b/bramble-android/src/main/java/org/briarproject/bramble/system/SharedWakeLock.java new file mode 100644 index 000000000..db0a07043 --- /dev/null +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/SharedWakeLock.java @@ -0,0 +1,22 @@ +package org.briarproject.bramble.system; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.system.AndroidWakeLock; + +@NotNullByDefault +interface SharedWakeLock { + + /** + * Acquires the wake lock. This increments the wake lock's reference count, + * so unlike {@link AndroidWakeLock#acquire()} every call to this method + * must be followed by a balancing call to {@link #release()}. + */ + void acquire(); + + /** + * Releases the wake lock. This decrements the wake lock's reference count, + * so unlike {@link AndroidWakeLock#release()} every call to this method + * must follow a balancing call to {@link #acquire()}. + */ + void release(); +} From 7cdd05fd672b6e6cbde1b11ada352fffe8b5d7f1 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 4 Aug 2020 17:36:55 +0100 Subject: [PATCH 5/8] Log a warning if the wake lock expires before it's renewed. --- .../bramble/system/RenewableWakeLock.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/RenewableWakeLock.java b/bramble-android/src/main/java/org/briarproject/bramble/system/RenewableWakeLock.java index 5dcca9ce5..c47a8dfb9 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/RenewableWakeLock.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/RenewableWakeLock.java @@ -15,6 +15,7 @@ import javax.annotation.concurrent.ThreadSafe; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull; @@ -40,6 +41,8 @@ class RenewableWakeLock implements SharedWakeLock { private Future future; @GuardedBy("lock") private int refCount = 0; + @GuardedBy("lock") + private long acquired = 0; RenewableWakeLock(PowerManager powerManager, TaskScheduler scheduler, int levelAndFlags, String tag, long durationMs, @@ -68,6 +71,7 @@ class RenewableWakeLock implements SharedWakeLock { wakeLock.acquire(durationMs + safetyMarginMs); future = scheduler.schedule(this::renew, durationMs, MILLISECONDS); + acquired = android.os.SystemClock.elapsedRealtime(); } } } @@ -79,12 +83,18 @@ class RenewableWakeLock implements SharedWakeLock { LOG.info("Already released"); return; } + long now = android.os.SystemClock.elapsedRealtime(); + long expiry = acquired + durationMs + safetyMarginMs; + if (now > expiry && LOG.isLoggable(WARNING)) { + LOG.warning("Wake lock expired " + (now - expiry) + " ms ago"); + } WakeLock oldWakeLock = wakeLock; wakeLock = powerManager.newWakeLock(levelAndFlags, tag); wakeLock.setReferenceCounted(false); wakeLock.acquire(durationMs + safetyMarginMs); oldWakeLock.release(); future = scheduler.schedule(this::renew, durationMs, MILLISECONDS); + acquired = now; } } @@ -100,6 +110,7 @@ class RenewableWakeLock implements SharedWakeLock { future = null; requireNonNull(wakeLock).release(); wakeLock = null; + acquired = 0; } } } From b6b721e3b1d1461390be50664d8f8797f8973ebc Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 4 Aug 2020 17:44:22 +0100 Subject: [PATCH 6/8] Use a wider safety margin to allow for scheduler delays. --- .../briarproject/bramble/system/AndroidWakeLockFactoryImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java index e174052d5..e61af6644 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java @@ -33,7 +33,7 @@ class AndroidWakeLockFactoryImpl implements AndroidWakeLockFactory { * Automatically release the lock this many milliseconds after it's due * to have been replaced and released. */ - private static final long SAFETY_MARGIN_MS = SECONDS.toMillis(10); + private static final long SAFETY_MARGIN_MS = SECONDS.toMillis(30); private final SharedWakeLock sharedWakeLock; From d5395d3d01c48440166d6639450709bba30b6f5a Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 7 Aug 2020 15:07:48 +0100 Subject: [PATCH 7/8] Shared wake lock must be a singleton. --- .../org/briarproject/bramble/system/AndroidSystemModule.java | 1 + 1 file changed, 1 insertion(+) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java index deb30e871..b18b99d26 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java @@ -50,6 +50,7 @@ public class AndroidSystemModule { } @Provides + @Singleton AndroidWakeLockFactory provideWakeLockFactory( AndroidWakeLockFactoryImpl wakeLockFactory) { return wakeLockFactory; From 2e2bc2d82fd9dc10f93ec6c6c9d64e32c52a5804 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 7 Aug 2020 15:51:15 +0100 Subject: [PATCH 8/8] Remove @Immutable annotation, which is no longer true. --- .../briarproject/bramble/system/AndroidWakeLockFactoryImpl.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java index e61af6644..f1e7acf8f 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockFactoryImpl.java @@ -11,7 +11,6 @@ import org.briarproject.bramble.api.system.AndroidWakeLock; import org.briarproject.bramble.api.system.AndroidWakeLockFactory; import org.briarproject.bramble.api.system.TaskScheduler; -import javax.annotation.concurrent.Immutable; import javax.inject.Inject; import static android.content.Context.POWER_SERVICE; @@ -20,7 +19,6 @@ import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.SECONDS; import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull; -@Immutable @NotNullByDefault class AndroidWakeLockFactoryImpl implements AndroidWakeLockFactory {