diff --git a/bramble-android/build.gradle b/bramble-android/build.gradle index f7c9415ed..758fe7a42 100644 --- a/bramble-android/build.gradle +++ b/bramble-android/build.gradle @@ -27,7 +27,6 @@ configurations { dependencies { implementation project(path: ':bramble-core', configuration: 'default') - implementation 'org.briarproject:jtorctl:0.3' tor 'org.briarproject:tor-android:0.2.9.16@zip' annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2' @@ -115,7 +114,6 @@ dependencyVerification { 'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8', 'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca', 'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349', - 'org.briarproject:jtorctl:0.3:jtorctl-0.3.jar:f2939238a097898998432effe93b0334d97a787972ab3a91a8973a1d309fc864', 'org.briarproject:tor-android:0.2.9.16:tor-android-0.2.9.16.zip:515e33dda6a30853c885a2de2c79ae1ab9ad8b6db44f5db8890333ec2e24f4ae', 'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4', 'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d', diff --git a/bramble-android/src/androidTest/java/org/briarproject/bramble/plugin/tor/BridgeTest.java b/bramble-android/src/androidTest/java/org/briarproject/bramble/plugin/tor/BridgeTest.java index fb3e4b5ab..8800f8856 100644 --- a/bramble-android/src/androidTest/java/org/briarproject/bramble/plugin/tor/BridgeTest.java +++ b/bramble-android/src/androidTest/java/org/briarproject/bramble/plugin/tor/BridgeTest.java @@ -9,6 +9,7 @@ import org.briarproject.bramble.api.plugin.BackoffFactory; import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.LocationUtils; +import org.briarproject.bramble.api.system.ResourceProvider; import org.briarproject.bramble.test.BrambleAndroidIntegrationTestComponent; import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.bramble.test.DaggerBrambleAndroidIntegrationTestComponent; @@ -45,38 +46,23 @@ public class BridgeTest extends BrambleTestCase { @Inject NetworkManager networkManager; @Inject + ResourceProvider resourceProvider; + @Inject + CircumventionProvider circumventionProvider; + @Inject EventBus eventBus; @Inject BackoffFactory backoffFactory; @Inject Clock clock; - private final Context appContext = getTargetContext(); - private final CircumventionProvider circumventionProvider; - private final List bridges; - private TorPluginFactory factory; - private volatile int currentBridge = 0; + private final Context appContext = + getTargetContext().getApplicationContext(); - public BridgeTest() { - super(); - circumventionProvider = new CircumventionProvider() { - @Override - public boolean isTorProbablyBlocked(String countryCode) { - return true; - } + private List bridges; + private AndroidTorPluginFactory factory; - @Override - public boolean doBridgesWork(String countryCode) { - return true; - } - - @Override - public List getBridges() { - return singletonList(bridges.get(currentBridge)); - } - }; - bridges = new CircumventionProviderImpl(appContext).getBridges(); - } + private volatile String currentBridge = null; @Before public void setUp() { @@ -89,28 +75,43 @@ public class BridgeTest extends BrambleTestCase { LocationUtils locationUtils = () -> "US"; SocketFactory torSocketFactory = SocketFactory.getDefault(); - factory = new TorPluginFactory(ioExecutor, scheduler, appContext, + bridges = circumventionProvider.getBridges(); + CircumventionProvider bridgeProvider = new CircumventionProvider() { + @Override + public boolean isTorProbablyBlocked(String countryCode) { + return true; + } + + @Override + public boolean doBridgesWork(String countryCode) { + return true; + } + + @Override + public List getBridges() { + return singletonList(currentBridge); + } + }; + factory = new AndroidTorPluginFactory(ioExecutor, scheduler, appContext, networkManager, locationUtils, eventBus, torSocketFactory, - backoffFactory, circumventionProvider, clock); + backoffFactory, resourceProvider, bridgeProvider, clock); } @Test public void testBridges() throws Exception { assertTrue(bridges.size() > 0); - for (int i = 0; i < bridges.size(); i++) { - testBridge(i); - } + for (String bridge : bridges) testBridge(bridge); } - private void testBridge(int bridge) throws Exception { + private void testBridge(String bridge) throws Exception { DuplexPlugin duplexPlugin = factory.createPlugin(new TorPluginCallBack()); assertNotNull(duplexPlugin); - TorPlugin plugin = (TorPlugin) duplexPlugin; + AndroidTorPlugin plugin = (AndroidTorPlugin) duplexPlugin; currentBridge = bridge; - LOG.warning("Testing " + bridges.get(currentBridge)); + LOG.warning("Testing " + bridge); try { plugin.start(); long start = clock.currentTimeMillis(); diff --git a/bramble-android/src/androidTest/java/org/briarproject/bramble/test/ApplicationModule.java b/bramble-android/src/androidTest/java/org/briarproject/bramble/test/ApplicationModule.java index f67f32edb..df642cf95 100644 --- a/bramble-android/src/androidTest/java/org/briarproject/bramble/test/ApplicationModule.java +++ b/bramble-android/src/androidTest/java/org/briarproject/bramble/test/ApplicationModule.java @@ -1,20 +1,20 @@ package org.briarproject.bramble.test; import android.app.Application; -import android.support.test.InstrumentationRegistry; import javax.inject.Singleton; import dagger.Module; import dagger.Provides; +import static android.support.test.InstrumentationRegistry.getTargetContext; + @Module class ApplicationModule { @Provides @Singleton Application provideApplication() { - return (Application) InstrumentationRegistry.getTargetContext() - .getApplicationContext(); + return (Application) getTargetContext().getApplicationContext(); } } diff --git a/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java b/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java index 48c49794e..713c007c5 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java @@ -1,27 +1,16 @@ package org.briarproject.bramble; -import android.app.Application; - import org.briarproject.bramble.network.AndroidNetworkModule; -import org.briarproject.bramble.plugin.tor.CircumventionProvider; -import org.briarproject.bramble.plugin.tor.CircumventionProviderImpl; +import org.briarproject.bramble.plugin.tor.CircumventionModule; import org.briarproject.bramble.system.AndroidSystemModule; -import javax.inject.Singleton; - import dagger.Module; -import dagger.Provides; @Module(includes = { AndroidNetworkModule.class, - AndroidSystemModule.class + AndroidSystemModule.class, + CircumventionModule.class }) public class BrambleAndroidModule { - @Provides - @Singleton - CircumventionProvider provideCircumventionProvider(Application app) { - return new CircumventionProviderImpl(app.getApplicationContext()); - } - } diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java new file mode 100644 index 000000000..c2cdac186 --- /dev/null +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java @@ -0,0 +1,88 @@ +package org.briarproject.bramble.plugin.tor; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.PowerManager; + +import org.briarproject.bramble.api.network.NetworkManager; +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.bramble.api.plugin.Backoff; +import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.system.LocationUtils; +import org.briarproject.bramble.api.system.ResourceProvider; +import org.briarproject.bramble.util.RenewableWakeLock; + +import java.io.IOException; +import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; + +import javax.net.SocketFactory; + +import static android.content.Context.MODE_PRIVATE; +import static android.content.Context.POWER_SERVICE; +import static android.os.PowerManager.PARTIAL_WAKE_LOCK; +import static java.util.concurrent.TimeUnit.MINUTES; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +class AndroidTorPlugin extends TorPlugin { + + // This tag may prevent Huawei's power manager from killing us + private static final String WAKE_LOCK_TAG = "LocationManagerService"; + + private final Context appContext; + private final RenewableWakeLock wakeLock; + + AndroidTorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler, + Context appContext, NetworkManager networkManager, + LocationUtils locationUtils, SocketFactory torSocketFactory, + Clock clock, ResourceProvider resourceProvider, + CircumventionProvider circumventionProvider, Backoff backoff, + DuplexPluginCallback callback, String architecture, int maxLatency, + int maxIdleTime) { + super(ioExecutor, networkManager, locationUtils, torSocketFactory, + clock, resourceProvider, circumventionProvider, backoff, + callback, architecture, maxLatency, maxIdleTime, + appContext.getDir("tor", MODE_PRIVATE)); + this.appContext = appContext; + PowerManager pm = (PowerManager) + appContext.getSystemService(POWER_SERVICE); + assert pm != null; + wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK, + WAKE_LOCK_TAG, 1, MINUTES); + } + + @Override + protected int getProcessId() { + return android.os.Process.myPid(); + } + + @Override + protected long getLastUpdateTime() { + try { + PackageManager pm = appContext.getPackageManager(); + PackageInfo pi = pm.getPackageInfo(appContext.getPackageName(), 0); + return pi.lastUpdateTime; + } catch (NameNotFoundException e) { + throw new AssertionError(e); + } + } + + @Override + protected void enableNetwork(boolean enable) throws IOException { + if (!running) return; + if (enable) wakeLock.acquire(); + super.enableNetwork(enable); + if (!enable) wakeLock.release(); + } + + @Override + public void stop() { + super.stop(); + wakeLock.release(); + } +} diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPluginFactory.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPluginFactory.java similarity index 83% rename from bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPluginFactory.java rename to bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPluginFactory.java index 1055a03a7..7287317a9 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPluginFactory.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPluginFactory.java @@ -15,6 +15,7 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.LocationUtils; +import org.briarproject.bramble.api.system.ResourceProvider; import org.briarproject.bramble.util.AndroidUtils; import java.util.concurrent.Executor; @@ -26,10 +27,10 @@ import javax.net.SocketFactory; @Immutable @NotNullByDefault -public class TorPluginFactory implements DuplexPluginFactory { +public class AndroidTorPluginFactory implements DuplexPluginFactory { private static final Logger LOG = - Logger.getLogger(TorPluginFactory.class.getName()); + Logger.getLogger(AndroidTorPluginFactory.class.getName()); private static final int MAX_LATENCY = 30 * 1000; // 30 seconds private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds @@ -45,14 +46,15 @@ public class TorPluginFactory implements DuplexPluginFactory { private final EventBus eventBus; private final SocketFactory torSocketFactory; private final BackoffFactory backoffFactory; + private final ResourceProvider resourceProvider; private final CircumventionProvider circumventionProvider; private final Clock clock; - public TorPluginFactory(Executor ioExecutor, + public AndroidTorPluginFactory(Executor ioExecutor, ScheduledExecutorService scheduler, Context appContext, NetworkManager networkManager, LocationUtils locationUtils, EventBus eventBus, SocketFactory torSocketFactory, - BackoffFactory backoffFactory, + BackoffFactory backoffFactory, ResourceProvider resourceProvider, CircumventionProvider circumventionProvider, Clock clock) { this.ioExecutor = ioExecutor; this.scheduler = scheduler; @@ -62,6 +64,7 @@ public class TorPluginFactory implements DuplexPluginFactory { this.eventBus = eventBus; this.torSocketFactory = torSocketFactory; this.backoffFactory = backoffFactory; + this.resourceProvider = resourceProvider; this.circumventionProvider = circumventionProvider; this.clock = clock; } @@ -99,10 +102,10 @@ public class TorPluginFactory implements DuplexPluginFactory { Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, MAX_POLLING_INTERVAL, BACKOFF_BASE); - TorPlugin plugin = new TorPlugin(ioExecutor, scheduler, appContext, - networkManager, locationUtils, torSocketFactory, clock, - circumventionProvider, backoff, callback, architecture, - MAX_LATENCY, MAX_IDLE_TIME); + AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler, + appContext, networkManager, locationUtils, torSocketFactory, + clock, resourceProvider, circumventionProvider, backoff, + callback, architecture, MAX_LATENCY, MAX_IDLE_TIME); eventBus.addListener(plugin); return plugin; } diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidResourceProvider.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidResourceProvider.java new file mode 100644 index 000000000..6d391e5ec --- /dev/null +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidResourceProvider.java @@ -0,0 +1,30 @@ +package org.briarproject.bramble.system; + +import android.app.Application; +import android.content.Context; +import android.content.res.Resources; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.system.ResourceProvider; + +import java.io.InputStream; + +import javax.inject.Inject; + +@NotNullByDefault +class AndroidResourceProvider implements ResourceProvider { + + private final Context appContext; + + @Inject + AndroidResourceProvider(Application app) { + this.appContext = app.getApplicationContext(); + } + + @Override + public InputStream getResourceInputStream(String name) { + Resources res = appContext.getResources(); + int resId = res.getIdentifier(name, "raw", appContext.getPackageName()); + return res.openRawResource(resId); + } +} diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java index 79fbf44b5..2f7ea5543 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java @@ -1,9 +1,8 @@ package org.briarproject.bramble.system; -import android.app.Application; - import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.bramble.api.system.LocationUtils; +import org.briarproject.bramble.api.system.ResourceProvider; import org.briarproject.bramble.api.system.SecureRandomProvider; import javax.inject.Singleton; @@ -16,18 +15,26 @@ public class AndroidSystemModule { @Provides @Singleton - SecureRandomProvider provideSecureRandomProvider(Application app) { - return new AndroidSecureRandomProvider(app); + SecureRandomProvider provideSecureRandomProvider( + AndroidSecureRandomProvider provider) { + return provider; } @Provides - LocationUtils provideLocationUtils(Application app) { - return new AndroidLocationUtils(app); + LocationUtils provideLocationUtils(AndroidLocationUtils locationUtils) { + return locationUtils; } @Provides @Singleton - AndroidExecutor provideAndroidExecutor(Application app) { - return new AndroidExecutorImpl(app); + AndroidExecutor provideAndroidExecutor( + AndroidExecutorImpl androidExecutor) { + return androidExecutor; + } + + @Provides + @Singleton + ResourceProvider provideResourceProvider(AndroidResourceProvider provider) { + return provider; } } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/system/ResourceProvider.java b/bramble-api/src/main/java/org/briarproject/bramble/api/system/ResourceProvider.java new file mode 100644 index 000000000..e0bbc63d4 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/system/ResourceProvider.java @@ -0,0 +1,11 @@ +package org.briarproject.bramble.api.system; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import java.io.InputStream; + +@NotNullByDefault +public interface ResourceProvider { + + InputStream getResourceInputStream(String name); +} diff --git a/bramble-core/build.gradle b/bramble-core/build.gradle index ea5b426d3..abc85106e 100644 --- a/bramble-core/build.gradle +++ b/bramble-core/build.gradle @@ -14,6 +14,7 @@ dependencies { implementation 'org.bitlet:weupnp:0.1.4' implementation 'net.i2p.crypto:eddsa:0.2.0' implementation 'org.whispersystems:curve25519-java:0.4.1' + implementation 'org.briarproject:jtorctl:0.3' apt 'com.google.dagger:dagger-compiler:2.0.2' @@ -47,6 +48,7 @@ dependencyVerification { 'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8', 'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8', 'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb', + 'org.briarproject:jtorctl:0.3:jtorctl-0.3.jar:f2939238a097898998432effe93b0334d97a787972ab3a91a8973a1d309fc864', 'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619', 'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90', 'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52', diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionModule.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionModule.java new file mode 100644 index 000000000..9ad744861 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionModule.java @@ -0,0 +1,17 @@ +package org.briarproject.bramble.plugin.tor; + +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +@Module +public class CircumventionModule { + + @Provides + @Singleton + CircumventionProvider provideCircumventionProvider( + CircumventionProviderImpl provider) { + return provider; + } +} diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProvider.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProvider.java similarity index 100% rename from bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProvider.java rename to bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProvider.java diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProviderImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProviderImpl.java similarity index 61% rename from bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProviderImpl.java rename to bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProviderImpl.java index bf194fa4e..8396dd774 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProviderImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProviderImpl.java @@ -1,13 +1,10 @@ package org.briarproject.bramble.plugin.tor; -import android.content.Context; -import android.content.res.Resources; - import org.briarproject.bramble.api.lifecycle.IoExecutor; +import org.briarproject.bramble.api.system.ResourceProvider; import java.io.InputStream; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Scanner; @@ -16,26 +13,27 @@ import java.util.Set; import javax.annotation.Nullable; import javax.inject.Inject; -// TODO: Create a module for this so it doesn't need to be public +import static java.util.Arrays.asList; -public class CircumventionProviderImpl implements CircumventionProvider { +class CircumventionProviderImpl implements CircumventionProvider { private final static String BRIDGE_FILE_NAME = "bridges"; - private final Context ctx; + private static final Set BLOCKED_IN_COUNTRIES = + new HashSet<>(asList(BLOCKED)); + private static final Set BRIDGES_WORK_IN_COUNTRIES = + new HashSet<>(asList(BRIDGES)); + + private final ResourceProvider resourceProvider; + @Nullable private volatile List bridges = null; @Inject - public CircumventionProviderImpl(Context ctx) { - this.ctx = ctx; + CircumventionProviderImpl(ResourceProvider resourceProvider) { + this.resourceProvider = resourceProvider; } - private static final Set BLOCKED_IN_COUNTRIES = - new HashSet<>(Arrays.asList(BLOCKED)); - private static final Set BRIDGES_WORK_IN_COUNTRIES = - new HashSet<>(Arrays.asList(BRIDGES)); - @Override public boolean isTorProbablyBlocked(String countryCode) { return BLOCKED_IN_COUNTRIES.contains(countryCode); @@ -49,15 +47,14 @@ public class CircumventionProviderImpl implements CircumventionProvider { @Override @IoExecutor public List getBridges() { - if (this.bridges != null) return this.bridges; + List bridges = this.bridges; + if (bridges != null) return new ArrayList<>(bridges); - Resources res = ctx.getResources(); - int resId = res.getIdentifier(BRIDGE_FILE_NAME, "raw", - ctx.getPackageName()); - InputStream is = ctx.getResources().openRawResource(resId); + InputStream is = + resourceProvider.getResourceInputStream(BRIDGE_FILE_NAME); Scanner scanner = new Scanner(is); - List bridges = new ArrayList<>(); + bridges = new ArrayList<>(); while (scanner.hasNextLine()) { String line = scanner.nextLine(); if (!line.startsWith("#")) bridges.add(line); diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java similarity index 89% rename from bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java rename to bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index fa7d2fac2..3c6f4cb04 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -1,12 +1,5 @@ package org.briarproject.bramble.plugin.tor; -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Resources; -import android.os.PowerManager; - import net.freehaven.tor.control.EventHandler; import net.freehaven.tor.control.TorControlConnection; @@ -33,8 +26,8 @@ import org.briarproject.bramble.api.settings.Settings; import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.LocationUtils; +import org.briarproject.bramble.api.system.ResourceProvider; import org.briarproject.bramble.util.IoUtils; -import org.briarproject.bramble.util.RenewableWakeLock; import org.briarproject.bramble.util.StringUtils; import java.io.Closeable; @@ -57,7 +50,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Scanner; import java.util.concurrent.Executor; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Logger; import java.util.regex.Pattern; @@ -66,10 +58,6 @@ import java.util.zip.ZipInputStream; import javax.annotation.Nullable; import javax.net.SocketFactory; -import static android.content.Context.MODE_PRIVATE; -import static android.content.Context.POWER_SERVICE; -import static android.os.PowerManager.PARTIAL_WAKE_LOCK; -import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS; @@ -88,7 +76,10 @@ import static org.briarproject.bramble.util.PrivacyUtils.scrubOnion; @MethodsNotNullByDefault @ParametersNotNullByDefault -class TorPlugin implements DuplexPlugin, EventHandler, EventListener { +abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { + + private static final Logger LOG = + Logger.getLogger(TorPlugin.class.getName()); private static final String[] EVENTS = { "CIRC", "ORCONN", "HS_DESC", "NOTICE", "WARN", "ERR" @@ -97,13 +88,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { private static final int COOKIE_TIMEOUT_MS = 3000; private static final int COOKIE_POLLING_INTERVAL_MS = 200; private static final Pattern ONION = Pattern.compile("[a-z2-7]{16}"); - // 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()); private final Executor ioExecutor, connectionStatusExecutor; - private final Context appContext; private final NetworkManager networkManager; private final LocationUtils locationUtils; private final SocketFactory torSocketFactory; @@ -112,53 +98,54 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { private final DuplexPluginCallback callback; private final String architecture; private final CircumventionProvider circumventionProvider; + private final ResourceProvider resourceProvider; private final int maxLatency, maxIdleTime, socketTimeout; - private final ConnectionStatus connectionStatus; private final File torDirectory, torFile, geoIpFile, configFile; private final File doneFile, cookieFile; - private final RenewableWakeLock wakeLock; + private final ConnectionStatus connectionStatus; private final AtomicBoolean used = new AtomicBoolean(false); - private volatile boolean running = false; private volatile ServerSocket socket = null; private volatile Socket controlSocket = null; private volatile TorControlConnection controlConnection = null; - TorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler, - Context appContext, NetworkManager networkManager, + protected volatile boolean running = false; + + protected abstract int getProcessId(); + + protected abstract long getLastUpdateTime(); + + TorPlugin(Executor ioExecutor, NetworkManager networkManager, LocationUtils locationUtils, SocketFactory torSocketFactory, - Clock clock, CircumventionProvider circumventionProvider, - Backoff backoff, DuplexPluginCallback callback, - String architecture, int maxLatency, int maxIdleTime) { + Clock clock, ResourceProvider resourceProvider, + CircumventionProvider circumventionProvider, Backoff backoff, + DuplexPluginCallback callback, String architecture, int maxLatency, + int maxIdleTime, File torDirectory) { this.ioExecutor = ioExecutor; - this.appContext = appContext; this.networkManager = networkManager; this.locationUtils = locationUtils; this.torSocketFactory = torSocketFactory; this.clock = clock; + this.resourceProvider = resourceProvider; + this.circumventionProvider = circumventionProvider; this.backoff = backoff; this.callback = callback; this.architecture = architecture; - this.circumventionProvider = circumventionProvider; this.maxLatency = maxLatency; this.maxIdleTime = maxIdleTime; if (maxIdleTime > Integer.MAX_VALUE / 2) socketTimeout = Integer.MAX_VALUE; else socketTimeout = maxIdleTime * 2; - connectionStatus = new ConnectionStatus(); - torDirectory = appContext.getDir("tor", MODE_PRIVATE); + this.torDirectory = torDirectory; torFile = new File(torDirectory, "tor"); geoIpFile = new File(torDirectory, "geoip"); configFile = new File(torDirectory, "torrc"); doneFile = new File(torDirectory, "done"); cookieFile = new File(torDirectory, ".tor/control_auth_cookie"); + connectionStatus = new ConnectionStatus(); // Don't execute more than one connection status check at a time connectionStatusExecutor = new PoliteExecutor("TorPlugin", ioExecutor, 1); - PowerManager pm = (PowerManager) - appContext.getSystemService(POWER_SERVICE); - wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK, - WAKE_LOCK_TAG, 1, MINUTES); } @Override @@ -187,7 +174,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { LOG.info("Starting Tor"); String torPath = torFile.getAbsolutePath(); String configPath = configFile.getAbsolutePath(); - String pid = String.valueOf(android.os.Process.myPid()); + String pid = String.valueOf(getProcessId()); Process torProcess; ProcessBuilder pb = new ProcessBuilder(torPath, "-f", configPath, OWNER, pid); @@ -266,13 +253,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } private boolean assetsAreUpToDate() { - try { - PackageManager pm = appContext.getPackageManager(); - PackageInfo pi = pm.getPackageInfo(appContext.getPackageName(), 0); - return doneFile.lastModified() > pi.lastUpdateTime; - } catch (NameNotFoundException e) { - throw new RuntimeException(e); - } + return doneFile.lastModified() > getLastUpdateTime(); } private void installAssets() throws PluginException { @@ -305,29 +286,22 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { private InputStream getTorInputStream() throws IOException { if (LOG.isLoggable(INFO)) LOG.info("Installing Tor binary for " + architecture); - int resId = getResourceId("tor_" + architecture); - InputStream in = appContext.getResources().openRawResource(resId); + InputStream in = + resourceProvider.getResourceInputStream("tor_" + architecture); ZipInputStream zin = new ZipInputStream(in); if (zin.getNextEntry() == null) throw new IOException(); return zin; } private InputStream getGeoIpInputStream() throws IOException { - int resId = getResourceId("geoip"); - InputStream in = appContext.getResources().openRawResource(resId); + InputStream in = resourceProvider.getResourceInputStream("geoip"); ZipInputStream zin = new ZipInputStream(in); if (zin.getNextEntry() == null) throw new IOException(); return zin; } private InputStream getConfigInputStream() { - int resId = getResourceId("torrc"); - return appContext.getResources().openRawResource(resId); - } - - private int getResourceId(String filename) { - Resources res = appContext.getResources(); - return res.getIdentifier(filename, "raw", appContext.getPackageName()); + return resourceProvider.getResourceInputStream("torrc"); } private void tryToClose(@Nullable Closeable c) { @@ -473,15 +447,11 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } } - private void enableNetwork(boolean enable) throws IOException { + protected void enableNetwork(boolean enable) throws IOException { if (!running) return; - if (enable) wakeLock.acquire(); connectionStatus.enableNetwork(enable); controlConnection.setConf("DisableNetwork", enable ? "0" : "1"); - if (!enable) { - callback.transportDisabled(); - wakeLock.release(); - } + if (!enable) callback.transportDisabled(); } private void enableBridges(boolean enable) throws IOException { @@ -509,7 +479,6 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { logException(LOG, WARNING, e); } } - wakeLock.release(); } @Override diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorTransportConnection.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorTransportConnection.java similarity index 100% rename from bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/TorTransportConnection.java rename to bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorTransportConnection.java diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java b/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java index 06d275767..9f4ba2d14 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java @@ -21,11 +21,12 @@ import org.briarproject.bramble.api.reporting.DevConfig; import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.LocationUtils; +import org.briarproject.bramble.api.system.ResourceProvider; import org.briarproject.bramble.api.system.Scheduler; import org.briarproject.bramble.plugin.bluetooth.AndroidBluetoothPluginFactory; import org.briarproject.bramble.plugin.tcp.AndroidLanTcpPluginFactory; +import org.briarproject.bramble.plugin.tor.AndroidTorPluginFactory; import org.briarproject.bramble.plugin.tor.CircumventionProvider; -import org.briarproject.bramble.plugin.tor.TorPluginFactory; import org.briarproject.bramble.util.AndroidUtils; import org.briarproject.bramble.util.StringUtils; import org.briarproject.briar.api.android.AndroidNotificationManager; @@ -95,14 +96,16 @@ public class AppModule { SocketFactory torSocketFactory, BackoffFactory backoffFactory, Application app, NetworkManager networkManager, LocationUtils locationUtils, EventBus eventBus, + ResourceProvider resourceProvider, CircumventionProvider circumventionProvider, Clock clock) { Context appContext = app.getApplicationContext(); DuplexPluginFactory bluetooth = new AndroidBluetoothPluginFactory(ioExecutor, androidExecutor, appContext, random, eventBus, backoffFactory); - DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, scheduler, - appContext, networkManager, locationUtils, eventBus, - torSocketFactory, backoffFactory, circumventionProvider, clock); + DuplexPluginFactory tor = new AndroidTorPluginFactory(ioExecutor, + scheduler, appContext, networkManager, locationUtils, eventBus, + torSocketFactory, backoffFactory, resourceProvider, + circumventionProvider, clock); DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor, eventBus, backoffFactory, appContext); Collection duplex = asList(bluetooth, tor, lan);