mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-15 20:29:52 +01:00
Share a single OS wake lock among all holders.
This commit is contained in:
@@ -1,16 +1,9 @@
|
|||||||
package org.briarproject.bramble.api.system;
|
package org.briarproject.bramble.api.system;
|
||||||
|
|
||||||
import android.os.PowerManager;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface AndroidWakeLockFactory {
|
public interface AndroidWakeLockFactory {
|
||||||
|
|
||||||
/**
|
AndroidWakeLock createWakeLock();
|
||||||
* Creates and returns a wake lock.
|
|
||||||
*
|
|
||||||
* @param levelAndFlags See {@link PowerManager#newWakeLock(int, String)}
|
|
||||||
*/
|
|
||||||
AndroidWakeLock createWakeLock(int levelAndFlags);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
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.api.plugin.BluetoothConstants.PROP_ADDRESS;
|
||||||
import static org.briarproject.bramble.util.AndroidUtils.isValidBluetoothAddress;
|
import static org.briarproject.bramble.util.AndroidUtils.isValidBluetoothAddress;
|
||||||
|
|
||||||
@@ -36,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(PARTIAL_WAKE_LOCK);
|
wakeLock = wakeLockFactory.createWakeLock();
|
||||||
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);
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import java.util.concurrent.Executor;
|
|||||||
import javax.net.SocketFactory;
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
import static android.content.Context.MODE_PRIVATE;
|
import static android.content.Context.MODE_PRIVATE;
|
||||||
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
|
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -54,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(PARTIAL_WAKE_LOCK);
|
wakeLock = wakeLockFactory.createWakeLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import javax.annotation.concurrent.Immutable;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static android.content.Context.POWER_SERVICE;
|
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.MINUTES;
|
||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
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;
|
||||||
@@ -34,22 +35,20 @@ class AndroidWakeLockFactoryImpl implements AndroidWakeLockFactory {
|
|||||||
*/
|
*/
|
||||||
private static final long SAFETY_MARGIN_MS = SECONDS.toMillis(10);
|
private static final long SAFETY_MARGIN_MS = SECONDS.toMillis(10);
|
||||||
|
|
||||||
private final TaskScheduler scheduler;
|
private final SharedWakeLock sharedWakeLock;
|
||||||
private final PowerManager powerManager;
|
|
||||||
private final String tag;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
AndroidWakeLockFactoryImpl(TaskScheduler scheduler, Application app) {
|
AndroidWakeLockFactoryImpl(TaskScheduler scheduler, Application app) {
|
||||||
this.scheduler = scheduler;
|
PowerManager powerManager = (PowerManager)
|
||||||
powerManager = (PowerManager)
|
|
||||||
requireNonNull(app.getSystemService(POWER_SERVICE));
|
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
|
@Override
|
||||||
public AndroidWakeLock createWakeLock(int levelAndFlags) {
|
public AndroidWakeLock createWakeLock() {
|
||||||
return new RenewableWakeLock(powerManager, scheduler, levelAndFlags,
|
return new AndroidWakeLockImpl(sharedWakeLock);
|
||||||
tag, LOCK_DURATION_MS, SAFETY_MARGIN_MS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getWakeLockTag(Context ctx) {
|
private String getWakeLockTag(Context ctx) {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,22 +4,23 @@ 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.AndroidWakeLock;
|
|
||||||
import org.briarproject.bramble.api.system.TaskScheduler;
|
import org.briarproject.bramble.api.system.TaskScheduler;
|
||||||
|
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
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.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class RenewableWakeLock implements AndroidWakeLock {
|
class RenewableWakeLock implements SharedWakeLock {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
getLogger(RenewableWakeLock.class.getName());
|
getLogger(RenewableWakeLock.class.getName());
|
||||||
@@ -31,10 +32,14 @@ class RenewableWakeLock implements AndroidWakeLock {
|
|||||||
private final long durationMs, safetyMarginMs;
|
private final long durationMs, safetyMarginMs;
|
||||||
|
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
|
@GuardedBy("lock")
|
||||||
@Nullable
|
@Nullable
|
||||||
private WakeLock wakeLock; // Locking: lock
|
private WakeLock wakeLock;
|
||||||
|
@GuardedBy("lock")
|
||||||
@Nullable
|
@Nullable
|
||||||
private Future<?> future; // Locking: lock
|
private Future<?> future;
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private int refCount = 0;
|
||||||
|
|
||||||
RenewableWakeLock(PowerManager powerManager, TaskScheduler scheduler,
|
RenewableWakeLock(PowerManager powerManager, TaskScheduler scheduler,
|
||||||
int levelAndFlags, String tag, long durationMs,
|
int levelAndFlags, String tag, long durationMs,
|
||||||
@@ -49,16 +54,21 @@ class RenewableWakeLock implements AndroidWakeLock {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void acquire() {
|
public void acquire() {
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("Acquiring wake lock " + tag);
|
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
if (wakeLock != null) {
|
refCount++;
|
||||||
LOG.info("Already acquired");
|
if (refCount == 1) {
|
||||||
return;
|
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
|
@Override
|
||||||
public void release() {
|
public void release() {
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("Releasing wake lock " + tag);
|
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
if (wakeLock == null) {
|
refCount--;
|
||||||
LOG.info("Already released");
|
if (refCount == 0) {
|
||||||
return;
|
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user