diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseMigrationEvent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseMigrationEvent.java
deleted file mode 100644
index 7edd81fa0c19a7b4b8126d591141376e85f8355b..0000000000000000000000000000000000000000
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseMigrationEvent.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.briarproject.bramble.api.db;
-
-import org.briarproject.bramble.api.event.Event;
-
-/**
- * An event that is broadcast before database migrations are being applied.
- */
-public class DatabaseMigrationEvent extends Event {
-}
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/LifecycleManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/LifecycleManager.java
index 95b4ac08c19a5724c3da5e1e4277bae6e8c70b6f..5a036a3b6cc2005a36c28bbaacb67638256941a1 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/LifecycleManager.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/LifecycleManager.java
@@ -34,7 +34,12 @@ public interface LifecycleManager {
 	 * Returned by {@link #getLifecycleState()}
 	 */
 	enum LifecycleState {
-		STARTING, MIGRATING, RUNNING
+
+		STARTING, MIGRATING_DATABASE, STARTING_SERVICES, RUNNING, STOPPING;
+
+		public boolean isAfter(LifecycleState state) {
+			return ordinal() > state.ordinal();
+		}
 	}
 
 	/**
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/event/LifecycleEvent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/event/LifecycleEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..4e6370bcfb0064b42f6391f141b4fc8702778a0b
--- /dev/null
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/event/LifecycleEvent.java
@@ -0,0 +1,20 @@
+package org.briarproject.bramble.api.lifecycle.event;
+
+import org.briarproject.bramble.api.event.Event;
+import org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState;
+
+/**
+ * An event that is broadcast when the app enters a new lifecycle state.
+ */
+public class LifecycleEvent extends Event {
+
+	private final LifecycleState state;
+
+	public LifecycleEvent(LifecycleState state) {
+		this.state = state;
+	}
+
+	public LifecycleState getLifecycleState() {
+		return state;
+	}
+}
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/event/ShutdownEvent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/event/ShutdownEvent.java
deleted file mode 100644
index ba0c4d37f03e963483432eb115070379d2abbcc5..0000000000000000000000000000000000000000
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/event/ShutdownEvent.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.briarproject.bramble.api.lifecycle.event;
-
-import org.briarproject.bramble.api.event.Event;
-
-/**
- * An event that is broadcast when the app is shutting down.
- */
-public class ShutdownEvent extends Event {
-}
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/event/StartupEvent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/event/StartupEvent.java
deleted file mode 100644
index 973bd1c4700bfcaf6f4fa78eea5dd1aca36071cd..0000000000000000000000000000000000000000
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/event/StartupEvent.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.briarproject.bramble.api.lifecycle.event;
-
-import org.briarproject.bramble.api.event.Event;
-
-/**
- * An event that is broadcast when the app is starting.
- * This happens after the database was opened and services were started.
- */
-public class StartupEvent extends Event {
-}
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java
index 6e55a8df58f3589211ee519bad9d6e6dd025dde9..0f41cbf211676f5427b56591a24e872c085ecef9 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java
@@ -5,7 +5,6 @@ import org.briarproject.bramble.api.crypto.KeyPair;
 import org.briarproject.bramble.api.db.DataTooNewException;
 import org.briarproject.bramble.api.db.DataTooOldException;
 import org.briarproject.bramble.api.db.DatabaseComponent;
-import org.briarproject.bramble.api.db.DatabaseMigrationEvent;
 import org.briarproject.bramble.api.db.DbException;
 import org.briarproject.bramble.api.db.MigrationListener;
 import org.briarproject.bramble.api.db.Transaction;
@@ -16,8 +15,7 @@ import org.briarproject.bramble.api.identity.LocalAuthor;
 import org.briarproject.bramble.api.lifecycle.LifecycleManager;
 import org.briarproject.bramble.api.lifecycle.Service;
 import org.briarproject.bramble.api.lifecycle.ServiceException;
-import org.briarproject.bramble.api.lifecycle.event.ShutdownEvent;
-import org.briarproject.bramble.api.lifecycle.event.StartupEvent;
+import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.Client;
 
@@ -34,9 +32,11 @@ import javax.inject.Inject;
 
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
-import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING;
+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.STARTING;
+import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING_SERVICES;
+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.DATA_TOO_NEW_ERROR;
 import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.DATA_TOO_OLD_ERROR;
@@ -63,6 +63,7 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
 	private final CountDownLatch dbLatch = new CountDownLatch(1);
 	private final CountDownLatch startupLatch = new CountDownLatch(1);
 	private final CountDownLatch shutdownLatch = new CountDownLatch(1);
+
 	private volatile LifecycleState state = STARTING;
 
 	@Inject
@@ -142,7 +143,10 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
 				registerLocalAuthor(createLocalAuthor(nickname));
 			}
 
+			state = STARTING_SERVICES;
 			dbLatch.countDown();
+			eventBus.broadcast(new LifecycleEvent(STARTING_SERVICES));
+
 			Transaction txn = db.startTransaction(false);
 			try {
 				for (Client c : clients) {
@@ -168,9 +172,10 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
 							+ " took " + duration + " ms");
 				}
 			}
-			startupLatch.countDown();
+
 			state = RUNNING;
-			eventBus.broadcast(new StartupEvent());
+			startupLatch.countDown();
+			eventBus.broadcast(new LifecycleEvent(RUNNING));
 			return SUCCESS;
 		} catch (DataTooOldException e) {
 			if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
@@ -191,8 +196,8 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
 
 	@Override
 	public void onMigrationRun() {
-		state = MIGRATING;
-		eventBus.broadcast(new DatabaseMigrationEvent());
+		state = MIGRATING_DATABASE;
+		eventBus.broadcast(new LifecycleEvent(MIGRATING_DATABASE));
 	}
 
 	@Override
@@ -205,7 +210,8 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
 		}
 		try {
 			LOG.info("Stopping services");
-			eventBus.broadcast(new ShutdownEvent());
+			state = STOPPING;
+			eventBus.broadcast(new LifecycleEvent(STOPPING));
 			for (Service s : services) {
 				long start = System.currentTimeMillis();
 				s.stopService();
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/sync/DuplexOutgoingSession.java b/bramble-core/src/main/java/org/briarproject/bramble/sync/DuplexOutgoingSession.java
index 3fdabc01dcc239959f3c54d339c050cc7e6d4536..80f699a1f9e6ebdb134ae0835541018992c6c406 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/sync/DuplexOutgoingSession.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/sync/DuplexOutgoingSession.java
@@ -10,7 +10,7 @@ import org.briarproject.bramble.api.event.Event;
 import org.briarproject.bramble.api.event.EventBus;
 import org.briarproject.bramble.api.event.EventListener;
 import org.briarproject.bramble.api.lifecycle.IoExecutor;
-import org.briarproject.bramble.api.lifecycle.event.ShutdownEvent;
+import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.Ack;
 import org.briarproject.bramble.api.sync.Offer;
@@ -38,6 +38,7 @@ import javax.annotation.concurrent.ThreadSafe;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
 import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
 import static org.briarproject.bramble.api.sync.SyncConstants.MAX_RECORD_PAYLOAD_LENGTH;
 
@@ -209,8 +210,9 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
 		} else if (e instanceof MessageToRequestEvent) {
 			if (((MessageToRequestEvent) e).getContactId().equals(contactId))
 				generateRequest();
-		} else if (e instanceof ShutdownEvent) {
-			interrupt();
+		} else if (e instanceof LifecycleEvent) {
+			LifecycleEvent l = (LifecycleEvent) e;
+			if (l.getLifecycleState() == STOPPING) interrupt();
 		}
 	}
 
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/sync/IncomingSession.java b/bramble-core/src/main/java/org/briarproject/bramble/sync/IncomingSession.java
index 249d1f2c6be2e227f557b84b36131f567f10fcdb..32eb58df4854d87c080671e913926e7dd3a2e925 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/sync/IncomingSession.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/sync/IncomingSession.java
@@ -11,7 +11,7 @@ import org.briarproject.bramble.api.event.Event;
 import org.briarproject.bramble.api.event.EventBus;
 import org.briarproject.bramble.api.event.EventListener;
 import org.briarproject.bramble.api.lifecycle.IoExecutor;
-import org.briarproject.bramble.api.lifecycle.event.ShutdownEvent;
+import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.Ack;
 import org.briarproject.bramble.api.sync.Message;
@@ -27,6 +27,7 @@ import java.util.logging.Logger;
 import javax.annotation.concurrent.ThreadSafe;
 
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
 
 /**
  * An incoming {@link SyncSession}.
@@ -96,8 +97,9 @@ class IncomingSession implements SyncSession, EventListener {
 		if (e instanceof ContactRemovedEvent) {
 			ContactRemovedEvent c = (ContactRemovedEvent) e;
 			if (c.getContactId().equals(contactId)) interrupt();
-		} else if (e instanceof ShutdownEvent) {
-			interrupt();
+		} else if (e instanceof LifecycleEvent) {
+			LifecycleEvent l = (LifecycleEvent) e;
+			if (l.getLifecycleState() == STOPPING) interrupt();
 		}
 	}
 
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/sync/SimplexOutgoingSession.java b/bramble-core/src/main/java/org/briarproject/bramble/sync/SimplexOutgoingSession.java
index 3d0ecae22b739912b498e380156a9970eedb2028..b1f8198f86dcb6b0d771527876de0ce9261ab057 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/sync/SimplexOutgoingSession.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/sync/SimplexOutgoingSession.java
@@ -10,7 +10,7 @@ import org.briarproject.bramble.api.event.Event;
 import org.briarproject.bramble.api.event.EventBus;
 import org.briarproject.bramble.api.event.EventListener;
 import org.briarproject.bramble.api.lifecycle.IoExecutor;
-import org.briarproject.bramble.api.lifecycle.event.ShutdownEvent;
+import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.Ack;
 import org.briarproject.bramble.api.sync.RecordWriter;
@@ -28,6 +28,7 @@ import javax.annotation.concurrent.ThreadSafe;
 
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
 import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
 import static org.briarproject.bramble.api.sync.SyncConstants.MAX_RECORD_PAYLOAD_LENGTH;
 
@@ -109,8 +110,9 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
 		if (e instanceof ContactRemovedEvent) {
 			ContactRemovedEvent c = (ContactRemovedEvent) e;
 			if (c.getContactId().equals(contactId)) interrupt();
-		} else if (e instanceof ShutdownEvent) {
-			interrupt();
+		} else if (e instanceof LifecycleEvent) {
+			LifecycleEvent l = (LifecycleEvent) e;
+			if (l.getLifecycleState() == STOPPING) interrupt();
 		}
 	}
 
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/OpenDatabaseActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/login/OpenDatabaseActivity.java
index 16c49847ca1a5dbb91e28c0c4006efe15b198405..d24196d32b8a56d69dd2925fc8575a52d41b0a74 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/OpenDatabaseActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/login/OpenDatabaseActivity.java
@@ -6,12 +6,12 @@ import android.support.annotation.Nullable;
 import android.widget.ImageView;
 import android.widget.TextView;
 
-import org.briarproject.bramble.api.db.DatabaseMigrationEvent;
 import org.briarproject.bramble.api.event.Event;
 import org.briarproject.bramble.api.event.EventBus;
 import org.briarproject.bramble.api.event.EventListener;
 import org.briarproject.bramble.api.lifecycle.LifecycleManager;
-import org.briarproject.bramble.api.lifecycle.event.StartupEvent;
+import org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState;
+import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
 import org.briarproject.briar.R;
 import org.briarproject.briar.android.activity.ActivityComponent;
 import org.briarproject.briar.android.activity.BriarActivity;
@@ -20,8 +20,8 @@ import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
 import javax.annotation.ParametersAreNonnullByDefault;
 import javax.inject.Inject;
 
-import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING;
-import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RUNNING;
+import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING_DATABASE;
+import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING_SERVICES;
 
 @ParametersAreNonnullByDefault
 public class OpenDatabaseActivity extends BriarActivity
@@ -52,12 +52,11 @@ public class OpenDatabaseActivity extends BriarActivity
 	@Override
 	public void onStart() {
 		super.onStart();
-		if (lifecycleManager.getLifecycleState() == RUNNING) {
+		LifecycleState state = lifecycleManager.getLifecycleState();
+		if (state.isAfter(STARTING_SERVICES)) {
 			finishAndStartApp();
 		} else {
-			if (lifecycleManager.getLifecycleState() == MIGRATING) {
-				showMigration();
-			}
+			if (state == MIGRATING_DATABASE) showMigration();
 			eventBus.addListener(this);
 		}
 	}
@@ -70,10 +69,12 @@ public class OpenDatabaseActivity extends BriarActivity
 
 	@Override
 	public void eventOccurred(Event e) {
-		if (e instanceof StartupEvent) {
-			runOnUiThreadUnlessDestroyed(this::finishAndStartApp);
-		} else if (e instanceof DatabaseMigrationEvent) {
-			runOnUiThreadUnlessDestroyed(this::showMigration);
+		if (e instanceof LifecycleEvent) {
+			LifecycleState state = ((LifecycleEvent) e).getLifecycleState();
+			if (state.isAfter(STARTING_SERVICES))
+				runOnUiThreadUnlessDestroyed(this::finishAndStartApp);
+			else if (state == MIGRATING_DATABASE)
+				runOnUiThreadUnlessDestroyed(this::showMigration);
 		}
 	}