From 98a0d098993eb4ae917f404d2961d8b81694b815 Mon Sep 17 00:00:00 2001 From: goapunk Date: Wed, 6 Sep 2017 21:44:03 +0200 Subject: [PATCH 1/6] Renew the wake lock every 30min Signed-off-by: goapunk --- .../bramble/plugin/tor/TorPlugin.java | 29 +++++++++--- .../ScheduledExecutorServiceWakeLock.java | 47 +++++++++++++++++++ 2 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 bramble-android/src/main/java/org/briarproject/bramble/util/ScheduledExecutorServiceWakeLock.java diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index 5ce2d8255..4193fbd2a 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -36,6 +36,7 @@ import org.briarproject.bramble.api.settings.Settings; import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent; import org.briarproject.bramble.api.system.LocationUtils; import org.briarproject.bramble.util.IoUtils; +import org.briarproject.bramble.util.ScheduledExecutorServiceWakeLock; import org.briarproject.bramble.util.StringUtils; import java.io.Closeable; @@ -119,10 +120,12 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { private final ConnectionStatus connectionStatus; private final File torDirectory, torFile, geoIpFile, configFile; private final File doneFile, cookieFile; - private final PowerManager.WakeLock wakeLock; private final AtomicReference> connectivityCheck = new AtomicReference<>(); private final AtomicBoolean used = new AtomicBoolean(false); + private final ScheduledExecutorServiceWakeLock scheduledExecutorServiceWakeLock; + + private PowerManager.WakeLock wakeLock; private volatile boolean running = false; private volatile ServerSocket socket = null; @@ -155,14 +158,27 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { configFile = new File(torDirectory, "torrc"); doneFile = new File(torDirectory, "done"); cookieFile = new File(torDirectory, ".tor/control_auth_cookie"); - Object o = appContext.getSystemService(POWER_SERVICE); - PowerManager pm = (PowerManager) o; - // This tag will prevent Huawei's powermanager from killing us. - wakeLock = pm.newWakeLock(PARTIAL_WAKE_LOCK, "LocationManagerService"); - wakeLock.setReferenceCounted(false); // Don't execute more than one connection status check at a time connectionStatusExecutor = new PoliteExecutor("TorPlugin", ioExecutor, 1); + scheduledExecutorServiceWakeLock = + new ScheduledExecutorServiceWakeLock(appContext); + scheduledExecutorServiceWakeLock.setRunnable((Runnable) () -> { + LOG.info("Renewing wake lock"); + wakeLock.release(); + aquireWakeLock(); + }); + aquireWakeLock(); + } + + private void aquireWakeLock(){ + LOG.info("Aquiring wake lock"); + PowerManager pm = (PowerManager) + appContext.getSystemService(POWER_SERVICE); + // This tag will prevent Huawei's powermanager from killing us. + wakeLock = pm.newWakeLock(PARTIAL_WAKE_LOCK, "LocationManagerService"); + wakeLock.setReferenceCounted(false); + scheduledExecutorServiceWakeLock.setAlarm(1800000, MILLISECONDS); } @Override @@ -514,6 +530,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } } wakeLock.release(); + scheduledExecutorServiceWakeLock.cancelAlarm(); } @Override diff --git a/bramble-android/src/main/java/org/briarproject/bramble/util/ScheduledExecutorServiceWakeLock.java b/bramble-android/src/main/java/org/briarproject/bramble/util/ScheduledExecutorServiceWakeLock.java new file mode 100644 index 000000000..4dff3946d --- /dev/null +++ b/bramble-android/src/main/java/org/briarproject/bramble/util/ScheduledExecutorServiceWakeLock.java @@ -0,0 +1,47 @@ +package org.briarproject.bramble.util; + +import android.content.Context; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +public class ScheduledExecutorServiceWakeLock { + + final Context appContext; + + private static final ThreadFactory THREAD_FACTORY = new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r); + t.setDaemon(true); + return t; + } + }; + + private ScheduledExecutorService scheduledExecutorService = null; // Locking: this + private Runnable runnable; + + public ScheduledExecutorServiceWakeLock(Context appContext) { + this.appContext = appContext; + } + + public void setRunnable(Runnable r){ + runnable = r; + } + + public synchronized void setAlarm(long delay, TimeUnit unit) { + if(runnable == null) + return; + if (scheduledExecutorService == null) + scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(THREAD_FACTORY); + scheduledExecutorService.schedule(runnable, delay, unit); + } + + public synchronized void cancelAlarm() { + if (scheduledExecutorService == null) throw new IllegalStateException(); + scheduledExecutorService.shutdownNow(); + scheduledExecutorService = null; + } +} From c089a099f0e124272dd88ce47308f08d30b3ce62 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 11 Oct 2017 15:39:22 +0100 Subject: [PATCH 2/6] Refactor wake lock to use existing ScheduledExecutorService. --- .../bramble/plugin/tor/TorPlugin.java | 26 ++---- .../bramble/util/RenewableWakeLock.java | 90 +++++++++++++++++++ .../ScheduledExecutorServiceWakeLock.java | 47 ---------- 3 files changed, 95 insertions(+), 68 deletions(-) create mode 100644 bramble-android/src/main/java/org/briarproject/bramble/util/RenewableWakeLock.java delete mode 100644 bramble-android/src/main/java/org/briarproject/bramble/util/ScheduledExecutorServiceWakeLock.java diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index 4193fbd2a..3458c97e3 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -36,7 +36,7 @@ import org.briarproject.bramble.api.settings.Settings; import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent; import org.briarproject.bramble.api.system.LocationUtils; import org.briarproject.bramble.util.IoUtils; -import org.briarproject.bramble.util.ScheduledExecutorServiceWakeLock; +import org.briarproject.bramble.util.RenewableWakeLock; import org.briarproject.bramble.util.StringUtils; import java.io.Closeable; @@ -120,12 +120,10 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { private final ConnectionStatus connectionStatus; private final File torDirectory, torFile, geoIpFile, configFile; private final File doneFile, cookieFile; + private final RenewableWakeLock wakeLock; private final AtomicReference> connectivityCheck = new AtomicReference<>(); private final AtomicBoolean used = new AtomicBoolean(false); - private final ScheduledExecutorServiceWakeLock scheduledExecutorServiceWakeLock; - - private PowerManager.WakeLock wakeLock; private volatile boolean running = false; private volatile ServerSocket socket = null; @@ -161,24 +159,11 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { // Don't execute more than one connection status check at a time connectionStatusExecutor = new PoliteExecutor("TorPlugin", ioExecutor, 1); - scheduledExecutorServiceWakeLock = - new ScheduledExecutorServiceWakeLock(appContext); - scheduledExecutorServiceWakeLock.setRunnable((Runnable) () -> { - LOG.info("Renewing wake lock"); - wakeLock.release(); - aquireWakeLock(); - }); - aquireWakeLock(); - } - - private void aquireWakeLock(){ - LOG.info("Aquiring wake lock"); PowerManager pm = (PowerManager) appContext.getSystemService(POWER_SERVICE); - // This tag will prevent Huawei's powermanager from killing us. - wakeLock = pm.newWakeLock(PARTIAL_WAKE_LOCK, "LocationManagerService"); - wakeLock.setReferenceCounted(false); - scheduledExecutorServiceWakeLock.setAlarm(1800000, MILLISECONDS); + // This tag will prevent Huawei's power manager from killing us + wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK, + "LocationManagerService", 30, MINUTES); } @Override @@ -530,7 +515,6 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } } wakeLock.release(); - scheduledExecutorServiceWakeLock.cancelAlarm(); } @Override diff --git a/bramble-android/src/main/java/org/briarproject/bramble/util/RenewableWakeLock.java b/bramble-android/src/main/java/org/briarproject/bramble/util/RenewableWakeLock.java new file mode 100644 index 000000000..4b2dfb1ff --- /dev/null +++ b/bramble-android/src/main/java/org/briarproject/bramble/util/RenewableWakeLock.java @@ -0,0 +1,90 @@ +package org.briarproject.bramble.util; + +import android.os.PowerManager; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +import static java.util.logging.Level.INFO; + +public class RenewableWakeLock { + + private static final Logger LOG = + Logger.getLogger(RenewableWakeLock.class.getName()); + + private final PowerManager powerManager; + private final ScheduledExecutorService scheduler; + private final int levelAndFlags; + private final String tag; + private final long duration; + private final TimeUnit timeUnit; + private final Runnable renewTask; + + private final Object lock = new Object(); + private PowerManager.WakeLock wakeLock; // Locking: lock + private ScheduledFuture future; // Locking: lock + + public RenewableWakeLock(PowerManager powerManager, + ScheduledExecutorService scheduler, int levelAndFlags, String tag, + long duration, TimeUnit timeUnit) { + this.powerManager = powerManager; + this.scheduler = scheduler; + this.levelAndFlags = levelAndFlags; + this.tag = tag; + this.duration = duration; + this.timeUnit = timeUnit; + renewTask = new Runnable() { + @Override + public void run() { + renew(); + } + }; + } + + public void acquire() { + if (LOG.isLoggable(INFO)) LOG.info("Acquiring wake lock " + tag ); + synchronized (lock) { + if (wakeLock != null) { + LOG.info("Already acquired"); + return; + } + wakeLock = powerManager.newWakeLock(levelAndFlags, tag); + wakeLock.setReferenceCounted(false); + wakeLock.acquire(); + future = scheduler.schedule(renewTask, duration, timeUnit); + } + } + + private void renew() { + if (LOG.isLoggable(INFO)) LOG.info("Renewing wake lock " + tag ); + synchronized (lock) { + if (wakeLock == null) { + LOG.info("Already released"); + return; + } + PowerManager.WakeLock oldWakeLock = wakeLock; + wakeLock = powerManager.newWakeLock(levelAndFlags, tag); + wakeLock.setReferenceCounted(false); + wakeLock.acquire(); + oldWakeLock.release(); + future = scheduler.schedule(renewTask, duration, timeUnit); + } + } + + public void release() { + if (LOG.isLoggable(INFO)) LOG.info("Releasing wake lock " + tag ); + synchronized (lock) { + if (wakeLock == null) { + LOG.info("Already released"); + return; + } + future.cancel(false); + future = null; + wakeLock.release(); + wakeLock = null; + } + } +} + diff --git a/bramble-android/src/main/java/org/briarproject/bramble/util/ScheduledExecutorServiceWakeLock.java b/bramble-android/src/main/java/org/briarproject/bramble/util/ScheduledExecutorServiceWakeLock.java deleted file mode 100644 index 4dff3946d..000000000 --- a/bramble-android/src/main/java/org/briarproject/bramble/util/ScheduledExecutorServiceWakeLock.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.briarproject.bramble.util; - -import android.content.Context; - -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; - -public class ScheduledExecutorServiceWakeLock { - - final Context appContext; - - private static final ThreadFactory THREAD_FACTORY = new ThreadFactory() { - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r); - t.setDaemon(true); - return t; - } - }; - - private ScheduledExecutorService scheduledExecutorService = null; // Locking: this - private Runnable runnable; - - public ScheduledExecutorServiceWakeLock(Context appContext) { - this.appContext = appContext; - } - - public void setRunnable(Runnable r){ - runnable = r; - } - - public synchronized void setAlarm(long delay, TimeUnit unit) { - if(runnable == null) - return; - if (scheduledExecutorService == null) - scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(THREAD_FACTORY); - scheduledExecutorService.schedule(runnable, delay, unit); - } - - public synchronized void cancelAlarm() { - if (scheduledExecutorService == null) throw new IllegalStateException(); - scheduledExecutorService.shutdownNow(); - scheduledExecutorService = null; - } -} From 74cfd313ab8194089e9ae8c425536d2fadc4b3dc Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 11 Oct 2017 15:45:02 +0100 Subject: [PATCH 3/6] Code cleanup. --- .../briarproject/bramble/plugin/tor/TorPlugin.java | 5 +++-- .../bramble/util/RenewableWakeLock.java | 13 ++++--------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index 3458c97e3..5ad1360f8 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -105,6 +105,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { private static final String OWNER = "__OwningControllerProcess"; private static final int COOKIE_TIMEOUT = 3000; // Milliseconds private static final Pattern ONION = Pattern.compile("[a-z2-7]{16}"); + // This tag will prevent Huawei's power manager from killing us + private static final String WAKE_LOCK_TAG = "LocationManagerService"; private static final Logger LOG = Logger.getLogger(TorPlugin.class.getName()); @@ -161,9 +163,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { ioExecutor, 1); PowerManager pm = (PowerManager) appContext.getSystemService(POWER_SERVICE); - // This tag will prevent Huawei's power manager from killing us wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK, - "LocationManagerService", 30, MINUTES); + WAKE_LOCK_TAG, 30, MINUTES); } @Override diff --git a/bramble-android/src/main/java/org/briarproject/bramble/util/RenewableWakeLock.java b/bramble-android/src/main/java/org/briarproject/bramble/util/RenewableWakeLock.java index 4b2dfb1ff..5e26f4cfb 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/util/RenewableWakeLock.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/util/RenewableWakeLock.java @@ -35,16 +35,11 @@ public class RenewableWakeLock { this.tag = tag; this.duration = duration; this.timeUnit = timeUnit; - renewTask = new Runnable() { - @Override - public void run() { - renew(); - } - }; + renewTask = this::renew; } public void acquire() { - if (LOG.isLoggable(INFO)) LOG.info("Acquiring wake lock " + tag ); + if (LOG.isLoggable(INFO)) LOG.info("Acquiring wake lock " + tag); synchronized (lock) { if (wakeLock != null) { LOG.info("Already acquired"); @@ -58,7 +53,7 @@ public class RenewableWakeLock { } private void renew() { - if (LOG.isLoggable(INFO)) LOG.info("Renewing wake lock " + tag ); + if (LOG.isLoggable(INFO)) LOG.info("Renewing wake lock " + tag); synchronized (lock) { if (wakeLock == null) { LOG.info("Already released"); @@ -74,7 +69,7 @@ public class RenewableWakeLock { } public void release() { - if (LOG.isLoggable(INFO)) LOG.info("Releasing wake lock " + tag ); + if (LOG.isLoggable(INFO)) LOG.info("Releasing wake lock " + tag); synchronized (lock) { if (wakeLock == null) { LOG.info("Already released"); From 4f732c3997a5cb7034a6dda592b936d6c7858c9e Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 14 May 2018 16:47:47 +0100 Subject: [PATCH 4/6] Acquire wake lock with a timeout. --- .../bramble/util/RenewableWakeLock.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/util/RenewableWakeLock.java b/bramble-android/src/main/java/org/briarproject/bramble/util/RenewableWakeLock.java index 5e26f4cfb..eb7ff4e0b 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/util/RenewableWakeLock.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/util/RenewableWakeLock.java @@ -7,6 +7,7 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.logging.Level.INFO; public class RenewableWakeLock { @@ -14,12 +15,17 @@ public class RenewableWakeLock { private static final Logger LOG = Logger.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 ScheduledExecutorService scheduler; private final int levelAndFlags; private final String tag; - private final long duration; - private final TimeUnit timeUnit; + private final long durationMs; private final Runnable renewTask; private final Object lock = new Object(); @@ -33,8 +39,7 @@ public class RenewableWakeLock { this.scheduler = scheduler; this.levelAndFlags = levelAndFlags; this.tag = tag; - this.duration = duration; - this.timeUnit = timeUnit; + durationMs = MILLISECONDS.convert(duration, timeUnit); renewTask = this::renew; } @@ -47,8 +52,8 @@ public class RenewableWakeLock { } wakeLock = powerManager.newWakeLock(levelAndFlags, tag); wakeLock.setReferenceCounted(false); - wakeLock.acquire(); - future = scheduler.schedule(renewTask, duration, timeUnit); + wakeLock.acquire(durationMs + SAFETY_MARGIN_MS); + future = scheduler.schedule(renewTask, durationMs, MILLISECONDS); } } @@ -62,9 +67,9 @@ public class RenewableWakeLock { PowerManager.WakeLock oldWakeLock = wakeLock; wakeLock = powerManager.newWakeLock(levelAndFlags, tag); wakeLock.setReferenceCounted(false); - wakeLock.acquire(); + wakeLock.acquire(durationMs + SAFETY_MARGIN_MS); oldWakeLock.release(); - future = scheduler.schedule(renewTask, duration, timeUnit); + future = scheduler.schedule(renewTask, durationMs, MILLISECONDS); } } From d7f39af6d1d785ec31f3d766af66a9e8da8fdf32 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 14 May 2018 16:50:18 +0100 Subject: [PATCH 5/6] Reduce wake lock refresh interval to 1 minute. --- .../java/org/briarproject/bramble/plugin/tor/TorPlugin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index 5ad1360f8..865b198f0 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -105,7 +105,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { private static final String OWNER = "__OwningControllerProcess"; private static final int COOKIE_TIMEOUT = 3000; // Milliseconds private static final Pattern ONION = Pattern.compile("[a-z2-7]{16}"); - // This tag will prevent Huawei's power manager from killing us + // This tag may prevent Huawei's power manager from killing us private static final String WAKE_LOCK_TAG = "LocationManagerService"; private static final Logger LOG = Logger.getLogger(TorPlugin.class.getName()); @@ -164,7 +164,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { PowerManager pm = (PowerManager) appContext.getSystemService(POWER_SERVICE); wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK, - WAKE_LOCK_TAG, 30, MINUTES); + WAKE_LOCK_TAG, 1, MINUTES); } @Override From 6703be1c32b81a375f090617885b91e02995fa9a Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 12 Jun 2018 17:50:58 +0100 Subject: [PATCH 6/6] Add thread safety, null safety annotations. --- .../briarproject/bramble/util/RenewableWakeLock.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/util/RenewableWakeLock.java b/bramble-android/src/main/java/org/briarproject/bramble/util/RenewableWakeLock.java index eb7ff4e0b..1681cbfd1 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/util/RenewableWakeLock.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/util/RenewableWakeLock.java @@ -2,14 +2,21 @@ package org.briarproject.bramble.util; import android.os.PowerManager; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import javax.annotation.Nullable; +import javax.annotation.concurrent.ThreadSafe; + import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.logging.Level.INFO; +@ThreadSafe +@NotNullByDefault public class RenewableWakeLock { private static final Logger LOG = @@ -29,7 +36,9 @@ public class RenewableWakeLock { private final Runnable renewTask; private final Object lock = new Object(); + @Nullable private PowerManager.WakeLock wakeLock; // Locking: lock + @Nullable private ScheduledFuture future; // Locking: lock public RenewableWakeLock(PowerManager powerManager, @@ -80,6 +89,7 @@ public class RenewableWakeLock { LOG.info("Already released"); return; } + if (future == null) throw new AssertionError(); future.cancel(false); future = null; wakeLock.release();