diff --git a/tor-android-binary/src/main/java/org/torproject/jni/TorService.java b/tor-android-binary/src/main/java/org/torproject/jni/TorService.java
index b34cef707a730f063891df6ac92c2fb125574701..affdca0413922b0acfe4f0de56a016460140d66c 100644
--- a/tor-android-binary/src/main/java/org/torproject/jni/TorService.java
+++ b/tor-android-binary/src/main/java/org/torproject/jni/TorService.java
@@ -7,6 +7,7 @@ import android.os.Binder;
 import android.os.FileObserver;
 import android.os.IBinder;
 import android.os.Process;
+import android.util.Log;
 
 import net.freehaven.tor.control.RawEventListener;
 import net.freehaven.tor.control.TorControlCommands;
@@ -24,6 +25,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
 
 import androidx.annotation.Nullable;
 import androidx.localbroadcastmanager.content.LocalBroadcastManager;
@@ -167,6 +169,12 @@ public class TorService extends Service {
 
     private TorControlConnection torControlConnection;
 
+    /**
+     * This lock must be acquired before calling createTorConfiguration() and
+     * held until mainConfigurationFree() has been called.
+     */
+    private static final ReentrantLock runLock = new ReentrantLock();
+
     private native String apiGetProviderVersion();
 
     private native boolean createTorConfiguration();
@@ -314,50 +322,61 @@ public class TorService extends Service {
                         httpTunnelPort = Integer.toString(8118);
                     }
 
-                    createTorConfiguration();
-                    ArrayList<String> lines = new ArrayList<>(Arrays.asList("tor", "--verify-config", // must always be here
-                            "--RunAsDaemon", "0",
-                            "-f", getTorrc(context).getAbsolutePath(),
-                            "--defaults-torrc", getDefaultsTorrc(context).getAbsolutePath(),
-                            "--ignore-missing-torrc",
-                            "--SyslogIdentityTag", TAG,
-                            "--CacheDirectory", new File(getCacheDir(), TAG).getAbsolutePath(),
-                            "--DataDirectory", getAppTorServiceDataDir(context).getAbsolutePath(),
-                            "--ControlSocket", getControlSocket(context).getAbsolutePath(),
-                            "--CookieAuthentication", "0",
-                            "--SOCKSPort", socksPort,
-                            "--HTTPTunnelPort", httpTunnelPort,
-
-                            // can be moved to ControlPort messages
-                            "--LogMessageDomains", "1",
-                            "--TruncateLogFile", "1"
-                    ));
-                    String[] verifyLines = lines.toArray(new String[0]);
-                    if (!mainConfigurationSetCommandLine(verifyLines)) {
-                        throw new IllegalArgumentException("Setting command line failed: " + Arrays.toString(verifyLines));
-                    }
-                    int result = runMain(); // run verify
-                    if (result != 0) {
-                        throw new IllegalArgumentException("Bad command flags: " + Arrays.toString(verifyLines));
+                    if (runLock.isLocked()) {
+                        Log.i(TAG, "Waiting for lock");
                     }
+                    runLock.lock();
+                    Log.i(TAG, "Acquired lock");
+                    try {
+                        createTorConfiguration();
+                        ArrayList<String> lines = new ArrayList<>(Arrays.asList("tor", "--verify-config", // must always be here
+                                "--RunAsDaemon", "0",
+                                "-f", getTorrc(context).getAbsolutePath(),
+                                "--defaults-torrc", getDefaultsTorrc(context).getAbsolutePath(),
+                                "--ignore-missing-torrc",
+                                "--SyslogIdentityTag", TAG,
+                                "--CacheDirectory", new File(getCacheDir(), TAG).getAbsolutePath(),
+                                "--DataDirectory", getAppTorServiceDataDir(context).getAbsolutePath(),
+                                "--ControlSocket", getControlSocket(context).getAbsolutePath(),
+                                "--CookieAuthentication", "0",
+                                "--SOCKSPort", socksPort,
+                                "--HTTPTunnelPort", httpTunnelPort,
+
+                                // can be moved to ControlPort messages
+                                "--LogMessageDomains", "1",
+                                "--TruncateLogFile", "1"
+                        ));
+                        String[] verifyLines = lines.toArray(new String[0]);
+                        if (!mainConfigurationSetCommandLine(verifyLines)) {
+                            throw new IllegalArgumentException("Setting command line failed: " + Arrays.toString(verifyLines));
+                        }
+                        int result = runMain(); // run verify
+                        if (result != 0) {
+                            throw new IllegalArgumentException("Bad command flags: " + Arrays.toString(verifyLines));
+                        }
 
-                    controlPortThreadStarted = new CountDownLatch(1);
-                    controlPortThread.start();
-                    controlPortThreadStarted.await();
+                        controlPortThreadStarted = new CountDownLatch(1);
+                        controlPortThread.start();
+                        controlPortThreadStarted.await();
 
-                    String[] runLines = new String[lines.size() - 1];
-                    runLines[0] = "tor";
-                    for (int i = 2; i < lines.size(); i++) {
-                        runLines[i - 1] = lines.get(i);
-                    }
-                    if (!mainConfigurationSetCommandLine(runLines)) {
-                        throw new IllegalArgumentException("Setting command line failed: " + Arrays.toString(runLines));
-                    }
-                    if (!mainConfigurationSetupControlSocket()) {
-                        throw new IllegalStateException("Setting up ControlPort failed!");
-                    }
-                    if (runMain() != 0) {
-                        throw new IllegalStateException("Tor could not start!");
+                        String[] runLines = new String[lines.size() - 1];
+                        runLines[0] = "tor";
+                        for (int i = 2; i < lines.size(); i++) {
+                            runLines[i - 1] = lines.get(i);
+                        }
+                        if (!mainConfigurationSetCommandLine(runLines)) {
+                            throw new IllegalArgumentException("Setting command line failed: " + Arrays.toString(runLines));
+                        }
+                        if (!mainConfigurationSetupControlSocket()) {
+                            throw new IllegalStateException("Setting up ControlPort failed!");
+                        }
+                        if (runMain() != 0) {
+                            throw new IllegalStateException("Tor could not start!");
+                        }
+                    } finally {
+                        mainConfigurationFree();
+                        Log.i(TAG, "Releasing lock");
+                        runLock.unlock();
                     }
 
                 } catch (IllegalStateException | IllegalArgumentException | InterruptedException e) {
@@ -377,7 +396,6 @@ public class TorService extends Service {
             torControlConnection.removeRawEventListener(startedEventListener);
         }
         shutdownTor(TorControlCommands.SIGNAL_SHUTDOWN);
-        mainConfigurationFree();
         broadcastStatus(TorService.this, STATUS_OFF);
     }