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); }