diff --git a/briar-android/src/org/briarproject/android/BriarService.java b/briar-android/src/org/briarproject/android/BriarService.java
index ea17bfa2f5363e25e7e5ce70ca2ca7e9e55ecc73..2e606f42eb79e6fd1b3ff21668120f7a8143c1cb 100644
--- a/briar-android/src/org/briarproject/android/BriarService.java
+++ b/briar-android/src/org/briarproject/android/BriarService.java
@@ -4,6 +4,8 @@ import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
+import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
@@ -24,6 +26,7 @@ import org.briarproject.api.event.Event;
 import org.briarproject.api.event.EventListener;
 import org.briarproject.api.event.MessageAddedEvent;
 import org.briarproject.api.lifecycle.LifecycleManager;
+import org.briarproject.api.lifecycle.LifecycleManager.StartResult;
 import org.briarproject.api.messaging.GroupId;
 
 import roboguice.service.RoboService;
@@ -87,11 +90,16 @@ public class BriarService extends RoboService implements EventListener {
 		new Thread() {
 			@Override
 			public void run() {
-				if(lifecycleManager.startServices()) {
+				StartResult result = lifecycleManager.startServices();
+				if(result == SUCCESS) {
 					db.addListener(BriarService.this);
 					started = true;
+				} else if(result == ALREADY_RUNNING) {
+					LOG.info("Already running");
+					stopSelf();
 				} else {
-					LOG.info("Startup failed");
+					if(LOG.isLoggable(WARNING))
+						LOG.warning("Startup failed: " + result);
 					showStartupFailureNotification();
 					stopSelf();
 				}
diff --git a/briar-api/src/org/briarproject/api/lifecycle/LifecycleManager.java b/briar-api/src/org/briarproject/api/lifecycle/LifecycleManager.java
index 1df494ddbc7f9490c99a9c7e584588ac8d8b97ec..5f75237c25e080ed40cdfc0614cdb4107d345fe9 100644
--- a/briar-api/src/org/briarproject/api/lifecycle/LifecycleManager.java
+++ b/briar-api/src/org/briarproject/api/lifecycle/LifecycleManager.java
@@ -2,8 +2,17 @@ package org.briarproject.api.lifecycle;
 
 import java.util.concurrent.ExecutorService;
 
+/**
+ * Manages the lifecycle of the app, starting and stopping {@link Service
+ * Services}, shutting down {@link java.util.concurrent.ExecutorService
+ * ExecutorServices}, and opening and closing the {@link
+ * org.briarproject.api.db.DatabaseComponent DatabaseComponent}.
+ */
 public interface LifecycleManager {
 
+	/** The result of calling {@link LifecycleManager#startServices()}. */
+	enum StartResult { ALREADY_RUNNING, DB_ERROR, SERVICE_ERROR, SUCCESS }
+
 	/** Registers a {@link Service} to be started and stopped. */
 	public void register(Service s);
 
@@ -14,27 +23,37 @@ public interface LifecycleManager {
 	public void registerForShutdown(ExecutorService e);
 
 	/**
-	 * Starts any registered {@link Service}s and returns true if all services
-	 * started successfully.
+	 * Starts any registered {@link Service Services} and opens the {@link
+	 * org.briarproject.api.db.DatabaseComponent DatabaseComponent}.
 	 */
-	public boolean startServices();
+	public StartResult startServices();
 
 	/**
-	 * Stops any registered {@link Service}s and shuts down any registered
-	 * {@link java.util.concurrent.ExecutorService ExecutorService}s.
+	 * Stops any registered {@link Service Services}, shuts down any
+	 * registered {@link java.util.concurrent.ExecutorService ExecutorServices},
+	 * and closes the {@link org.briarproject.api.db.DatabaseComponent
+	 * DatabaseComponent}.
 	 */
 	public void stopServices();
 
-	/** Waits for the database to be opened before returning. */
+	/**
+	 * Waits for the {@link org.briarproject.api.db.DatabaseComponent
+	 * DatabaseComponent} to be opened before returning.
+	 */
 	public void waitForDatabase() throws InterruptedException;
 
-	/** Waits for all registered {@link Service}s to start before returning. */
+	/**
+	 * Waits for the {@link org.briarproject.api.db.DatabaseComponent
+	 * DatabaseComponent} to be opened and all registered {@link Service
+	 * Services} to start before returning.
+	 */
 	public void waitForStartup() throws InterruptedException;
 
 	/**
-	 * Waits for all registered {@link Service}s to stop and all registered
-	 * {@link java.util.concurrent.ExecutorService ExecutorService}s to shut
-	 * down before returning.
+	 * Waits for all registered {@link Service Services} to stop, all
+	 * registered {@link java.util.concurrent.ExecutorService ExecutorServices}
+	 * to shut down, and the {@link org.briarproject.api.db.DatabaseComponent
+	 * DatabaseComponent} to be closed before returning.
 	 */
 	public void waitForShutdown() throws InterruptedException;
 }
\ No newline at end of file
diff --git a/briar-core/src/org/briarproject/lifecycle/LifecycleManagerImpl.java b/briar-core/src/org/briarproject/lifecycle/LifecycleManagerImpl.java
index 15d0375fbd0fcf35f0e1c847f27d71ab2f1618d4..e6ff2c9780cb1ed18666dbb6f1f9e81ff6895324 100644
--- a/briar-core/src/org/briarproject/lifecycle/LifecycleManagerImpl.java
+++ b/briar-core/src/org/briarproject/lifecycle/LifecycleManagerImpl.java
@@ -2,12 +2,17 @@ package org.briarproject.lifecycle;
 
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
+import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.DB_ERROR;
+import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.SERVICE_ERROR;
+import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
 
 import java.io.IOException;
 import java.util.Collection;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Semaphore;
 import java.util.logging.Logger;
 
 import javax.inject.Inject;
@@ -27,6 +32,7 @@ class LifecycleManagerImpl implements LifecycleManager {
 	private final DatabaseComponent db;
 	private final Collection<Service> services;
 	private final Collection<ExecutorService> executors;
+	private final Semaphore startStopSemaphore = new Semaphore(1);
 	private final CountDownLatch dbLatch = new CountDownLatch(1);
 	private final CountDownLatch startupLatch = new CountDownLatch(1);
 	private final CountDownLatch shutdownLatch = new CountDownLatch(1);
@@ -51,12 +57,16 @@ class LifecycleManagerImpl implements LifecycleManager {
 		executors.add(e);
 	}
 
-	public boolean startServices() {
+	public StartResult startServices() {
+		if(!startStopSemaphore.tryAcquire()) {
+			LOG.info("Already starting or stopping");
+			return ALREADY_RUNNING;
+		}
 		try {
-			LOG.info("Starting");
-			long start = clock.currentTimeMillis();
+			LOG.info("Starting services");
+			long now = clock.currentTimeMillis();
 			boolean reopened = db.open();
-			long duration = clock.currentTimeMillis() - start;
+			long duration = clock.currentTimeMillis() - now;
 			if(LOG.isLoggable(INFO)) {
 				if(reopened)
 					LOG.info("Reopening database took " + duration + " ms");
@@ -64,15 +74,15 @@ class LifecycleManagerImpl implements LifecycleManager {
 			}
 			dbLatch.countDown();
 			for(Service s : services) {
-				start = clock.currentTimeMillis();
+				now = clock.currentTimeMillis();
 				boolean started = s.start();
-				duration = clock.currentTimeMillis() - start;
+				duration = clock.currentTimeMillis() - now;
 				if(!started) {
 					if(LOG.isLoggable(WARNING)) {
 						String name = s.getClass().getName();
 						LOG.warning(name + " did not start");
 					}
-					return false;
+					return SERVICE_ERROR;
 				}
 				if(LOG.isLoggable(INFO)) {
 					String name = s.getClass().getName();
@@ -80,19 +90,27 @@ class LifecycleManagerImpl implements LifecycleManager {
 				}
 			}
 			startupLatch.countDown();
-			return true;
+			return SUCCESS;
 		} catch(DbException e) {
 			if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
-			return false;
+			return DB_ERROR;
 		} catch(IOException e) {
 			if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
-			return false;
+			return DB_ERROR;
+		} finally {
+			startStopSemaphore.release();
 		}
 	}
 
 	public void stopServices() {
 		try {
-			LOG.info("Shutting down");
+			startStopSemaphore.acquire();
+		} catch(InterruptedException e) {
+			LOG.warning("Interrupted while waiting to stop services");
+			return;
+		}
+		try {
+			LOG.info("Stopping services");
 			for(Service s : services) {
 				boolean stopped = s.stop();
 				if(LOG.isLoggable(INFO)) {
@@ -111,6 +129,8 @@ class LifecycleManagerImpl implements LifecycleManager {
 			if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
 		} catch(IOException e) {
 			if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+		} finally {
+			startStopSemaphore.release();
 		}
 	}
 
diff --git a/briar-tests/src/org/briarproject/TestLifecycleModule.java b/briar-tests/src/org/briarproject/TestLifecycleModule.java
index 5f91d0ba6b58d58936043d8a52d5ef1fdf7be0cb..becccd4523a35d4834682595750ccf81b05a698b 100644
--- a/briar-tests/src/org/briarproject/TestLifecycleModule.java
+++ b/briar-tests/src/org/briarproject/TestLifecycleModule.java
@@ -17,7 +17,7 @@ public class TestLifecycleModule extends AbstractModule {
 
 			public void registerForShutdown(ExecutorService e) {}
 
-			public boolean startServices() { return true; }
+			public StartResult startServices() { return StartResult.SUCCESS; }
 
 			public void stopServices() {}