mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +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;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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