Compare commits

..

20 Commits

Author SHA1 Message Date
akwizgran
fb7d4076ab Use magic wake lock tag for Huawei devices. 2018-09-07 13:32:22 +01:00
akwizgran
a3083a6e73 Use a constant to enable the control condition. 2018-08-30 18:10:18 +01:00
akwizgran
c1fcae7de3 Add more logging for sleep and alarms. 2018-08-30 17:43:22 +01:00
Shannon Stork
35c1f50650 Added sleep and power status logging 2018-08-08 21:27:50 -04:00
Shannon Stork
f2c50b500e Acquire wakelock when alarm goes off 2018-08-07 10:38:57 -04:00
akwizgran
0776ab85b6 Use elapsed real time, postDelayed() instead of sleep(). 2018-07-26 10:51:00 +01:00
Shannon Stork
f77bde4edf Attempt to acquire wakelock when alarm goes off (DOES NOT WORK) 2018-07-25 19:20:54 -04:00
Torsten Grote
afa9b6193a Merge branch 'remove-reference-manager' into 'master'
Removed unused ReferenceManager

See merge request briar/briar!856
2018-07-16 15:44:29 +00:00
akwizgran
1bcedea34a Removed unused ReferenceManager. 2018-07-16 16:21:25 +01:00
akwizgran
0f16ac57f3 Merge branch '1267-tor-bridges' into 'master'
Tor Bridge Support

See merge request briar/briar!847
2018-07-05 14:22:39 +00:00
Torsten Grote
7ecac1867e Address review comments for Tor bridge support 2018-07-05 11:14:11 -03:00
Torsten Grote
331c09a02a Load bridges from file res/raw/bridges 2018-07-04 16:21:49 -03:00
Torsten Grote
7e05a49bda Add Android integration tests that checks if included bridges work
This also changes the way bridges are used.
Instead of using the torrc config file,
bridges are now activated via Tor's control port.
2018-07-04 15:17:28 -03:00
Torsten Grote
eac1f9ed74 MVP for bridge support 2018-07-04 15:17:28 -03:00
Torsten Grote
d16aa9e2a4 Merge branch '1334-disable-resource-shrinking' into 'master'
Disable resource shrinking for release builds

Closes #1334

See merge request briar/briar!854
2018-07-04 17:20:40 +00:00
akwizgran
cc72d146a0 Disable resource shrinking for release builds. 2018-07-04 17:02:39 +01:00
Torsten Grote
bff23480d7 Trigger external pipeline to check release builds 2018-07-04 12:47:22 -03:00
akwizgran
e435578f3b Merge branch 'gui-minor-padding-corrections' into 'master'
Fixed padding in rss_feed_import, list_item_crash, power_view

See merge request briar/briar!831
2018-07-04 13:21:18 +00:00
jRustig
33b9539a72 correction of crash report alignment 2018-07-04 14:59:34 +02:00
jRustig
8c64734ff1 Fixed padding in rss_feed_import, list_item_crash, power_view 2018-06-13 10:34:10 +02:00
24 changed files with 628 additions and 155 deletions

View File

@@ -21,11 +21,7 @@ test:
test_reproducible:
image: briar/reproducer:latest
script:
- cd /opt/briar-reproducer
- ./reproduce.py ${CI_COMMIT_REF_NAME}
- "curl -X POST -F token=${RELEASE_CHECK_TOKEN} -F ref=master -F variables[RELEASE_TAG]=${CI_COMMIT_REF_NAME} https://code.briarproject.org/api/v4/projects/61/trigger/pipeline"
only:
- tags

View File

@@ -11,6 +11,8 @@ android {
versionCode 10011
versionName "1.0.11"
consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
compileOptions {
@@ -31,6 +33,12 @@ dependencies {
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
compileOnly 'javax.annotation:jsr250-api:1.0'
androidTestImplementation project(path: ':bramble-api', configuration: 'testOutput')
androidTestImplementation project(path: ':bramble-core', configuration: 'testOutput')
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestAnnotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
androidTestCompileOnly 'javax.annotation:jsr250-api:1.0'
}
dependencyVerification {

View File

@@ -0,0 +1,23 @@
package org.briarproject.bramble;
import org.briarproject.bramble.event.EventModule;
import org.briarproject.bramble.plugin.PluginModule;
import org.briarproject.bramble.plugin.tor.BridgeTest;
import org.briarproject.bramble.system.SystemModule;
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(modules = {
BrambleAndroidModule.class,
PluginModule.class, // needed for BackoffFactory
EventModule.class,
SystemModule.class,
})
public interface IntegrationTestComponent {
void inject(BridgeTest init);
}

View File

@@ -0,0 +1,126 @@
package org.briarproject.bramble.plugin.tor;
import android.content.Context;
import android.support.test.runner.AndroidJUnit4;
import org.briarproject.bramble.DaggerIntegrationTestComponent;
import org.briarproject.bramble.IntegrationTestComponent;
import org.briarproject.bramble.api.event.EventBus;
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.test.BrambleTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.net.SocketFactory;
import static android.support.test.InstrumentationRegistry.getTargetContext;
import static java.util.Collections.singletonList;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@RunWith(AndroidJUnit4.class)
public class BridgeTest extends BrambleTestCase {
private final static long TIMEOUT = SECONDS.toMillis(23);
private final static Logger LOG =
Logger.getLogger(BridgeTest.class.getSimpleName());
@Inject
EventBus eventBus;
@Inject
BackoffFactory backoffFactory;
@Inject
Clock clock;
private final Context appContext = getTargetContext();
private final CircumventionProvider circumventionProvider;
private final List<String> bridges;
private TorPluginFactory factory;
private volatile int currentBridge = 0;
public BridgeTest() {
super();
circumventionProvider = new CircumventionProvider() {
@Override
public boolean isTorProbablyBlocked(String countryCode) {
return true;
}
@Override
public boolean doBridgesWork(String countryCode) {
return true;
}
@Override
public List<String> getBridges() {
return singletonList(bridges.get(currentBridge));
}
};
bridges = new CircumventionProviderImpl(appContext).getBridges();
}
@Before
public void setUp() {
IntegrationTestComponent component =
DaggerIntegrationTestComponent.builder().build();
component.inject(this);
Executor ioExecutor = Executors.newCachedThreadPool();
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
LocationUtils locationUtils = () -> "US";
SocketFactory torSocketFactory = SocketFactory.getDefault();
factory = new TorPluginFactory(ioExecutor, scheduler, appContext,
locationUtils, eventBus, torSocketFactory,
backoffFactory, circumventionProvider, clock);
}
@Test
public void testBridges() throws Exception {
assertTrue(bridges.size() > 0);
for (int i = 0; i < bridges.size(); i++) {
testBridge(i);
}
}
private void testBridge(int bridge) throws Exception {
DuplexPlugin duplexPlugin =
factory.createPlugin(new TorPluginCallBack());
assertNotNull(duplexPlugin);
TorPlugin plugin = (TorPlugin) duplexPlugin;
currentBridge = bridge;
LOG.warning("Testing " + bridges.get(currentBridge));
try {
plugin.start();
long start = clock.currentTimeMillis();
while (clock.currentTimeMillis() - start < TIMEOUT) {
if (plugin.isRunning()) return;
clock.sleep(500);
}
if (!plugin.isRunning()) {
fail("Could not connect to Tor within timeout.");
}
} finally {
plugin.stop();
}
}
}

View File

@@ -0,0 +1,54 @@
package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.settings.Settings;
@NotNullByDefault
public class TorPluginCallBack implements DuplexPluginCallback {
@Override
public void incomingConnectionCreated(DuplexTransportConnection d) {
}
@Override
public void outgoingConnectionCreated(ContactId c,
DuplexTransportConnection d) {
}
@Override
public Settings getSettings() {
return new Settings();
}
@Override
public TransportProperties getLocalProperties() {
return new TransportProperties();
}
@Override
public void mergeSettings(Settings s) {
}
@Override
public void mergeLocalProperties(TransportProperties p) {
}
@Override
public void transportEnabled() {
}
@Override
public void transportDisabled() {
}
}

View File

@@ -1,11 +1,25 @@
package org.briarproject.bramble;
import android.app.Application;
import org.briarproject.bramble.plugin.tor.CircumventionProvider;
import org.briarproject.bramble.plugin.tor.CircumventionProviderImpl;
import org.briarproject.bramble.system.AndroidSystemModule;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module(includes = {
AndroidSystemModule.class
})
public class BrambleAndroidModule {
@Provides
@Singleton
CircumventionProvider provideCircumventionProvider(Application app) {
return new CircumventionProviderImpl(app.getApplicationContext());
}
}

View File

@@ -0,0 +1,8 @@
package org.briarproject.bramble;
public interface PowerTestingConstants {
int WAKE_LOCK_DURATION = 5000;
int ALARM_DELAY = 5000;
boolean USE_TOR_WAKE_LOCK = true;
}

View File

@@ -0,0 +1,30 @@
package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import java.util.List;
public interface CircumventionProvider {
/**
* Countries where Tor is blocked, i.e. vanilla Tor connection won't work.
*
* See https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
* and https://trac.torproject.org/projects/tor/wiki/doc/OONI/censorshipwiki
*/
String[] BLOCKED = {"CN", "IR", "EG", "BY", "TR", "SY", "VE"};
/**
* Countries where vanilla bridge connection are likely to work.
* Should be a subset of {@link #BLOCKED}.
*/
String[] BRIDGES = { "EG", "BY", "TR", "SY", "VE" };
boolean isTorProbablyBlocked(String countryCode);
boolean doBridgesWork(String countryCode);
@IoExecutor
List<String> getBridges();
}

View File

@@ -0,0 +1,68 @@
package org.briarproject.bramble.plugin.tor;
import android.content.Context;
import android.content.res.Resources;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import javax.annotation.Nullable;
import javax.inject.Inject;
public class CircumventionProviderImpl implements CircumventionProvider {
private final static String BRIDGE_FILE_NAME = "bridges";
private final Context ctx;
@Nullable
private volatile List<String> bridges = null;
@Inject
public CircumventionProviderImpl(Context ctx) {
this.ctx = ctx;
}
private static final Set<String> BLOCKED_IN_COUNTRIES =
new HashSet<>(Arrays.asList(BLOCKED));
private static final Set<String> BRIDGES_WORK_IN_COUNTRIES =
new HashSet<>(Arrays.asList(BRIDGES));
@Override
public boolean isTorProbablyBlocked(String countryCode) {
return BLOCKED_IN_COUNTRIES.contains(countryCode);
}
@Override
public boolean doBridgesWork(String countryCode) {
return BRIDGES_WORK_IN_COUNTRIES.contains(countryCode);
}
@Override
@IoExecutor
public List<String> getBridges() {
if (this.bridges != null) return this.bridges;
Resources res = ctx.getResources();
int resId = res.getIdentifier(BRIDGE_FILE_NAME, "raw",
ctx.getPackageName());
InputStream is = ctx.getResources().openRawResource(resId);
Scanner scanner = new Scanner(is);
List<String> bridges = new ArrayList<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if (!line.startsWith("#")) bridges.add(line);
}
scanner.close();
this.bridges = bridges;
return bridges;
}
}

View File

@@ -1,18 +0,0 @@
package org.briarproject.bramble.plugin.tor;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
class TorNetworkMetadata {
// See https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
// and https://trac.torproject.org/projects/tor/wiki/doc/OONI/censorshipwiki
// TODO: get a more complete list
private static final Set<String> BLOCKED_IN_COUNTRIES =
new HashSet<>(Arrays.asList("CN", "IR", "SY", "ZZ"));
static boolean isTorProbablyBlocked(String countryCode) {
return BLOCKED_IN_COUNTRIES.contains(countryCode);
}
}

View File

@@ -50,7 +50,9 @@ import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -83,6 +85,7 @@ import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS;
import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY;
import static org.briarproject.bramble.PowerTestingConstants.USE_TOR_WAKE_LOCK;
import static org.briarproject.bramble.api.plugin.TorConstants.CONTROL_PORT;
import static org.briarproject.bramble.api.plugin.TorConstants.ID;
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK;
@@ -119,6 +122,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private final Backoff backoff;
private final DuplexPluginCallback callback;
private final String architecture;
private final CircumventionProvider circumventionProvider;
private final int maxLatency, maxIdleTime, socketTimeout;
private final ConnectionStatus connectionStatus;
private final File torDirectory, torFile, geoIpFile, configFile;
@@ -138,7 +142,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
Context appContext, LocationUtils locationUtils,
SocketFactory torSocketFactory, Clock clock, Backoff backoff,
DuplexPluginCallback callback, String architecture,
int maxLatency, int maxIdleTime) {
CircumventionProvider circumventionProvider, int maxLatency, int maxIdleTime) {
this.ioExecutor = ioExecutor;
this.scheduler = scheduler;
this.appContext = appContext;
@@ -148,6 +152,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
this.backoff = backoff;
this.callback = callback;
this.architecture = architecture;
this.circumventionProvider = circumventionProvider;
this.maxLatency = maxLatency;
this.maxIdleTime = maxIdleTime;
if (maxIdleTime > Integer.MAX_VALUE / 2)
@@ -489,12 +494,23 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private void enableNetwork(boolean enable) throws IOException {
if (!running) return;
if (enable) wakeLock.acquire();
if (enable && USE_TOR_WAKE_LOCK) wakeLock.acquire();
connectionStatus.enableNetwork(enable);
controlConnection.setConf("DisableNetwork", enable ? "0" : "1");
if (!enable) {
callback.transportDisabled();
wakeLock.release();
if (USE_TOR_WAKE_LOCK) wakeLock.release();
}
}
private void enableBridges(boolean enable) throws IOException {
if (enable) {
Collection<String> conf = new ArrayList<>();
conf.add("UseBridges 1");
conf.addAll(circumventionProvider.getBridges());
controlConnection.setConf(conf);
} else {
controlConnection.setConf("UseBridges", "0");
}
}
@@ -514,7 +530,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
logException(LOG, WARNING, e);
}
}
wakeLock.release();
if (USE_TOR_WAKE_LOCK) wakeLock.release();
}
@Override
@@ -662,8 +678,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
boolean online = net != null && net.isConnected();
boolean wifi = online && net.getType() == TYPE_WIFI;
String country = locationUtils.getCurrentCountry();
boolean blocked = TorNetworkMetadata.isTorProbablyBlocked(
country);
boolean blocked =
circumventionProvider.isTorProbablyBlocked(country);
Settings s = callback.getSettings();
int network = s.getInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_ALWAYS);
@@ -677,15 +693,22 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
if (!online) {
LOG.info("Disabling network, device is offline");
enableNetwork(false);
} else if (blocked) {
LOG.info("Disabling network, country is blocked");
enableNetwork(false);
} else if (network == PREF_TOR_NETWORK_NEVER
|| (network == PREF_TOR_NETWORK_WIFI && !wifi)) {
LOG.info("Disabling network due to data setting");
enableNetwork(false);
} else if (blocked) {
if (circumventionProvider.doBridgesWork(country)) {
LOG.info("Enabling network, using bridges");
enableBridges(true);
enableNetwork(true);
} else {
LOG.info("Disabling network, country is blocked");
enableNetwork(false);
}
} else {
LOG.info("Enabling network");
enableBridges(false);
enableNetwork(true);
}
} catch (IOException e) {

View File

@@ -43,12 +43,14 @@ public class TorPluginFactory implements DuplexPluginFactory {
private final EventBus eventBus;
private final SocketFactory torSocketFactory;
private final BackoffFactory backoffFactory;
private final CircumventionProvider circumventionProvider;
private final Clock clock;
public TorPluginFactory(Executor ioExecutor,
ScheduledExecutorService scheduler, Context appContext,
LocationUtils locationUtils, EventBus eventBus,
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
CircumventionProvider circumventionProvider,
Clock clock) {
this.ioExecutor = ioExecutor;
this.scheduler = scheduler;
@@ -57,6 +59,7 @@ public class TorPluginFactory implements DuplexPluginFactory {
this.eventBus = eventBus;
this.torSocketFactory = torSocketFactory;
this.backoffFactory = backoffFactory;
this.circumventionProvider = circumventionProvider;
this.clock = clock;
}
@@ -95,7 +98,7 @@ public class TorPluginFactory implements DuplexPluginFactory {
MAX_POLLING_INTERVAL, BACKOFF_BASE);
TorPlugin plugin = new TorPlugin(ioExecutor, scheduler, appContext,
locationUtils, torSocketFactory, clock, backoff, callback,
architecture, MAX_LATENCY, MAX_IDLE_TIME);
architecture, circumventionProvider, MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -0,0 +1,5 @@
Bridge 131.252.210.150:8081 0E858AC201BF0F3FA3C462F64844CBFFC7297A42
Bridge 67.205.189.122:8443 12D64D5D44E20169585E7378580C0D33A872AD98
Bridge 45.32.148.146:8443 0CE016FB2462D8BF179AE71F7D702D09DEAC3F1D
Bridge 148.251.90.59:7510 019F727CA6DCA6CA5C90B55E477B7D87981E75BC
#Bridge 128.105.214.161:8081 1E326AAFB3FCB515015250D8FCCC8E37F91A153B

View File

@@ -12,7 +12,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotation for injecting the executor for long-running IO tasks. Also used
* for annotating methods that should run on the UI executor.
* for annotating methods that should run on the IO executor.
* <p>
* The contract of this executor is that tasks may be run concurrently, and
* submitting a task will never block. Tasks may run indefinitely. Tasks

View File

@@ -261,7 +261,7 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
release {
shrinkResources true
shrinkResources false
minifyEnabled true
crunchPngs false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'

View File

@@ -25,12 +25,12 @@ import org.briarproject.bramble.api.system.LocationUtils;
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.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;
import org.briarproject.briar.api.android.DozeWatchdog;
import org.briarproject.briar.api.android.ReferenceManager;
import org.briarproject.briar.api.android.ScreenFilterMonitor;
import java.io.File;
@@ -99,14 +99,14 @@ public class AppModule {
AndroidExecutor androidExecutor, SecureRandom random,
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
Application app, LocationUtils locationUtils, EventBus eventBus,
Clock clock) {
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, locationUtils, eventBus, torSocketFactory,
backoffFactory, clock);
backoffFactory, circumventionProvider, clock);
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
scheduler, backoffFactory, appContext);
Collection<DuplexPluginFactory> duplex = asList(bluetooth, tor, lan);
@@ -165,12 +165,6 @@ public class AppModule {
return app.getSharedPreferences("db", MODE_PRIVATE);
}
@Provides
@Singleton
ReferenceManager provideReferenceManager() {
return new ReferenceManagerImpl();
}
@Provides
@Singleton
AndroidNotificationManager provideAndroidNotificationManager(

View File

@@ -117,6 +117,7 @@ public class BriarApplicationImpl extends Application
BrambleCoreModule.initEagerSingletons(applicationComponent);
BriarCoreModule.initEagerSingletons(applicationComponent);
AndroidEagerSingletons.initEagerSingletons(applicationComponent);
new SleepMonitor().start();
}
@Override

View File

@@ -0,0 +1,84 @@
package org.briarproject.briar.android;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.PowerManager;
import android.support.v4.content.WakefulBroadcastReceiver;
import android.util.Log;
import static android.content.Context.CONNECTIVITY_SERVICE;
import static android.content.Context.POWER_SERVICE;
import static android.content.Intent.ACTION_AIRPLANE_MODE_CHANGED;
import static android.content.Intent.ACTION_BATTERY_CHANGED;
import static android.content.Intent.ACTION_POWER_CONNECTED;
import static android.content.Intent.ACTION_POWER_DISCONNECTED;
import static android.content.Intent.ACTION_SCREEN_OFF;
import static android.content.Intent.ACTION_SCREEN_ON;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.os.BatteryManager.EXTRA_LEVEL;
import static android.os.BatteryManager.EXTRA_PLUGGED;
import static android.os.BatteryManager.EXTRA_SCALE;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
import static android.os.PowerManager.ACTION_POWER_SAVE_MODE_CHANGED;
public class BriarBroadcastReceiver extends WakefulBroadcastReceiver {
IntentFilter getIntentFilter() {
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_SCREEN_ON);
filter.addAction(ACTION_SCREEN_OFF);
filter.addAction(ACTION_BATTERY_CHANGED);
filter.addAction(ACTION_POWER_CONNECTED);
filter.addAction(ACTION_POWER_DISCONNECTED);
if (SDK_INT >= 21) filter.addAction(ACTION_POWER_SAVE_MODE_CHANGED);
if (SDK_INT >= 23) filter.addAction(ACTION_DEVICE_IDLE_MODE_CHANGED);
filter.addAction(ACTION_AIRPLANE_MODE_CHANGED);
filter.addAction(CONNECTIVITY_ACTION);
return filter;
}
@Override
public void onReceive(Context ctx, Intent i) {
String action = i.getAction();
if (ACTION_SCREEN_ON.equals(action)) {
Log.i("DEVICE_STATUS", "Screen on");
} else if (ACTION_SCREEN_OFF.equals(action)) {
Log.i("DEVICE_STATUS", "Screen off");
} else if (ACTION_BATTERY_CHANGED.equals(action)) {
int level = i.getIntExtra(EXTRA_LEVEL, -1);
int scale = i.getIntExtra(EXTRA_SCALE, -1);
int plugged = i.getIntExtra(EXTRA_PLUGGED, -1);
Log.i("DEVICE_STATUS", "Battery level: " + (level / (float) scale)
+ ", plugged: " + (plugged != 0));
} else if (ACTION_POWER_CONNECTED.equals(action)) {
Log.i("DEVICE_STATUS", "Power connected");
} else if (ACTION_POWER_DISCONNECTED.equals(action)) {
Log.i("DEVICE_STATUS", "Power disconnected");
} else if (SDK_INT >= 21
&& ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
PowerManager pm = (PowerManager)
ctx.getSystemService(POWER_SERVICE);
Log.i("DEVICE_STATUS", "Power save mode: " + pm.isPowerSaveMode());
} else if (SDK_INT >= 23
&& ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
PowerManager pm = (PowerManager)
ctx.getSystemService(POWER_SERVICE);
Log.i("DEVICE_STATUS", " Idle mode: " + pm.isDeviceIdleMode());
} else if (ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
Log.i("DEVICE_STATUS",
"Airplane mode: " + i.getBooleanExtra("state", false));
} else if (CONNECTIVITY_ACTION.equals(action)) {
ConnectivityManager cm = (ConnectivityManager)
ctx.getSystemService(CONNECTIVITY_SERVICE);
NetworkInfo net = cm.getActiveNetworkInfo();
boolean online = net != null && net.isConnected();
boolean wifi = net != null && net.getType() == TYPE_WIFI;
Log.i("DEVICE_STATUS", "Online: " + online + ", wifi: " + wifi);
}
}
}

View File

@@ -2,6 +2,7 @@ package org.briarproject.briar.android;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.AlarmManager;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -13,9 +14,14 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.SystemClock;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
@@ -33,8 +39,10 @@ import javax.annotation.Nullable;
import javax.inject.Inject;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static android.content.Intent.ACTION_SHUTDOWN;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
@@ -43,11 +51,15 @@ import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static android.support.v4.app.NotificationCompat.CATEGORY_SERVICE;
import static android.support.v4.app.NotificationCompat.PRIORITY_MIN;
import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.PowerTestingConstants.ALARM_DELAY;
import static org.briarproject.bramble.PowerTestingConstants.USE_TOR_WAKE_LOCK;
import static org.briarproject.bramble.PowerTestingConstants.WAKE_LOCK_DURATION;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
import static org.briarproject.briar.api.android.AndroidNotificationManager.FAILURE_CHANNEL_ID;
@@ -65,15 +77,27 @@ public class BriarService extends Service {
public static String EXTRA_STARTUP_FAILED =
"org.briarproject.briar.STARTUP_FAILED";
// This tag prevents the wake lock from being ignored on some Huawei devices
private static final String WAKE_LOCK_TAG = "LocationManagerService";
private static final String ACTION_ALARM =
"org.briarproject.briar.android.ACTION_ALARM";
private static final String EXTRA_DUE_MILLIS =
"org.briarproject.briar.android.DUE_MILLIS";
private static final Logger LOG =
Logger.getLogger(BriarService.class.getName());
private final AtomicBoolean created = new AtomicBoolean(false);
private final Binder binder = new BriarBinder();
private AlarmManager alarm;
@Nullable
private BroadcastReceiver receiver = null;
@Nullable
private BriarBroadcastReceiver testReceiver = null;
@Inject
protected DatabaseConfig databaseConfig;
// Fields that are accessed from background threads must be volatile
@@ -90,6 +114,11 @@ public class BriarService extends Service {
BriarApplication application = (BriarApplication) getApplication();
application.getApplicationComponent().inject(this);
alarm = (AlarmManager)
getApplicationContext().getSystemService(ALARM_SERVICE);
setAlarm();
LOG.info("Created");
if (created.getAndSet(true)) {
LOG.info("Already created");
@@ -168,6 +197,34 @@ public class BriarService extends Service {
filter.addAction("android.intent.action.QUICKBOOT_POWEROFF");
filter.addAction("com.htc.intent.action.QUICKBOOT_POWEROFF");
registerReceiver(receiver, filter);
testReceiver = new BriarBroadcastReceiver();
registerReceiver(testReceiver, testReceiver.getIntentFilter());
}
private void setAlarm() {
long dueMillis = SystemClock.elapsedRealtime() + ALARM_DELAY;
PendingIntent pi = getPendingIntent(dueMillis);
if (SDK_INT >= 23) {
alarm.setExactAndAllowWhileIdle(ELAPSED_REALTIME_WAKEUP,
dueMillis, pi);
} else if (SDK_INT >= 19) {
alarm.setExact(ELAPSED_REALTIME_WAKEUP, dueMillis, pi);
} else {
alarm.set(ELAPSED_REALTIME_WAKEUP, dueMillis, pi);
}
Log.i("ALARM_TEST", "Alarm set for " + ALARM_DELAY + " ms");
}
PendingIntent getPendingIntent(long dueMillis) {
return PendingIntent.getService(getApplicationContext(), 0,
getAlarmIntent(dueMillis), FLAG_CANCEL_CURRENT);
}
Intent getAlarmIntent(long dueMillis) {
Intent i = new Intent(getApplicationContext(), BriarService.class);
i.setAction(ACTION_ALARM);
i.putExtra(EXTRA_DUE_MILLIS, dueMillis);
return i;
}
@Override
@@ -204,6 +261,30 @@ public class BriarService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (ACTION_ALARM.equals(intent.getAction())) {
long dueMillis = intent.getLongExtra(EXTRA_DUE_MILLIS, 0);
long late = SystemClock.elapsedRealtime() - dueMillis;
Log.i("ALARM_TEST", "Alarm fired " + late + " ms late");
PowerManager powerManager = (PowerManager)
getApplicationContext().getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PARTIAL_WAKE_LOCK,
WAKE_LOCK_TAG);
if (!USE_TOR_WAKE_LOCK) {
//acquire wakelock
wakeLock.acquire();
Log.i("ALARM_TEST", "WakeLock acquired for "
+ WAKE_LOCK_DURATION + " ms");
}
new Handler().postDelayed(() -> {
//set alarm before releasing wake lock
setAlarm();
if (!USE_TOR_WAKE_LOCK) {
//release wakelock
Log.i("ALARM_TEST", "Releasing WakeLock");
wakeLock.release();
}
}, WAKE_LOCK_DURATION);
}
return START_NOT_STICKY; // Don't restart automatically if killed
}
@@ -218,10 +299,12 @@ public class BriarService extends Service {
LOG.info("Destroyed");
stopForeground(true);
if (receiver != null) unregisterReceiver(receiver);
if (testReceiver != null) unregisterReceiver(testReceiver);
// Stop the services in a background thread
new Thread(() -> {
if (started) lifecycleManager.stopServices();
}).start();
}
@Override

View File

@@ -1,83 +0,0 @@
package org.briarproject.briar.android;
import org.briarproject.briar.api.android.ReferenceManager;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Logger;
import static java.util.logging.Level.INFO;
class ReferenceManagerImpl implements ReferenceManager {
private static final Logger LOG =
Logger.getLogger(ReferenceManagerImpl.class.getName());
private final Lock lock = new ReentrantLock();
// The following are locking: lock
private final Map<Class<?>, Map<Long, Object>> outerMap = new HashMap<>();
private long nextHandle = 0;
@Override
public <T> T getReference(long handle, Class<T> c) {
lock.lock();
try {
Map<Long, Object> innerMap = outerMap.get(c);
if (innerMap == null) {
if (LOG.isLoggable(INFO))
LOG.info("0 handles for " + c.getName());
return null;
}
if (LOG.isLoggable(INFO))
LOG.info(innerMap.size() + " handles for " + c.getName());
Object o = innerMap.get(handle);
return c.cast(o);
} finally {
lock.unlock();
}
}
@Override
public <T> long putReference(T reference, Class<T> c) {
lock.lock();
try {
Map<Long, Object> innerMap = outerMap.get(c);
if (innerMap == null) {
innerMap = new HashMap<>();
outerMap.put(c, innerMap);
}
long handle = nextHandle++;
innerMap.put(handle, reference);
if (LOG.isLoggable(INFO)) {
LOG.info(innerMap.size() + " handles for " + c.getName() +
" after put");
}
return handle;
} finally {
lock.unlock();
}
}
@Override
public <T> T removeReference(long handle, Class<T> c) {
lock.lock();
try {
Map<Long, Object> innerMap = outerMap.get(c);
if (innerMap == null) return null;
Object o = innerMap.remove(handle);
if (innerMap.isEmpty()) outerMap.remove(c);
if (LOG.isLoggable(INFO)) {
LOG.info(innerMap.size() + " handles for " + c.getName() +
" after remove");
}
return c.cast(o);
} finally {
lock.unlock();
}
}
}

View File

@@ -0,0 +1,77 @@
package org.briarproject.briar.android;
import android.os.SystemClock;
import android.util.Log;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import static java.util.Locale.US;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
public class SleepMonitor implements Runnable {
/**
* How often to check the uptime and real time.
*/
private static final int INTERVAL_MS = 5000;
/**
* If the difference between uptime and real time changes by more than
* this amount, assume deep sleep has occurred.
*/
private static final int MIN_SLEEP_DURATION_MS = 1000;
private final ScheduledExecutorService executorService;
private volatile long uptime, realtime, diff;
SleepMonitor() {
uptime = SystemClock.uptimeMillis();
realtime = SystemClock.elapsedRealtime();
diff = realtime - uptime;
executorService = Executors.newSingleThreadScheduledExecutor();
}
void start() {
executorService.scheduleAtFixedRate(this, 0, INTERVAL_MS, MILLISECONDS);
}
@Override
public void run() {
long lastRealtime = realtime;
long sleepDuration = getSleepDuration();
if (sleepDuration > MIN_SLEEP_DURATION_MS) {
long elapsed = realtime - lastRealtime;
long now = System.currentTimeMillis();
String earliestStart = getTime(now - elapsed);
String earliestEnd = getTime(now - elapsed + sleepDuration);
String latestStart = getTime(now - sleepDuration);
String latestEnd = getTime(now);
Log.i("SLEEP_INFO", "System slept for " + sleepDuration
+ " ms since last check " + elapsed
+ " ms ago (earliest " + earliestStart + " - "
+ earliestEnd + ", latest " + latestStart + " - "
+ latestEnd + ")");
}
}
/**
* Returns the amount of time spent in deep sleep since the last check.
*/
private long getSleepDuration() {
uptime = SystemClock.uptimeMillis();
realtime = SystemClock.elapsedRealtime();
long lastDiff = diff;
diff = realtime - uptime;
return diff - lastDiff;
}
private String getTime(long time) {
DateFormat sdf = new SimpleDateFormat("HH:mm:ss", US);
return sdf.format(new Date(time));
}
}

View File

@@ -1,27 +0,0 @@
package org.briarproject.briar.api.android;
/**
* Manages mappings between object references and serialisable handles. This
* enables references to be passed between Android UI objects that belong to
* the same process but can only communicate via serialisation.
*/
public interface ReferenceManager {
/**
* Returns the object with the given handle, or null if no mapping exists
* for the handle.
*/
<T> T getReference(long handle, Class<T> c);
/**
* Creates a mapping between the given reference and a handle, and returns
* the handle.
*/
<T> long putReference(T reference, Class<T> c);
/**
* Removes and returns the object with the given handle, or returns null
* if no mapping exists for the handle.
*/
<T> T removeReference(long handle, Class<T> c);
}

View File

@@ -15,7 +15,9 @@
android:layout_weight="1"
android:gravity="top"
android:hint="@string/blogs_rss_feeds_import_hint"
android:inputType="textUri"/>
android:inputType="textUri"
android:paddingLeft="@dimen/margin_large"
android:paddingRight="@dimen/margin_large"/>
<Button
android:id="@+id/importButton"

View File

@@ -12,6 +12,8 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:paddingLeft="@dimen/margin_large"
android:paddingRight="@dimen/margin_large"
android:textSize="@dimen/text_size_medium"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"