[tor-commits] [tor-browser/tor-browser-60.5.1esr-8.5-1] Bug 28329 - Part 2. Implement checking if the Tor service is running

gk at torproject.org gk at torproject.org
Fri Mar 15 21:48:09 UTC 2019


commit a6e87093856101ec93bbeaf93eed22ac77031f73
Author: Matthew Finkel <Matthew.Finkel at gmail.com>
Date:   Wed Feb 20 01:04:56 2019 +0000

    Bug 28329 - Part 2. Implement checking if the Tor service is running
---
 .../base/java/org/mozilla/gecko/BrowserApp.java    | 130 +++++++++++++++++++++
 1 file changed, 130 insertions(+)

diff --git a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
index 9330a6ba9838..5aa0a6a7f3ac 100644
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -51,6 +51,7 @@ import android.support.design.widget.Snackbar;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.NotificationCompat;
+import android.support.v4.content.LocalBroadcastManager;
 import android.support.v4.content.res.ResourcesCompat;
 import android.support.v4.view.MenuItemCompat;
 import android.text.TextUtils;
@@ -182,6 +183,7 @@ import org.mozilla.gecko.widget.SplashScreen;
 import org.mozilla.geckoview.GeckoSession;
 
 import org.torproject.android.OrbotMainActivity;
+import org.torproject.android.service.TorService;
 import org.torproject.android.service.TorServiceConstants;
 
 import java.io.File;
@@ -270,6 +272,7 @@ public class BrowserApp extends GeckoApp
     private TabsPanel mTabsPanel;
 
     private boolean mOrbotNeedsStart = true;
+    private boolean mTorNeedsStart = true;
 
     private boolean showSplashScreen = false;
     private SplashScreen splashScreen;
@@ -1079,6 +1082,131 @@ public class BrowserApp extends GeckoApp
     }
 
     /**
+     * Send the service a request for the current status.
+     * The response is sent as a broadcast. Capture that in
+     * receiveTorIsStartedAsync().
+     */
+    private void requestTorIsStartedAsync() {
+        Intent torServiceStatus = new Intent(this, TorService.class);
+        torServiceStatus.setAction(TorServiceConstants.ACTION_STATUS);
+        startService(torServiceStatus);
+    }
+
+    private BroadcastReceiver mLocalBroadcastReceiver;
+    private Boolean mTorStatus;
+
+    /**
+     * Setup the status receiver for broadcasts from the service.
+     * The response is sent as a broadcast. Create a background thread
+     * for receiving/handling the broadcast.
+     *
+     * This method is coupled with receiveTorIsStartedAsync(). They should
+     * be used together.
+     */
+    private BroadcastReceiver setupReceiveTorIsStartedAsync() {
+
+        // Create a thread specifically for defining the BroadcastReceiver
+        new Thread(new Runnable() {
+
+            @Override
+            public void run() {
+                mLocalBroadcastReceiver = new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        String action = intent.getAction();
+                        if (action == null) {
+                            return;
+                        }
+
+                        // We only want ACTION_STATUS messages
+                        if (!action.equals(TorServiceConstants.ACTION_STATUS)) {
+                            return;
+                        }
+
+                        // The current status has the EXTRA_STATUS key
+                        String currentStatus =
+                            intent.getStringExtra(TorServiceConstants.EXTRA_STATUS);
+
+                        try {
+                            synchronized (mTorStatus) {
+                                mTorStatus = (currentStatus == TorServiceConstants.STATUS_ON);
+                                mTorStatus.notify();
+                            }
+                        } catch (IllegalMonitorStateException e) {
+                            // |synchronized| should prevent this
+                        }
+                    }
+                };
+
+                LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(BrowserApp.this);
+                lbm.registerReceiver(mLocalBroadcastReceiver,
+                        new IntentFilter(TorServiceConstants.ACTION_STATUS));
+
+            }
+        }).start();
+
+        return mLocalBroadcastReceiver;
+    }
+
+    /**
+     * Receive the current status from the service.
+     * The response is sent as a broadcast. If it is not received within
+     * 1 second, then return false.
+     *
+     * This method is coupled with setupReceiveTorIsStartedAsync(). They
+     * should be used together.
+     */
+    private boolean receiveTorIsStartedAsync(BroadcastReceiver mLocalBroadcastReceiver, Boolean torStatus) {
+        // Wait until we're notified from the above thread, or we're
+        // interrupted by the timeout.
+        try {
+            // One thousand milliseconds = one second
+            final long oneSecTimeout = Math.round(Math.pow(10, 3));
+            synchronized (torStatus) {
+                // We wake from wait() because we reached the one second
+                // timeout, the BroadcastReceiver notified us, or we received
+                // a spurious wakeup. For all three cases, we can accept the
+                // current value of torStatus.
+                torStatus.wait(oneSecTimeout);
+            }
+        } catch (InterruptedException e) {
+            // ignore.
+        } catch (IllegalArgumentException e) {
+            // oneSecTimeout should never be negative
+        } catch (IllegalMonitorStateException e) {
+            // |synchronized| should take care of this
+        }
+
+        // Unregister the receiver
+        LocalBroadcastManager.getInstance(this).unregisterReceiver(mLocalBroadcastReceiver);
+
+        return torStatus;
+    }
+
+    /**
+     * Receive the current Tor status.
+     *
+     * Send a request for the current status and receive the response.
+     * Returns true if Tor is running, false otherwise.
+     *
+     * mTorStatus provides synchronization across threads.
+     */
+    private boolean checkTorIsStarted() {
+        // When tor is started, true. Otherwise, false
+        mTorStatus = false;
+        BroadcastReceiver br = setupReceiveTorIsStartedAsync();
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                requestTorIsStartedAsync();
+            }
+        }).start();
+
+        return receiveTorIsStartedAsync(br, mTorStatus);
+    }
+
+
+    /**
      * Code to actually show the first run pager, separated
      * for distribution purposes.
      */
@@ -1309,6 +1437,7 @@ public class BrowserApp extends GeckoApp
         final SafeIntent intent = new SafeIntent(getIntent());
         if (!IntentUtils.getIsInAutomationFromEnvironment(intent)) {
             checkStartOrbot();
+            mTorNeedsStart = !checkTorIsStarted();
         }
     }
 
@@ -1763,6 +1892,7 @@ public class BrowserApp extends GeckoApp
         GeckoNetworkManager.destroy();
 
         mOrbotNeedsStart = true;
+        mTorNeedsStart = true;
 
         super.onDestroy();
     }





More information about the tor-commits mailing list