mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-15 20:29:52 +01:00
Compare commits
12 Commits
2211-make-
...
beta-1.4.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5563ead28 | ||
|
|
e15f49fde7 | ||
|
|
1531a24b2d | ||
|
|
2298818af5 | ||
|
|
0ae5361281 | ||
|
|
d8e26eebbe | ||
|
|
692e353046 | ||
|
|
7bbe9068bb | ||
|
|
e481a02126 | ||
|
|
825dff27fc | ||
|
|
de3a87fff5 | ||
|
|
85d1addd04 |
@@ -15,8 +15,8 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode 10409
|
versionCode 10410
|
||||||
versionName "1.4.9"
|
versionName "1.4.10"
|
||||||
consumerProguardFiles 'proguard-rules.txt'
|
consumerProguardFiles 'proguard-rules.txt'
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|||||||
@@ -37,8 +37,14 @@ public interface LifecycleManager {
|
|||||||
*/
|
*/
|
||||||
enum LifecycleState {
|
enum LifecycleState {
|
||||||
|
|
||||||
STARTING, MIGRATING_DATABASE, COMPACTING_DATABASE, STARTING_SERVICES,
|
CREATED,
|
||||||
RUNNING, STOPPING;
|
STARTING,
|
||||||
|
MIGRATING_DATABASE,
|
||||||
|
COMPACTING_DATABASE,
|
||||||
|
STARTING_SERVICES,
|
||||||
|
RUNNING,
|
||||||
|
STOPPING,
|
||||||
|
STOPPED;
|
||||||
|
|
||||||
public boolean isAfter(LifecycleState state) {
|
public boolean isAfter(LifecycleState state) {
|
||||||
return ordinal() > state.ordinal();
|
return ordinal() > state.ordinal();
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import java.util.List;
|
|||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
@@ -29,10 +29,12 @@ import static java.util.logging.Level.INFO;
|
|||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.COMPACTING_DATABASE;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.COMPACTING_DATABASE;
|
||||||
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.CREATED;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING_DATABASE;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING_DATABASE;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RUNNING;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RUNNING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING_SERVICES;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING_SERVICES;
|
||||||
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPED;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.CLOCK_ERROR;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.CLOCK_ERROR;
|
||||||
@@ -60,12 +62,11 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
private final List<Service> services;
|
private final List<Service> services;
|
||||||
private final List<OpenDatabaseHook> openDatabaseHooks;
|
private final List<OpenDatabaseHook> openDatabaseHooks;
|
||||||
private final List<ExecutorService> executors;
|
private final List<ExecutorService> executors;
|
||||||
private final Semaphore startStopSemaphore = new Semaphore(1);
|
|
||||||
private final CountDownLatch dbLatch = new CountDownLatch(1);
|
private final CountDownLatch dbLatch = new CountDownLatch(1);
|
||||||
private final CountDownLatch startupLatch = new CountDownLatch(1);
|
private final CountDownLatch startupLatch = new CountDownLatch(1);
|
||||||
private final CountDownLatch shutdownLatch = new CountDownLatch(1);
|
private final CountDownLatch shutdownLatch = new CountDownLatch(1);
|
||||||
|
private final AtomicReference<LifecycleState> state =
|
||||||
private volatile LifecycleState state = STARTING;
|
new AtomicReference<>(CREATED);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
LifecycleManagerImpl(DatabaseComponent db, EventBus eventBus,
|
LifecycleManagerImpl(DatabaseComponent db, EventBus eventBus,
|
||||||
@@ -102,8 +103,8 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StartResult startServices(SecretKey dbKey) {
|
public StartResult startServices(SecretKey dbKey) {
|
||||||
if (!startStopSemaphore.tryAcquire()) {
|
if (!state.compareAndSet(CREATED, STARTING)) {
|
||||||
LOG.info("Already starting or stopping");
|
LOG.warning("Already running");
|
||||||
return ALREADY_RUNNING;
|
return ALREADY_RUNNING;
|
||||||
}
|
}
|
||||||
long now = clock.currentTimeMillis();
|
long now = clock.currentTimeMillis();
|
||||||
@@ -135,7 +136,7 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
});
|
});
|
||||||
|
|
||||||
LOG.info("Starting services");
|
LOG.info("Starting services");
|
||||||
state = STARTING_SERVICES;
|
state.set(STARTING_SERVICES);
|
||||||
dbLatch.countDown();
|
dbLatch.countDown();
|
||||||
eventBus.broadcast(new LifecycleEvent(STARTING_SERVICES));
|
eventBus.broadcast(new LifecycleEvent(STARTING_SERVICES));
|
||||||
|
|
||||||
@@ -148,7 +149,7 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state = RUNNING;
|
state.set(RUNNING);
|
||||||
startupLatch.countDown();
|
startupLatch.countDown();
|
||||||
eventBus.broadcast(new LifecycleEvent(RUNNING));
|
eventBus.broadcast(new LifecycleEvent(RUNNING));
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
@@ -164,63 +165,58 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
return SERVICE_ERROR;
|
return SERVICE_ERROR;
|
||||||
} finally {
|
|
||||||
startStopSemaphore.release();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDatabaseMigration() {
|
public void onDatabaseMigration() {
|
||||||
state = MIGRATING_DATABASE;
|
state.set(MIGRATING_DATABASE);
|
||||||
eventBus.broadcast(new LifecycleEvent(MIGRATING_DATABASE));
|
eventBus.broadcast(new LifecycleEvent(MIGRATING_DATABASE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDatabaseCompaction() {
|
public void onDatabaseCompaction() {
|
||||||
state = COMPACTING_DATABASE;
|
state.set(COMPACTING_DATABASE);
|
||||||
eventBus.broadcast(new LifecycleEvent(COMPACTING_DATABASE));
|
eventBus.broadcast(new LifecycleEvent(COMPACTING_DATABASE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stopServices() {
|
public void stopServices() {
|
||||||
try {
|
if (!state.compareAndSet(RUNNING, STOPPING)) {
|
||||||
startStopSemaphore.acquire();
|
LOG.warning("Not running");
|
||||||
} catch (InterruptedException e) {
|
|
||||||
LOG.warning("Interrupted while waiting to stop services");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
LOG.info("Stopping services");
|
||||||
if (state == STOPPING) {
|
eventBus.broadcast(new LifecycleEvent(STOPPING));
|
||||||
LOG.info("Already stopped");
|
for (Service s : services) {
|
||||||
return;
|
try {
|
||||||
}
|
|
||||||
LOG.info("Stopping services");
|
|
||||||
state = STOPPING;
|
|
||||||
eventBus.broadcast(new LifecycleEvent(STOPPING));
|
|
||||||
for (Service s : services) {
|
|
||||||
long start = now();
|
long start = now();
|
||||||
s.stopService();
|
s.stopService();
|
||||||
if (LOG.isLoggable(FINE)) {
|
if (LOG.isLoggable(FINE)) {
|
||||||
logDuration(LOG, "Stopping service "
|
logDuration(LOG, "Stopping service "
|
||||||
+ s.getClass().getSimpleName(), start);
|
+ s.getClass().getSimpleName(), start);
|
||||||
}
|
}
|
||||||
|
} catch (ServiceException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
for (ExecutorService e : executors) {
|
}
|
||||||
if (LOG.isLoggable(FINE)) {
|
for (ExecutorService e : executors) {
|
||||||
LOG.fine("Stopping executor "
|
if (LOG.isLoggable(FINE)) {
|
||||||
+ e.getClass().getSimpleName());
|
LOG.fine("Stopping executor "
|
||||||
}
|
+ e.getClass().getSimpleName());
|
||||||
e.shutdownNow();
|
|
||||||
}
|
}
|
||||||
|
e.shutdownNow();
|
||||||
|
}
|
||||||
|
try {
|
||||||
long start = now();
|
long start = now();
|
||||||
db.close();
|
db.close();
|
||||||
logDuration(LOG, "Closing database", start);
|
logDuration(LOG, "Closing database", start);
|
||||||
shutdownLatch.countDown();
|
} catch (DbException e) {
|
||||||
} catch (DbException | ServiceException e) {
|
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
} finally {
|
|
||||||
startStopSemaphore.release();
|
|
||||||
}
|
}
|
||||||
|
state.set(STOPPED);
|
||||||
|
shutdownLatch.countDown();
|
||||||
|
eventBus.broadcast(new LifecycleEvent(STOPPED));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -240,6 +236,6 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LifecycleState getLifecycleState() {
|
public LifecycleState getLifecycleState() {
|
||||||
return state;
|
return state.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ import javax.annotation.concurrent.ThreadSafe;
|
|||||||
import javax.net.SocketFactory;
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
import static java.util.Collections.singletonMap;
|
import static java.util.Collections.singletonMap;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
@@ -93,9 +94,7 @@ import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION_V3;
|
|||||||
import static org.briarproject.bramble.api.plugin.TorConstants.REASON_BATTERY;
|
import static org.briarproject.bramble.api.plugin.TorConstants.REASON_BATTERY;
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.REASON_COUNTRY_BLOCKED;
|
import static org.briarproject.bramble.api.plugin.TorConstants.REASON_COUNTRY_BLOCKED;
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.REASON_MOBILE_DATA;
|
import static org.briarproject.bramble.api.plugin.TorConstants.REASON_MOBILE_DATA;
|
||||||
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.DEFAULT_OBFS4;
|
|
||||||
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.MEEK;
|
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.MEEK;
|
||||||
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.NON_DEFAULT_OBFS4;
|
|
||||||
import static org.briarproject.bramble.plugin.tor.TorRendezvousCrypto.SEED_BYTES;
|
import static org.briarproject.bramble.plugin.tor.TorRendezvousCrypto.SEED_BYTES;
|
||||||
import static org.briarproject.bramble.util.IoUtils.copyAndClose;
|
import static org.briarproject.bramble.util.IoUtils.copyAndClose;
|
||||||
import static org.briarproject.bramble.util.IoUtils.tryToClose;
|
import static org.briarproject.bramble.util.IoUtils.tryToClose;
|
||||||
@@ -239,8 +238,14 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
// Load the settings
|
// Load the settings
|
||||||
settings = callback.getSettings();
|
settings = callback.getSettings();
|
||||||
// Install or update the assets if necessary
|
try {
|
||||||
if (!assetsAreUpToDate()) installAssets();
|
// Install or update the assets if necessary
|
||||||
|
if (!assetsAreUpToDate()) installAssets();
|
||||||
|
// Start from the default config every time
|
||||||
|
extract(getConfigInputStream(), configFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new PluginException(e);
|
||||||
|
}
|
||||||
if (cookieFile.exists() && !cookieFile.delete())
|
if (cookieFile.exists() && !cookieFile.delete())
|
||||||
LOG.warning("Old auth cookie not deleted");
|
LOG.warning("Old auth cookie not deleted");
|
||||||
// Start a new Tor process
|
// Start a new Tor process
|
||||||
@@ -302,7 +307,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
info = controlConnection.getInfo("status/circuit-established");
|
info = controlConnection.getInfo("status/circuit-established");
|
||||||
if ("1".equals(info)) {
|
if ("1".equals(info)) {
|
||||||
LOG.info("Tor has already built a circuit");
|
LOG.info("Tor has already built a circuit");
|
||||||
state.getAndSetCircuitBuilt(true);
|
state.setCircuitBuilt(true);
|
||||||
}
|
}
|
||||||
} catch (TorNotRunningException e) {
|
} catch (TorNotRunningException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
@@ -321,25 +326,20 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
return doneFile.lastModified() > getLastUpdateTime();
|
return doneFile.lastModified() > getLastUpdateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void installAssets() throws PluginException {
|
private void installAssets() throws IOException {
|
||||||
try {
|
// The done file may already exist from a previous installation
|
||||||
// The done file may already exist from a previous installation
|
//noinspection ResultOfMethodCallIgnored
|
||||||
//noinspection ResultOfMethodCallIgnored
|
doneFile.delete();
|
||||||
doneFile.delete();
|
// The GeoIP file may exist from a previous installation - we can
|
||||||
// The GeoIP file may exist from a previous installation - we can
|
// save some space by deleting it.
|
||||||
// save some space by deleting it.
|
// TODO: Remove after a reasonable migration period
|
||||||
// TODO: Remove after a reasonable migration period
|
// (added 2022-03-29)
|
||||||
// (added 2022-03-29)
|
//noinspection ResultOfMethodCallIgnored
|
||||||
//noinspection ResultOfMethodCallIgnored
|
geoIpFile.delete();
|
||||||
geoIpFile.delete();
|
installTorExecutable();
|
||||||
installTorExecutable();
|
installObfs4Executable();
|
||||||
installObfs4Executable();
|
if (!doneFile.createNewFile())
|
||||||
extract(getConfigInputStream(), configFile);
|
LOG.warning("Failed to create done file");
|
||||||
if (!doneFile.createNewFile())
|
|
||||||
LOG.warning("Failed to create done file");
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new PluginException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void extract(InputStream in, File dest) throws IOException {
|
protected void extract(InputStream in, File dest) throws IOException {
|
||||||
@@ -398,6 +398,10 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
append(strb, "SocksPort", torSocksPort);
|
append(strb, "SocksPort", torSocksPort);
|
||||||
strb.append("GeoIPFile\n");
|
strb.append("GeoIPFile\n");
|
||||||
strb.append("GeoIPv6File\n");
|
strb.append("GeoIPv6File\n");
|
||||||
|
append(strb, "ConnectionPadding", 0);
|
||||||
|
String obfs4Path = getObfs4ExecutableFile().getAbsolutePath();
|
||||||
|
append(strb, "ClientTransportPlugin obfs4 exec", obfs4Path);
|
||||||
|
append(strb, "ClientTransportPlugin meek_lite exec", obfs4Path);
|
||||||
//noinspection CharsetObjectCanBeUsed
|
//noinspection CharsetObjectCanBeUsed
|
||||||
return new ByteArrayInputStream(
|
return new ByteArrayInputStream(
|
||||||
strb.toString().getBytes(Charset.forName("UTF-8")));
|
strb.toString().getBytes(Charset.forName("UTF-8")));
|
||||||
@@ -547,7 +551,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void enableNetwork(boolean enable) throws IOException {
|
protected void enableNetwork(boolean enable) throws IOException {
|
||||||
state.enableNetwork(enable);
|
if (!state.enableNetwork(enable)) return; // Unchanged
|
||||||
try {
|
try {
|
||||||
controlConnection.setConf("DisableNetwork", enable ? "0" : "1");
|
controlConnection.setConf("DisableNetwork", enable ? "0" : "1");
|
||||||
} catch (TorNotRunningException e) {
|
} catch (TorNotRunningException e) {
|
||||||
@@ -555,28 +559,20 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enableBridges(boolean enable, List<BridgeType> bridgeTypes)
|
private void enableBridges(List<BridgeType> bridgeTypes)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
if (!state.setBridgeTypes(bridgeTypes)) return; // Unchanged
|
||||||
try {
|
try {
|
||||||
if (enable) {
|
if (bridgeTypes.isEmpty()) {
|
||||||
|
controlConnection.setConf("UseBridges", "0");
|
||||||
|
controlConnection.resetConf(singletonList("Bridge"));
|
||||||
|
} else {
|
||||||
Collection<String> conf = new ArrayList<>();
|
Collection<String> conf = new ArrayList<>();
|
||||||
conf.add("UseBridges 1");
|
conf.add("UseBridges 1");
|
||||||
File obfs4File = getObfs4ExecutableFile();
|
|
||||||
if (bridgeTypes.contains(MEEK)) {
|
|
||||||
conf.add("ClientTransportPlugin meek_lite exec " +
|
|
||||||
obfs4File.getAbsolutePath());
|
|
||||||
}
|
|
||||||
if (bridgeTypes.contains(DEFAULT_OBFS4) ||
|
|
||||||
bridgeTypes.contains(NON_DEFAULT_OBFS4)) {
|
|
||||||
conf.add("ClientTransportPlugin obfs4 exec " +
|
|
||||||
obfs4File.getAbsolutePath());
|
|
||||||
}
|
|
||||||
for (BridgeType bridgeType : bridgeTypes) {
|
for (BridgeType bridgeType : bridgeTypes) {
|
||||||
conf.addAll(circumventionProvider.getBridges(bridgeType));
|
conf.addAll(circumventionProvider.getBridges(bridgeType));
|
||||||
}
|
}
|
||||||
controlConnection.setConf(conf);
|
controlConnection.setConf(conf);
|
||||||
} else {
|
|
||||||
controlConnection.setConf("UseBridges", "0");
|
|
||||||
}
|
}
|
||||||
} catch (TorNotRunningException e) {
|
} catch (TorNotRunningException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
@@ -590,7 +586,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
if (controlSocket != null && controlConnection != null) {
|
if (controlSocket != null && controlConnection != null) {
|
||||||
try {
|
try {
|
||||||
LOG.info("Stopping Tor");
|
LOG.info("Stopping Tor");
|
||||||
controlConnection.setConf("DisableNetwork", "1");
|
|
||||||
controlConnection.shutdownTor("TERM");
|
controlConnection.shutdownTor("TERM");
|
||||||
controlSocket.close();
|
controlSocket.close();
|
||||||
} catch (TorNotRunningException e) {
|
} catch (TorNotRunningException e) {
|
||||||
@@ -758,7 +753,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
public void circuitStatus(String status, String id, String path) {
|
public void circuitStatus(String status, String id, String path) {
|
||||||
// In case of races between receiving CIRCUIT_ESTABLISHED and setting
|
// In case of races between receiving CIRCUIT_ESTABLISHED and setting
|
||||||
// DisableNetwork, set our circuitBuilt flag if not already set
|
// DisableNetwork, set our circuitBuilt flag if not already set
|
||||||
if (status.equals("BUILT") && !state.getAndSetCircuitBuilt(true)) {
|
if (status.equals("BUILT") && state.setCircuitBuilt(true)) {
|
||||||
LOG.info("Circuit built");
|
LOG.info("Circuit built");
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
}
|
}
|
||||||
@@ -815,12 +810,12 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
state.setBootstrapped();
|
state.setBootstrapped();
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
} else if (msg.startsWith("CIRCUIT_ESTABLISHED")) {
|
} else if (msg.startsWith("CIRCUIT_ESTABLISHED")) {
|
||||||
if (!state.getAndSetCircuitBuilt(true)) {
|
if (state.setCircuitBuilt(true)) {
|
||||||
LOG.info("Circuit built");
|
LOG.info("Circuit built");
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
}
|
}
|
||||||
} else if (msg.startsWith("CIRCUIT_NOT_ESTABLISHED")) {
|
} else if (msg.startsWith("CIRCUIT_NOT_ESTABLISHED")) {
|
||||||
if (state.getAndSetCircuitBuilt(false)) {
|
if (state.setCircuitBuilt(false)) {
|
||||||
LOG.info("Circuit not built");
|
LOG.info("Circuit not built");
|
||||||
// TODO: Disable and re-enable network to prompt Tor to rebuild
|
// TODO: Disable and re-enable network to prompt Tor to rebuild
|
||||||
// its guard/bridge connections? This will also close any
|
// its guard/bridge connections? This will also close any
|
||||||
@@ -911,10 +906,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int reasonsDisabled = 0;
|
int reasonsDisabled = 0;
|
||||||
boolean enableNetwork = false, enableBridges = false;
|
boolean enableNetwork = false, enableConnectionPadding = false;
|
||||||
boolean enableConnectionPadding = false;
|
List<BridgeType> bridgeTypes = emptyList();
|
||||||
List<BridgeType> bridgeTypes =
|
|
||||||
circumventionProvider.getSuitableBridgeTypes(country);
|
|
||||||
|
|
||||||
if (!online) {
|
if (!online) {
|
||||||
LOG.info("Disabling network, device is offline");
|
LOG.info("Disabling network, device is offline");
|
||||||
@@ -943,8 +936,12 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
enableNetwork = true;
|
enableNetwork = true;
|
||||||
if (network == PREF_TOR_NETWORK_WITH_BRIDGES ||
|
if (network == PREF_TOR_NETWORK_WITH_BRIDGES ||
|
||||||
(automatic && bridgesWork)) {
|
(automatic && bridgesWork)) {
|
||||||
if (ipv6Only) bridgeTypes = singletonList(MEEK);
|
if (ipv6Only) {
|
||||||
enableBridges = true;
|
bridgeTypes = singletonList(MEEK);
|
||||||
|
} else {
|
||||||
|
bridgeTypes = circumventionProvider
|
||||||
|
.getSuitableBridgeTypes(country);
|
||||||
|
}
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info("Using bridge types " + bridgeTypes);
|
LOG.info("Using bridge types " + bridgeTypes);
|
||||||
}
|
}
|
||||||
@@ -964,9 +961,9 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (enableNetwork) {
|
if (enableNetwork) {
|
||||||
enableBridges(enableBridges, bridgeTypes);
|
enableBridges(bridgeTypes);
|
||||||
enableConnectionPadding(enableConnectionPadding);
|
enableConnectionPadding(enableConnectionPadding);
|
||||||
useIpv6(ipv6Only);
|
enableIpv6(ipv6Only);
|
||||||
}
|
}
|
||||||
enableNetwork(enableNetwork);
|
enableNetwork(enableNetwork);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -976,6 +973,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void enableConnectionPadding(boolean enable) throws IOException {
|
private void enableConnectionPadding(boolean enable) throws IOException {
|
||||||
|
if (!state.enableConnectionPadding(enable)) return; // Unchanged
|
||||||
try {
|
try {
|
||||||
controlConnection.setConf("ConnectionPadding", enable ? "1" : "0");
|
controlConnection.setConf("ConnectionPadding", enable ? "1" : "0");
|
||||||
} catch (TorNotRunningException e) {
|
} catch (TorNotRunningException e) {
|
||||||
@@ -983,10 +981,11 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void useIpv6(boolean ipv6Only) throws IOException {
|
private void enableIpv6(boolean enable) throws IOException {
|
||||||
|
if (!state.enableIpv6(enable)) return; // Unchanged
|
||||||
try {
|
try {
|
||||||
controlConnection.setConf("ClientUseIPv4", ipv6Only ? "0" : "1");
|
controlConnection.setConf("ClientUseIPv4", enable ? "0" : "1");
|
||||||
controlConnection.setConf("ClientUseIPv6", ipv6Only ? "1" : "0");
|
controlConnection.setConf("ClientUseIPv6", enable ? "1" : "0");
|
||||||
} catch (TorNotRunningException e) {
|
} catch (TorNotRunningException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -1001,6 +1000,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
stopped = false,
|
stopped = false,
|
||||||
networkInitialised = false,
|
networkInitialised = false,
|
||||||
networkEnabled = false,
|
networkEnabled = false,
|
||||||
|
paddingEnabled = false,
|
||||||
|
ipv6Enabled = false,
|
||||||
bootstrapped = false,
|
bootstrapped = false,
|
||||||
circuitBuilt = false,
|
circuitBuilt = false,
|
||||||
settingsChecked = false;
|
settingsChecked = false;
|
||||||
@@ -1015,6 +1016,9 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
private int orConnectionsConnected = 0;
|
private int orConnectionsConnected = 0;
|
||||||
|
|
||||||
|
@GuardedBy("this")
|
||||||
|
private List<BridgeType> bridgeTypes = emptyList();
|
||||||
|
|
||||||
private synchronized void setStarted() {
|
private synchronized void setStarted() {
|
||||||
started = true;
|
started = true;
|
||||||
callback.pluginStateChanged(getState());
|
callback.pluginStateChanged(getState());
|
||||||
@@ -1035,28 +1039,66 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void setBootstrapped() {
|
private synchronized void setBootstrapped() {
|
||||||
|
boolean wasBootstrapped = bootstrapped;
|
||||||
bootstrapped = true;
|
bootstrapped = true;
|
||||||
callback.pluginStateChanged(getState());
|
if (!wasBootstrapped) callback.pluginStateChanged(getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized boolean getAndSetCircuitBuilt(boolean built) {
|
/**
|
||||||
boolean old = circuitBuilt;
|
* Sets the `circuitBuilt` flag and returns true if the flag has
|
||||||
|
* changed.
|
||||||
|
*/
|
||||||
|
private synchronized boolean setCircuitBuilt(boolean built) {
|
||||||
|
if (built == circuitBuilt) return false; // Unchanged
|
||||||
circuitBuilt = built;
|
circuitBuilt = built;
|
||||||
if (built != old) callback.pluginStateChanged(getState());
|
callback.pluginStateChanged(getState());
|
||||||
return old;
|
return true; // Changed
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void enableNetwork(boolean enable) {
|
/**
|
||||||
|
* Sets the `networkEnabled` flag and returns true if the flag has
|
||||||
|
* changed.
|
||||||
|
*/
|
||||||
|
private synchronized boolean enableNetwork(boolean enable) {
|
||||||
|
boolean wasInitialised = networkInitialised;
|
||||||
|
boolean wasEnabled = networkEnabled;
|
||||||
networkInitialised = true;
|
networkInitialised = true;
|
||||||
networkEnabled = enable;
|
networkEnabled = enable;
|
||||||
if (!enable) circuitBuilt = false;
|
if (!enable) circuitBuilt = false;
|
||||||
callback.pluginStateChanged(getState());
|
if (!wasInitialised || enable != wasEnabled) {
|
||||||
|
callback.pluginStateChanged(getState());
|
||||||
|
}
|
||||||
|
return enable != wasEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void setReasonsDisabled(int reasonsDisabled) {
|
/**
|
||||||
|
* Sets the `paddingEnabled` flag and returns true if the flag has
|
||||||
|
* changed. Doesn't affect getState().
|
||||||
|
*/
|
||||||
|
private synchronized boolean enableConnectionPadding(boolean enable) {
|
||||||
|
if (enable == paddingEnabled) return false; // Unchanged
|
||||||
|
paddingEnabled = enable;
|
||||||
|
return true; // Changed
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the `ipv6Enabled` flag and returns true if the flag has
|
||||||
|
* changed. Doesn't affect getState().
|
||||||
|
*/
|
||||||
|
private synchronized boolean enableIpv6(boolean enable) {
|
||||||
|
if (enable == ipv6Enabled) return false; // Unchanged
|
||||||
|
ipv6Enabled = enable;
|
||||||
|
return true; // Changed
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void setReasonsDisabled(int reasons) {
|
||||||
|
boolean wasChecked = settingsChecked;
|
||||||
settingsChecked = true;
|
settingsChecked = true;
|
||||||
this.reasonsDisabled = reasonsDisabled;
|
int oldReasons = reasonsDisabled;
|
||||||
callback.pluginStateChanged(getState());
|
reasonsDisabled = reasons;
|
||||||
|
if (!wasChecked || reasons != oldReasons) {
|
||||||
|
callback.pluginStateChanged(getState());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Doesn't affect getState()
|
// Doesn't affect getState()
|
||||||
@@ -1071,6 +1113,17 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
if (serverSocket == ss) serverSocket = null;
|
if (serverSocket == ss) serverSocket = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the list of bridge types being used and returns true if the
|
||||||
|
* list has changed. The list is empty if bridges are disabled.
|
||||||
|
* Doesn't affect getState().
|
||||||
|
*/
|
||||||
|
private synchronized boolean setBridgeTypes(List<BridgeType> types) {
|
||||||
|
if (types.equals(bridgeTypes)) return false; // Unchanged
|
||||||
|
bridgeTypes = types;
|
||||||
|
return true; // Changed
|
||||||
|
}
|
||||||
|
|
||||||
private synchronized State getState() {
|
private synchronized State getState() {
|
||||||
if (!started || stopped || !settingsChecked) {
|
if (!started || stopped || !settingsChecked) {
|
||||||
return STARTING_STOPPING;
|
return STARTING_STOPPING;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
|
|||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager.OpenDatabaseHook;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager.OpenDatabaseHook;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.Service;
|
||||||
import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
|
import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
@@ -12,12 +13,10 @@ import org.briarproject.bramble.test.DbExpectations;
|
|||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
import static junit.framework.TestCase.assertTrue;
|
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RUNNING;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RUNNING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPED;
|
||||||
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.CLOCK_ERROR;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.CLOCK_ERROR;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
|
||||||
import static org.briarproject.bramble.api.system.Clock.MAX_REASONABLE_TIME_MS;
|
import static org.briarproject.bramble.api.system.Clock.MAX_REASONABLE_TIME_MS;
|
||||||
@@ -30,6 +29,8 @@ public class LifecycleManagerImplTest extends BrambleMockTestCase {
|
|||||||
private final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
private final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
private final EventBus eventBus = context.mock(EventBus.class);
|
private final EventBus eventBus = context.mock(EventBus.class);
|
||||||
private final Clock clock = context.mock(Clock.class);
|
private final Clock clock = context.mock(Clock.class);
|
||||||
|
private final OpenDatabaseHook hook = context.mock(OpenDatabaseHook.class);
|
||||||
|
private final Service service = context.mock(Service.class);
|
||||||
|
|
||||||
private final SecretKey dbKey = getSecretKey();
|
private final SecretKey dbKey = getSecretKey();
|
||||||
|
|
||||||
@@ -40,8 +41,6 @@ public class LifecycleManagerImplTest extends BrambleMockTestCase {
|
|||||||
public void testOpenDatabaseHooksAreCalledAtStartup() throws Exception {
|
public void testOpenDatabaseHooksAreCalledAtStartup() throws Exception {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
AtomicBoolean called = new AtomicBoolean(false);
|
|
||||||
OpenDatabaseHook hook = transaction -> called.set(true);
|
|
||||||
|
|
||||||
context.checking(new DbExpectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
@@ -50,6 +49,7 @@ public class LifecycleManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||||
oneOf(db).removeTemporaryMessages(txn);
|
oneOf(db).removeTemporaryMessages(txn);
|
||||||
|
oneOf(hook).onDatabaseOpened(txn);
|
||||||
allowing(eventBus).broadcast(with(any(LifecycleEvent.class)));
|
allowing(eventBus).broadcast(with(any(LifecycleEvent.class)));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
@@ -57,7 +57,38 @@ public class LifecycleManagerImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
assertEquals(SUCCESS, lifecycleManager.startServices(dbKey));
|
assertEquals(SUCCESS, lifecycleManager.startServices(dbKey));
|
||||||
assertEquals(RUNNING, lifecycleManager.getLifecycleState());
|
assertEquals(RUNNING, lifecycleManager.getLifecycleState());
|
||||||
assertTrue(called.get());
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testServicesAreStartedAndStopped() throws Exception {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
|
context.checking(new DbExpectations() {{
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(now));
|
||||||
|
oneOf(db).open(dbKey, lifecycleManager);
|
||||||
|
will(returnValue(false));
|
||||||
|
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||||
|
oneOf(db).removeTemporaryMessages(txn);
|
||||||
|
oneOf(service).startService();
|
||||||
|
allowing(eventBus).broadcast(with(any(LifecycleEvent.class)));
|
||||||
|
}});
|
||||||
|
|
||||||
|
lifecycleManager.registerService(service);
|
||||||
|
|
||||||
|
assertEquals(SUCCESS, lifecycleManager.startServices(dbKey));
|
||||||
|
assertEquals(RUNNING, lifecycleManager.getLifecycleState());
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(db).close();
|
||||||
|
oneOf(service).stopService();
|
||||||
|
allowing(eventBus).broadcast(with(any(LifecycleEvent.class)));
|
||||||
|
}});
|
||||||
|
|
||||||
|
lifecycleManager.stopServices();
|
||||||
|
assertEquals(STOPPED, lifecycleManager.getLifecycleState());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -84,6 +115,31 @@ public class LifecycleManagerImplTest extends BrambleMockTestCase {
|
|||||||
assertEquals(STARTING, lifecycleManager.getLifecycleState());
|
assertEquals(STARTING, lifecycleManager.getLifecycleState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSecondCallToStartServicesReturnsEarly() throws Exception {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
|
context.checking(new DbExpectations() {{
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(now));
|
||||||
|
oneOf(db).open(dbKey, lifecycleManager);
|
||||||
|
will(returnValue(false));
|
||||||
|
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||||
|
oneOf(db).removeTemporaryMessages(txn);
|
||||||
|
allowing(eventBus).broadcast(with(any(LifecycleEvent.class)));
|
||||||
|
}});
|
||||||
|
|
||||||
|
assertEquals(SUCCESS, lifecycleManager.startServices(dbKey));
|
||||||
|
assertEquals(RUNNING, lifecycleManager.getLifecycleState());
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
|
||||||
|
// Calling startServices() again should not try to open the DB or
|
||||||
|
// start the services again
|
||||||
|
assertEquals(ALREADY_RUNNING, lifecycleManager.startServices(dbKey));
|
||||||
|
assertEquals(RUNNING, lifecycleManager.getLifecycleState());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSecondCallToStopServicesReturnsEarly() throws Exception {
|
public void testSecondCallToStopServicesReturnsEarly() throws Exception {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
@@ -96,7 +152,7 @@ public class LifecycleManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||||
oneOf(db).removeTemporaryMessages(txn);
|
oneOf(db).removeTemporaryMessages(txn);
|
||||||
exactly(2).of(eventBus).broadcast(with(any(LifecycleEvent.class)));
|
allowing(eventBus).broadcast(with(any(LifecycleEvent.class)));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
assertEquals(SUCCESS, lifecycleManager.startServices(dbKey));
|
assertEquals(SUCCESS, lifecycleManager.startServices(dbKey));
|
||||||
@@ -104,17 +160,17 @@ public class LifecycleManagerImplTest extends BrambleMockTestCase {
|
|||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(eventBus).broadcast(with(any(LifecycleEvent.class)));
|
|
||||||
oneOf(db).close();
|
oneOf(db).close();
|
||||||
|
allowing(eventBus).broadcast(with(any(LifecycleEvent.class)));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
lifecycleManager.stopServices();
|
lifecycleManager.stopServices();
|
||||||
assertEquals(STOPPING, lifecycleManager.getLifecycleState());
|
assertEquals(STOPPED, lifecycleManager.getLifecycleState());
|
||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
|
|
||||||
// Calling stopServices() again should not broadcast another event or
|
// Calling stopServices() again should not broadcast another event or
|
||||||
// try to close the DB again
|
// try to close the DB again
|
||||||
lifecycleManager.stopServices();
|
lifecycleManager.stopServices();
|
||||||
assertEquals(STOPPING, lifecycleManager.getLifecycleState());
|
assertEquals(STOPPED, lifecycleManager.getLifecycleState());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode 10409
|
versionCode 10410
|
||||||
versionName "1.4.9"
|
versionName "1.4.10"
|
||||||
applicationId "org.briarproject.briar.android"
|
applicationId "org.briarproject.briar.android"
|
||||||
|
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
|
|||||||
@@ -156,8 +156,11 @@ public class BriarService extends Service {
|
|||||||
if (result == SUCCESS) {
|
if (result == SUCCESS) {
|
||||||
started = true;
|
started = true;
|
||||||
} else if (result == ALREADY_RUNNING) {
|
} else if (result == ALREADY_RUNNING) {
|
||||||
LOG.info("Already running");
|
LOG.warning("Already running");
|
||||||
stopSelf();
|
// The core has outlived the original BriarService
|
||||||
|
// instance. We don't know how to recover from this
|
||||||
|
// unexpected state, so try to exit cleanly
|
||||||
|
shutdownFromBackground();
|
||||||
} else {
|
} else {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.warning("Startup failed: " + result);
|
LOG.warning("Startup failed: " + result);
|
||||||
|
|||||||
@@ -26,6 +26,10 @@
|
|||||||
<string name="dnkm_xiaomi_button">Proteggi Briar</string>
|
<string name="dnkm_xiaomi_button">Proteggi Briar</string>
|
||||||
<string name="dnkm_xiaomi_help">Se Briar non è fissato nella lista di app recenti, non potrà funzionare in secondo piano.</string>
|
<string name="dnkm_xiaomi_help">Se Briar non è fissato nella lista di app recenti, non potrà funzionare in secondo piano.</string>
|
||||||
<string name="dnkm_xiaomi_dialog_body_old">1. Apri la lista di app recenti (chiamata anche app switcher)\n\n2. Scorri fino alla schermata di Briar per mostrare l\'icona del lucchetto\n\n3. Se il lucchetto non è chiuso, toccalo per chiuderlo</string>
|
<string name="dnkm_xiaomi_dialog_body_old">1. Apri la lista di app recenti (chiamata anche app switcher)\n\n2. Scorri fino alla schermata di Briar per mostrare l\'icona del lucchetto\n\n3. Se il lucchetto non è chiuso, toccalo per chiuderlo</string>
|
||||||
|
<string name="dnkm_xiaomi_dialog_body_new">1. Apri la lista di app recenti (chiamata anche app switcher)\n\n2. Se Briar ha un piccolo lucchetto accanto al nome, allora non devi fare nulla\n\n3. Se non c\'è un lucchetto, tieni premuta la schermata di Briar finché non compare l\'icona del lucchetto, poi toccala</string>
|
||||||
|
<string name="dnkm_xiaomi_lock_apps_text">Tocca il pulsante sottostante per aprire le impostazioni di sicurezza. Tocca \"Aumenta velocità\", poi \"Blocca le app\" e assicurati che Briar sia impostato su \"Bloccato\".</string>
|
||||||
|
<string name="dnkm_xiaomi_lock_apps_help">Se Briar non è impostato su \"Bloccato\" nella schermata \"Blocca le app\", non riuscirà a funzionare in secondo piano.</string>
|
||||||
|
<string name="dnkm_warning_dozed_1">Briar non è riuscito a funzionare in secondo piano</string>
|
||||||
<!--Login-->
|
<!--Login-->
|
||||||
<string name="enter_password">Password</string>
|
<string name="enter_password">Password</string>
|
||||||
<string name="try_again">Password sbagliata, riprova</string>
|
<string name="try_again">Password sbagliata, riprova</string>
|
||||||
@@ -238,6 +242,8 @@
|
|||||||
<string name="contact_added_toast">Contatto aggiunto: %s</string>
|
<string name="contact_added_toast">Contatto aggiunto: %s</string>
|
||||||
<string name="contact_already_exists">Il contatto %s esiste già</string>
|
<string name="contact_already_exists">Il contatto %s esiste già</string>
|
||||||
<string name="qr_code_invalid">Il codice QR non è valido</string>
|
<string name="qr_code_invalid">Il codice QR non è valido</string>
|
||||||
|
<string name="qr_code_too_old_1">Il codice QR che hai scansionato proviene da una versione più vecchia di Briar.\n\nChiedi al tuo contatto di aggiornare all\'ultima versione e poi riprova.</string>
|
||||||
|
<string name="qr_code_too_new_1">Il codice QR che hai scansionato proviene da una versione più recente di Briar.\n\nAggiorna all\'ultima versione e poi riprova.</string>
|
||||||
<string name="camera_error">Errore fotocamera</string>
|
<string name="camera_error">Errore fotocamera</string>
|
||||||
<string name="connecting_to_device">Connessione al dispositivo\u2026</string>
|
<string name="connecting_to_device">Connessione al dispositivo\u2026</string>
|
||||||
<string name="authenticating_with_device">Autenticazione con il dispositivo\u2026</string>
|
<string name="authenticating_with_device">Autenticazione con il dispositivo\u2026</string>
|
||||||
@@ -613,6 +619,10 @@
|
|||||||
<string name="mailbox_status_connected_title">Casella postale in esecuzione</string>
|
<string name="mailbox_status_connected_title">Casella postale in esecuzione</string>
|
||||||
<string name="mailbox_status_problem_title">Briar sta avendo problemi a connettersi alla casella postale</string>
|
<string name="mailbox_status_problem_title">Briar sta avendo problemi a connettersi alla casella postale</string>
|
||||||
<string name="mailbox_status_failure_title">Casella postale non disponibile</string>
|
<string name="mailbox_status_failure_title">Casella postale non disponibile</string>
|
||||||
|
<string name="mailbox_status_app_too_old_title">Briar è troppo vecchio</string>
|
||||||
|
<string name="mailbox_status_app_too_old_message">Aggiorna Briar all\'ultima versione e riprova.</string>
|
||||||
|
<string name="mailbox_status_mailbox_too_old_title">La cassella postale è troppo vecchia</string>
|
||||||
|
<string name="mailbox_status_mailbox_too_old_message">Aggiorna la casella postale all\'ultima versione e riprova.</string>
|
||||||
<string name="mailbox_status_check_button">Controlla connessione</string>
|
<string name="mailbox_status_check_button">Controlla connessione</string>
|
||||||
<!--Example for string substitution: Last connection: 3min ago-->
|
<!--Example for string substitution: Last connection: 3min ago-->
|
||||||
<string name="mailbox_status_connected_info">Ultima connessione: %s</string>
|
<string name="mailbox_status_connected_info">Ultima connessione: %s</string>
|
||||||
@@ -764,6 +774,9 @@
|
|||||||
<string name="hotspot_manual_site_address">Indirizzo (URL)</string>
|
<string name="hotspot_manual_site_address">Indirizzo (URL)</string>
|
||||||
<string name="hotspot_qr_site">Il tuo telefono sta fornendo un hotspot Wi-Fi. Le persone connesse all\'hotspot possono scaricare Briar scansionando questo codice QR.</string>
|
<string name="hotspot_qr_site">Il tuo telefono sta fornendo un hotspot Wi-Fi. Le persone connesse all\'hotspot possono scaricare Briar scansionando questo codice QR.</string>
|
||||||
<!--e.g. Download Briar 1.2.20-->
|
<!--e.g. Download Briar 1.2.20-->
|
||||||
|
<string name="website_download_title_1">Scarica Briar %s</string>
|
||||||
|
<string name="website_download_intro_1">Qualcuno nelle vicinanze ha condiviso Briar con te.</string>
|
||||||
|
<string name="website_download_button">Scarica Briar</string>
|
||||||
<string name="website_download_outro">Dopo il completamento del download, apri il file scaricato e installalo.</string>
|
<string name="website_download_outro">Dopo il completamento del download, apri il file scaricato e installalo.</string>
|
||||||
<string name="website_troubleshooting_title">Risoluzione dei problemi</string>
|
<string name="website_troubleshooting_title">Risoluzione dei problemi</string>
|
||||||
<string name="website_troubleshooting_1">Se non puoi scaricare l\'app, prova con un browser web diverso.</string>
|
<string name="website_troubleshooting_1">Se non puoi scaricare l\'app, prova con un browser web diverso.</string>
|
||||||
|
|||||||
@@ -41,10 +41,10 @@
|
|||||||
<string name="dialog_message_lost_password">Contul dumneavoastră Briar este stocat în mod criptat pe dispozitivul dumneavoastră, nu în cloud, așa că nu vă putem reseta parola. Doriți să vă ștergeți contul și să o luați de la capăt?\n\nAtenție: Identitățile, contactele și mesajele dumneavoastră vor fi pierdute definitiv.</string>
|
<string name="dialog_message_lost_password">Contul dumneavoastră Briar este stocat în mod criptat pe dispozitivul dumneavoastră, nu în cloud, așa că nu vă putem reseta parola. Doriți să vă ștergeți contul și să o luați de la capăt?\n\nAtenție: Identitățile, contactele și mesajele dumneavoastră vor fi pierdute definitiv.</string>
|
||||||
<string name="startup_failed_activity_title">Eroare de pornire Briar</string>
|
<string name="startup_failed_activity_title">Eroare de pornire Briar</string>
|
||||||
<string name="startup_failed_clock_error">Briar nu a putut porni deoarece ceasul dispozitivului dvs. este greșit.\n\nVă rugăm să setați ceasul dispozitivului dvs. la ora corectă și să încercați din nou.</string>
|
<string name="startup_failed_clock_error">Briar nu a putut porni deoarece ceasul dispozitivului dvs. este greșit.\n\nVă rugăm să setați ceasul dispozitivului dvs. la ora corectă și să încercați din nou.</string>
|
||||||
<string name="startup_failed_db_error">Briar nu a reușit să deschidă baza de date care conține contul dumneavoastră, contactele și mesajele dumneavoastră.\n\nVă rugăm să faceți upgrade la cea mai recentă versiune a app și să încercați din nou, sau să configurați un cont nou alegând \"Mi-am uitat parola\" la solicitarea parolei.</string>
|
<string name="startup_failed_db_error">Briar nu a reușit să deschidă baza de date care conține contul dumneavoastră, contactele și mesajele dumneavoastră.\n\nVă rugăm să faceți upgrade la cea mai recentă versiune a aplicației și să încercați din nou, sau să configurați un cont nou alegând \"Mi-am uitat parola\" la solicitarea parolei.</string>
|
||||||
<string name="startup_failed_data_too_old_error">Contul dvs. a fost creat cu o versiune veche a acestei aplicații și nu poate fi deschis cu această versiune.\n\nTrebuie fie să reinstalați versiunea veche, fie să creați un cont nou alegând \"Mi-am uitat parola\" la solicitarea de parolă.</string>
|
<string name="startup_failed_data_too_old_error">Contul dvs. a fost creat cu o versiune veche a acestei aplicații și nu poate fi deschis cu această versiune.\n\nTrebuie fie să reinstalați versiunea veche, fie să creați un cont nou alegând \"Mi-am uitat parola\" la solicitarea de parolă.</string>
|
||||||
<string name="startup_failed_data_too_new_error">Contul dvs. a fost creat cu o versiune mai nouă a acestei aplicații și nu poate fi deschis cu această versiune.\n\nVă rugăm să faceți upgrade la cea mai recentă versiune și să încercați din nou.</string>
|
<string name="startup_failed_data_too_new_error">Contul dvs. a fost creat cu o versiune mai nouă a acestei aplicații și nu poate fi deschis cu această versiune.\n\nVă rugăm să faceți upgrade la cea mai recentă versiune și să încercați din nou.</string>
|
||||||
<string name="startup_failed_service_error">Briar nu a reușit să pornească o componentă necesară.\n\nVă rugăm să faceți upgrade la cea mai recentă versiune a acestui app și să încercați din nou.</string>
|
<string name="startup_failed_service_error">Briar nu a reușit să pornească o componentă necesară.\n\nVă rugăm să faceți upgrade la cea mai recentă versiune a acestei aplicații și să încercați din nou.</string>
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="one">Aceasta este o versiune de test pentru Briar. Contul dumneavoastră va expira în %d zi și nu se poate reînnoi</item>
|
<item quantity="one">Aceasta este o versiune de test pentru Briar. Contul dumneavoastră va expira în %d zi și nu se poate reînnoi</item>
|
||||||
<item quantity="few">Aceasta este o versiune de test pentru Briar. Contul dumneavoastră va expira în %d zile și nu se poate reînnoi.</item>
|
<item quantity="few">Aceasta este o versiune de test pentru Briar. Contul dumneavoastră va expira în %d zile și nu se poate reînnoi.</item>
|
||||||
@@ -554,12 +554,12 @@
|
|||||||
<string name="password_changed">Parola a fost schimbată.</string>
|
<string name="password_changed">Parola a fost schimbată.</string>
|
||||||
<string name="panic_setting">Setare buton de panică</string>
|
<string name="panic_setting">Setare buton de panică</string>
|
||||||
<string name="panic_setting_title">Buton de panică</string>
|
<string name="panic_setting_title">Buton de panică</string>
|
||||||
<string name="panic_setting_hint">Configurați cum va reacționa Briar atunci când folosiți un app de buton de panică.</string>
|
<string name="panic_setting_hint">Configurați cum va reacționa Briar atunci când folosiți o aplicație de buton de panică.</string>
|
||||||
<string name="panic_app_setting_title">App buton de panică</string>
|
<string name="panic_app_setting_title">Aplicație buton de panică</string>
|
||||||
<string name="unknown_app">app necunoscut</string>
|
<string name="unknown_app">aplicație necunoscută</string>
|
||||||
<string name="panic_app_setting_summary">Nu a fost setată nici un app</string>
|
<string name="panic_app_setting_summary">Nu a fost setată nici o aplicație</string>
|
||||||
<string name="panic_app_setting_none">Nici una</string>
|
<string name="panic_app_setting_none">Nici una</string>
|
||||||
<string name="dialog_title_connect_panic_app">Confirmare app de panică</string>
|
<string name="dialog_title_connect_panic_app">Confirmare aplicație de panică</string>
|
||||||
<string name="dialog_message_connect_panic_app">Sigur doriți să permiteți %1$s să declanșeze acțiuni destructive pentru butonul de panică?</string>
|
<string name="dialog_message_connect_panic_app">Sigur doriți să permiteți %1$s să declanșeze acțiuni destructive pentru butonul de panică?</string>
|
||||||
<string name="panic_setting_destructive_action">Acțiuni distructive</string>
|
<string name="panic_setting_destructive_action">Acțiuni distructive</string>
|
||||||
<string name="panic_setting_signout_title">Ieșire</string>
|
<string name="panic_setting_signout_title">Ieșire</string>
|
||||||
@@ -606,7 +606,7 @@
|
|||||||
<string name="mailbox_setup_io_error_title">Nu s-a putut conecta</string>
|
<string name="mailbox_setup_io_error_title">Nu s-a putut conecta</string>
|
||||||
<string name="mailbox_setup_io_error_description">Asigurați-vă că ambele dispozitive sunt conectate la Internet și încercați din nou.</string>
|
<string name="mailbox_setup_io_error_description">Asigurați-vă că ambele dispozitive sunt conectate la Internet și încercați din nou.</string>
|
||||||
<string name="mailbox_setup_assertion_error_title">Eroare de Cutie poștală</string>
|
<string name="mailbox_setup_assertion_error_title">Eroare de Cutie poștală</string>
|
||||||
<string name="mailbox_setup_assertion_error_description">Vă rugăm să trimiteți feedback (cu date anonime) prin intermediul app-ului Briar dacă problema persistă.</string>
|
<string name="mailbox_setup_assertion_error_description">Vă rugăm să trimiteți feedback (cu date anonime) prin intermediul aplicației Briar dacă problema persistă.</string>
|
||||||
<string name="mailbox_setup_camera_error_description">Nu s-a putut accesa camera. Încercați din nou, poate după repornirea dispozitivului.</string>
|
<string name="mailbox_setup_camera_error_description">Nu s-a putut accesa camera. Încercați din nou, poate după repornirea dispozitivului.</string>
|
||||||
<string name="mailbox_setup_paired_title">Conectat</string>
|
<string name="mailbox_setup_paired_title">Conectat</string>
|
||||||
<string name="mailbox_setup_paired_description">Cutia dumneavoastră poștală a fost atașată cu succes la Briar.\n
|
<string name="mailbox_setup_paired_description">Cutia dumneavoastră poștală a fost atașată cu succes la Briar.\n
|
||||||
@@ -742,7 +742,7 @@ De asemenea, contactul dvs. poate modifica această setare pentru amândoi.</str
|
|||||||
<string name="transports_help_text">Briar se poate conecta la contactele dumneavoastră prin Internet, Wi-Fi sau Bluetooth.\n\nToate conexiunile la internet trec prin rețeaua Tor din motive de confidențialitate.\n\nDacă un contact poate fi accesat prin metode multiple, Briar le va folosi în mod paralel.</string>
|
<string name="transports_help_text">Briar se poate conecta la contactele dumneavoastră prin Internet, Wi-Fi sau Bluetooth.\n\nToate conexiunile la internet trec prin rețeaua Tor din motive de confidențialitate.\n\nDacă un contact poate fi accesat prin metode multiple, Briar le va folosi în mod paralel.</string>
|
||||||
<!--Share app offline-->
|
<!--Share app offline-->
|
||||||
<string name="hotspot_title">Partajează această aplicație fără Internet</string>
|
<string name="hotspot_title">Partajează această aplicație fără Internet</string>
|
||||||
<string name="hotspot_intro">Împărtășiți acest app cu o persoană din apropiere fără conexiune la Internet, utilizând Wi-Fi-ul telefonului dumneavoastră.
|
<string name="hotspot_intro">Împărtășiți această aplicație cu o persoană din apropiere fără conexiune la Internet, utilizând Wi-Fi-ul telefonului dumneavoastră.
|
||||||
\n\nTelefonul dumneavoastră va porni un hotspot Wi-Fi. Persoanele din apropiere se pot conecta la hotspot și pot descărca aplicația Briar de pe telefonul vostru.</string>
|
\n\nTelefonul dumneavoastră va porni un hotspot Wi-Fi. Persoanele din apropiere se pot conecta la hotspot și pot descărca aplicația Briar de pe telefonul vostru.</string>
|
||||||
<string name="hotspot_button_start_sharing">Pornește hotspot</string>
|
<string name="hotspot_button_start_sharing">Pornește hotspot</string>
|
||||||
<string name="hotspot_button_stop_sharing">Oprește hotspot</string>
|
<string name="hotspot_button_stop_sharing">Oprește hotspot</string>
|
||||||
@@ -793,7 +793,7 @@ De asemenea, contactul dvs. poate modifica această setare pentru amândoi.</str
|
|||||||
<string name="hotspot_help_site_4">Dacă puteți vizita siteul dar nu puteți descărca aplicația Briar, încercați cu un alt browser.</string>
|
<string name="hotspot_help_site_4">Dacă puteți vizita siteul dar nu puteți descărca aplicația Briar, încercați cu un alt browser.</string>
|
||||||
<string name="hotspot_help_fallback_title">Nimic nu funcționează?</string>
|
<string name="hotspot_help_fallback_title">Nimic nu funcționează?</string>
|
||||||
<string name="hotspot_help_fallback_intro">Puteți încerca să salvați aplicația ca un fișier .APK pentru a-l partaja în alt mod. Odată fișierul transferat pe celălalt dispozitiv, poate fi folosit să se instaleze Briar.
|
<string name="hotspot_help_fallback_intro">Puteți încerca să salvați aplicația ca un fișier .APK pentru a-l partaja în alt mod. Odată fișierul transferat pe celălalt dispozitiv, poate fi folosit să se instaleze Briar.
|
||||||
\n\nPont: Pentru a partaja prin Bluetooth s-ar putea sa fie necesar sa redenumiți fișierul ca să aivă terminația .ZIP.</string>
|
\n\nPont: Pentru a partaja prin Bluetooth s-ar putea sa fie necesar sa redenumiți fișierul ca să aibă terminația .ZIP.</string>
|
||||||
<string name="hotspot_help_fallback_button">Salvează aplicația</string>
|
<string name="hotspot_help_fallback_button">Salvează aplicația</string>
|
||||||
<!--error handling-->
|
<!--error handling-->
|
||||||
<string name="hotspot_error_intro">A apărut o problemă când s-a încercat partajarea aplicației prin Wi-Fi.</string>
|
<string name="hotspot_error_intro">A apărut o problemă când s-a încercat partajarea aplicației prin Wi-Fi.</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user