diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
index b0cc91746d57a6955d2c5b631d97258e8a2ba361..d98c2134363e611077a4f84e34500aca9714af4e 100644
--- a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
+++ b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
@@ -24,6 +24,7 @@ import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
 import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
 import org.briarproject.api.properties.TransportProperties;
 import org.briarproject.api.settings.Settings;
+import org.briarproject.api.system.Clock;
 import org.briarproject.api.system.LocationUtils;
 import org.briarproject.util.StringUtils;
 
@@ -44,6 +45,7 @@ import java.util.Scanner;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.logging.Logger;
 import java.util.regex.Pattern;
 import java.util.zip.ZipInputStream;
@@ -63,7 +65,7 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 	static final TransportId ID = new TransportId("tor");
 
 	private static final String[] EVENTS = {
-			"CIRC", "ORCONN", "NOTICE", "WARN", "ERR"
+			"CIRC", "ORCONN", "HS_DESC", "NOTICE", "WARN", "ERR"
 	};
 	private static final String OWNER = "__OwningControllerProcess";
 	private static final int SOCKS_PORT = 59050, CONTROL_PORT = 59051;
@@ -71,23 +73,27 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 	private static final int HOSTNAME_TIMEOUT = 30 * 1000; // Milliseconds
 	private static final Pattern ONION =
 			Pattern.compile("[a-z2-7]{16}\\.onion");
+	private static final int MIN_DESCRIPTORS_PUBLISHED = 3;
 	private static final Logger LOG =
 			Logger.getLogger(TorPlugin.class.getName());
 
 	private final Executor ioExecutor;
 	private final Context appContext;
 	private final LocationUtils locationUtils;
+	private final Clock clock;
 	private final DuplexPluginCallback callback;
 	private final String architecture;
 	private final int maxLatency, maxIdleTime, pollingInterval, socketTimeout;
 	private final File torDirectory, torFile, geoIpFile, configFile, doneFile;
 	private final File cookieFile, hostnameFile;
 	private final AtomicBoolean circuitBuilt;
+	private final AtomicInteger descriptorsPublished;
 
 	private volatile boolean running = false, networkEnabled = false;
 	private volatile boolean bootstrapped = false;
 	private volatile boolean connectedToWifi = false;
 	private volatile boolean online = false;
+	private volatile long descriptorsPublishedTime = Long.MAX_VALUE;
 
 	private volatile ServerSocket socket = null;
 	private volatile Socket controlSocket = null;
@@ -95,12 +101,13 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 	private volatile BroadcastReceiver networkStateReceiver = null;
 
 	TorPlugin(Executor ioExecutor, Context appContext,
-			LocationUtils locationUtils, DuplexPluginCallback callback,
-			String architecture, int maxLatency, int maxIdleTime,
-			int pollingInterval) {
+			LocationUtils locationUtils, Clock clock,
+			DuplexPluginCallback callback, String architecture, int maxLatency,
+			int maxIdleTime, int pollingInterval) {
 		this.ioExecutor = ioExecutor;
 		this.appContext = appContext;
 		this.locationUtils = locationUtils;
+		this.clock = clock;
 		this.callback = callback;
 		this.architecture = architecture;
 		this.maxLatency = maxLatency;
@@ -117,6 +124,7 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 		cookieFile = new File(torDirectory, ".tor/control_auth_cookie");
 		hostnameFile = new File(torDirectory, "hs/hostname");
 		circuitBuilt = new AtomicBoolean(false);
+		descriptorsPublished = new AtomicInteger(0);
 	}
 
 	public TransportId getId() {
@@ -462,6 +470,8 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 		if (LOG.isLoggable(INFO)) LOG.info("Enabling network: " + enable);
 		if (!enable) {
 			circuitBuilt.set(false);
+			descriptorsPublished.set(0);
+			descriptorsPublishedTime = Long.MAX_VALUE;
 			callback.transportDisabled();
 		}
 		networkEnabled = enable;
@@ -503,6 +513,14 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 
 	public void poll(Collection<ContactId> connected) {
 		if (!isRunning()) return;
+		if (descriptorsPublished.get() >= MIN_DESCRIPTORS_PUBLISHED) {
+			long now = clock.currentTimeMillis();
+			if (now - descriptorsPublishedTime >= 2 * pollingInterval) {
+				LOG.info("Hidden service descriptor published, not polling");
+				return;
+			}
+		}
+		// TODO: Pass properties to connectAndCallBack()
 		for (ContactId c : callback.getRemoteProperties().keySet())
 			if (!connected.contains(c)) connectAndCallBack(c);
 	}
@@ -576,7 +594,15 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 		}
 	}
 
-	public void unrecognized(String type, String msg) {}
+	public void unrecognized(String type, String msg) {
+		if (type.equals("HS_DESC") && msg.startsWith("UPLOADED")) {
+			int descriptors = descriptorsPublished.incrementAndGet();
+			if (descriptors == MIN_DESCRIPTORS_PUBLISHED) {
+				LOG.info("Hidden service descriptor published");
+				descriptorsPublishedTime = clock.currentTimeMillis();
+			}
+		}
+	}
 
 	private static class WriteObserver extends FileObserver {
 
diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java b/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java
index 8561e4cdfffef4daee3fa36ab865e0976a704f60..3c6a749867b89366a086e6dfddf518e4337a76df 100644
--- a/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java
+++ b/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java
@@ -9,7 +9,9 @@ import org.briarproject.api.event.EventBus;
 import org.briarproject.api.plugins.duplex.DuplexPlugin;
 import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
 import org.briarproject.api.plugins.duplex.DuplexPluginFactory;
+import org.briarproject.api.system.Clock;
 import org.briarproject.api.system.LocationUtils;
+import org.briarproject.system.SystemClock;
 
 import java.util.concurrent.Executor;
 import java.util.logging.Logger;
@@ -21,12 +23,13 @@ public class TorPluginFactory implements DuplexPluginFactory {
 
 	private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
 	private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
-	private static final int POLLING_INTERVAL = 3 * 60 * 1000; // 3 minutes
+	private static final int POLLING_INTERVAL = 2 * 60 * 1000; // 2 minutes
 
 	private final Executor ioExecutor;
 	private final Context appContext;
 	private final LocationUtils locationUtils;
 	private final EventBus eventBus;
+	private final Clock clock;
 
 	public TorPluginFactory(Executor ioExecutor, Context appContext,
 			LocationUtils locationUtils, EventBus eventBus) {
@@ -34,6 +37,7 @@ public class TorPluginFactory implements DuplexPluginFactory {
 		this.appContext = appContext;
 		this.locationUtils = locationUtils;
 		this.eventBus = eventBus;
+		clock = new SystemClock();
 	}
 
 	public TransportId getId() {
@@ -61,7 +65,7 @@ public class TorPluginFactory implements DuplexPluginFactory {
 		if (Build.VERSION.SDK_INT >= 16) architecture += "-pie";
 
 		TorPlugin plugin = new TorPlugin(ioExecutor, appContext, locationUtils,
-				callback, architecture, MAX_LATENCY, MAX_IDLE_TIME,
+				clock, callback, architecture, MAX_LATENCY, MAX_IDLE_TIME,
 				POLLING_INTERVAL);
 		eventBus.addListener(plugin);
 		return plugin;
diff --git a/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java
index 03263bd77669e4a8db8af66068542a65b6cad5d9..64f91c4d1aba73cc117984620541496b98190924 100644
--- a/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java
+++ b/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java
@@ -176,6 +176,7 @@ abstract class TcpPlugin implements DuplexPlugin {
 	public void poll(Collection<ContactId> connected) {
 		if (!isRunning()) return;
 		backoff.increment();
+		// TODO: Pass properties to connectAndCallBack()
 		for (ContactId c : callback.getRemoteProperties().keySet())
 			if (!connected.contains(c)) connectAndCallBack(c);
 	}