commit 726cf0c6c9fcf687d275c61d272887f2d8bdb3e3 Author: Nathan Freitas <nat...@freitas.net> Date: Wed May 7 23:49:54 2014 -0400
work to stabilize Tor background service auto-restart tor binary process if killed by Android OS print out debug info related to memory mgmt requests move bind/start code to async task --- src/org/torproject/android/service/TorService.java | 323 ++++++++++++++------ 1 file changed, 238 insertions(+), 85 deletions(-) diff --git a/src/org/torproject/android/service/TorService.java b/src/org/torproject/android/service/TorService.java index ef8d47e..1a90258 100644 --- a/src/org/torproject/android/service/TorService.java +++ b/src/org/torproject/android/service/TorService.java @@ -22,6 +22,8 @@ import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.StringTokenizer; +import java.util.Timer; +import java.util.TimerTask; import net.freehaven.tor.control.ConfigEntry; import net.freehaven.tor.control.EventHandler; @@ -35,8 +37,8 @@ import org.torproject.android.TorConstants; import org.torproject.android.Utils; import org.torproject.android.settings.AppManager; +import android.annotation.SuppressLint; import android.app.Application; -import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; @@ -63,9 +65,12 @@ public class TorService extends Service implements TorServiceConstants, TorConst public static boolean ENABLE_DEBUG_LOG = false; private static int currentStatus = STATUS_OFF; + + private final static int CONTROL_SOCKET_TIMEOUT = 3000; private TorControlConnection conn = null; private Socket torConnSocket = null; + private int mLastProcessId = -1; private static final int NOTIFY_ID = 1; private static final int TRANSPROXY_NOTIFY_ID = 2; @@ -106,6 +111,12 @@ public class TorService extends Service implements TorServiceConstants, TorConst private boolean mEnableTransparentProxy = false; private boolean mTransProxyAll = false; private boolean mTransProxyTethering = false; + + + private ArrayList<String> callbackBuffer = new ArrayList<String>(); + private boolean inCallbackStatus = false; + private boolean inCallback = false; + public void logMessage(String msg) { @@ -136,9 +147,9 @@ public class TorService extends Service implements TorServiceConstants, TorConst try { - int procId = initControlConnection(1); + mLastProcessId = initControlConnection(1); - if (procId != -1) + if (mLastProcessId != -1) { sendCallbackLogMessage (getString(R.string.found_existing_tor_process)); @@ -284,34 +295,10 @@ public class TorService extends Service implements TorServiceConstants, TorConst try { - initBinaries(); - - IntentFilter mNetworkStateFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); - registerReceiver(mNetworkStateReceiver , mNetworkStateFilter); - - mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - - if (intent != null && intent.getAction()!=null && intent.getAction().equals("onboot")) - { - - boolean startOnBoot = TorServiceUtils.getSharedPrefs(getApplicationContext()).getBoolean("pref_start_boot",false); - - if (startOnBoot) - { - setTorProfile(PROFILE_ON); - } - } - else - { - findExistingProc(); - - } - - - // We want this service to continue running until it is explicitly - // stopped, so return sticky. - return START_NOT_STICKY; + new startTorOperation().execute(intent); + + return START_STICKY; } catch (Exception e) @@ -322,6 +309,50 @@ public class TorService extends Service implements TorServiceConstants, TorConst } + private class startTorOperation extends AsyncTask<Intent, Void, Boolean> { + @Override + protected Boolean doInBackground(Intent... params) { + + try + { + Intent intent = params[0]; + + initBinaries(); + + + IntentFilter mNetworkStateFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); + registerReceiver(mNetworkStateReceiver , mNetworkStateFilter); + + mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + + if (intent != null && intent.getAction()!=null && intent.getAction().equals("onboot")) + { + + boolean startOnBoot = TorServiceUtils.getSharedPrefs(getApplicationContext()).getBoolean("pref_start_boot",false); + + if (startOnBoot) + { + setTorProfile(PROFILE_ON); + } + } + else + { + findExistingProc(); + + } + } + catch (Exception e) + { + Log.e(TAG,"error onBind",e); + } + + + return true; + } + + } + + @@ -414,9 +445,12 @@ public class TorService extends Service implements TorServiceConstants, TorConst private void killTorProcess () throws Exception { - + + stopTorMinder(); + if (conn != null) { + logNotice("Using control port to shutdown Tor"); @@ -436,6 +470,7 @@ public class TorService extends Service implements TorServiceConstants, TorConst killProcess(filePolipo); killProcess(fileObfsclient); + } private void killProcess (File fileProcBin) throws IOException @@ -616,6 +651,9 @@ public class TorService extends Service implements TorServiceConstants, TorConst int code = 0; // Default state is "okay" + //clear rules first + mTransProxy.clearTransparentProxyingAll(this); + if(proxyAll) { showToolbarNotification(getString(R.string.setting_up_full_transparent_proxying_), TRANSPROXY_NOTIFY_ID, R.drawable.ic_stat_tor, false); @@ -685,8 +723,6 @@ public class TorService extends Service implements TorServiceConstants, TorConst { torrcPath = new File(appBinHome, TORRC_TETHER_KEY).getAbsolutePath(); } - - int procId = -1; int torRetryWaitTimeMS = 1000; @@ -700,9 +736,9 @@ public class TorService extends Service implements TorServiceConstants, TorConst Thread.sleep(torRetryWaitTimeMS); //now try to connect - procId = initControlConnection (3); + mLastProcessId = initControlConnection (3); - if (procId == -1) + if (mLastProcessId == -1) { logNotice(getString(R.string.couldn_t_start_tor_process_) + "; exit=" + cmdTor.getExitCode() + ": " + cmdTor.getOutput()); sendCallbackStatusMessage(getString(R.string.couldn_t_start_tor_process_)); @@ -712,12 +748,14 @@ public class TorService extends Service implements TorServiceConstants, TorConst else { - logNotice("Tor started; process id=" + procId); + logNotice("Tor started; process id=" + mLastProcessId); processSettingsImpl(); } shell.close(); + + startTorMinder (); } private void runPolipoShellCmd () throws Exception @@ -793,9 +831,11 @@ public class TorService extends Service implements TorServiceConstants, TorConst logNotice( "Connecting to control port: " + TOR_CONTROL_PORT); torConnSocket = new Socket(IP_LOCALHOST, TOR_CONTROL_PORT); + torConnSocket.setSoTimeout(CONTROL_SOCKET_TIMEOUT); + conn = TorControlConnection.getConnection(torConnSocket); - - logNotice( "SUCCESS connected to control port"); + + logNotice( "SUCCESS connected to Tor control port"); File fileCookie = new File(appCacheHome, TOR_CONTROL_COOKIE); @@ -812,9 +852,7 @@ public class TorService extends Service implements TorServiceConstants, TorConst sendCallbackStatusMessage(getString(R.string.tor_process_starting) + ' ' + getString(R.string.tor_process_complete)); addEventHandler(); - - - + String torProcId = conn.getInfo("process/pid"); return Integer.parseInt(torProcId); @@ -989,22 +1027,7 @@ public class TorService extends Service implements TorServiceConstants, TorConst return true; } - @Override - protected void onPostExecute(Boolean result) { - } - - @Override - protected void onPreExecute() { - } - - @Override - protected void onProgressUpdate(Void... values) { - } } - - - - public void message(String severity, String msg) { @@ -1214,34 +1237,32 @@ public class TorService extends Service implements TorServiceConstants, TorConst public IBinder onBind(Intent intent) { - Thread thread = new Thread () - { - - public void run () - { - try - { - initBinaries(); - findExistingProc (); - } - catch (Exception e) - { - Log.e(TAG,"error onBind",e); - } - } - }; - thread.start(); + new initTorOperation().execute(true); return mBinder; - /** - if (ITorService.class.getName().equals(intent.getAction())) { - return mBinder; + } + + private class initTorOperation extends AsyncTask<Boolean, Void, Boolean> { + @Override + protected Boolean doInBackground(Boolean... params) { + + try + { + initBinaries(); + findExistingProc (); + } + catch (Exception e) + { + Log.e(TAG,"error onBind",e); + } + + + return true; } - else - return null; - */ + } + /** * This is a list of callbacks that have been registered with the * service. Note that this is package scoped (instead of private) so @@ -1445,10 +1466,6 @@ public class TorService extends Service implements TorServiceConstants, TorConst }; - private ArrayList<String> callbackBuffer = new ArrayList<String>(); - private boolean inCallbackStatus = false; - private boolean inCallback = false; - private synchronized void sendCallbackStatusMessage (String newStatus) { @@ -1484,7 +1501,6 @@ public class TorService extends Service implements TorServiceConstants, TorConst if (mCallbacks == null) return; - // Broadcast to all clients the new value. final int N = mCallbacks.beginBroadcast(); @@ -1508,7 +1524,7 @@ public class TorService extends Service implements TorServiceConstants, TorConst } - private void sendCallbackLogMessage (String logMessage) + private synchronized void sendCallbackLogMessage (String logMessage) { if (mCallbacks == null) @@ -1597,6 +1613,9 @@ public class TorService extends Service implements TorServiceConstants, TorConst logNotice(context.getString(R.string.network_connectivity_is_good_waking_tor_up_)); showToolbarNotification(getString(R.string.status_activated),NOTIFY_ID,R.drawable.ic_stat_tor,prefPersistNotifications); + if (mHasRoot && mEnableTransparentProxy) + enableTransparentProxy(mTransProxyAll, mTransProxyTethering); + } } @@ -1889,7 +1908,141 @@ public class TorService extends Service implements TorServiceConstants, TorConst return file.getAbsolutePath(); } + + @SuppressLint("NewApi") + @Override + public void onTrimMemory(int level) { + super.onTrimMemory(level); + + switch (level) + { + + case TRIM_MEMORY_BACKGROUND: + logNotice("trim memory requested: app in the background"); + return; + + /** + public static final int TRIM_MEMORY_BACKGROUND + Added in API level 14 + Level for onTrimMemory(int): the process has gone on to the LRU list. This is a good opportunity to clean up resources that can efficiently and quickly be re-built if the user returns to the app. + Constant Value: 40 (0x00000028) + */ + + case TRIM_MEMORY_COMPLETE: + + logNotice("trim memory requested: cleanup all memory"); + return; + /** + public static final int TRIM_MEMORY_COMPLETE + Added in API level 14 + Level for onTrimMemory(int): the process is nearing the end of the background LRU list, and if more memory isn't found soon it will be killed. + Constant Value: 80 (0x00000050) + */ + case TRIM_MEMORY_MODERATE: + + logNotice("trim memory requested: clean up some memory"); + return; + + /** + public static final int TRIM_MEMORY_MODERATE + Added in API level 14 + Level for onTrimMemory(int): the process is around the middle of the background LRU list; freeing memory can help the system keep other processes running later in the list for better overall performance. + Constant Value: 60 (0x0000003c) + */ + + case TRIM_MEMORY_RUNNING_CRITICAL: + + logNotice("trim memory requested: memory on device is very low and critical"); + return; + /** + public static final int TRIM_MEMORY_RUNNING_CRITICAL + Added in API level 16 + Level for onTrimMemory(int): the process is not an expendable background process, but the device is running extremely low on memory and is about to not be able to keep any background processes running. Your running process should free up as many non-critical resources as it can to allow that memory to be used elsewhere. The next thing that will happen after this is onLowMemory() called to report that nothing at all can be kept in the background, a situation that can start to notably impact the user. + Constant Value: 15 (0x0000000f) + */ + + case TRIM_MEMORY_RUNNING_LOW: + + logNotice("trim memory requested: memory on device is running low"); + return; + /** + public static final int TRIM_MEMORY_RUNNING_LOW + Added in API level 16 + Level for onTrimMemory(int): the process is not an expendable background process, but the device is running low on memory. Your running process should free up unneeded resources to allow that memory to be used elsewhere. + Constant Value: 10 (0x0000000a) + */ + case TRIM_MEMORY_RUNNING_MODERATE: + + logNotice("trim memory requested: memory on device is moderate"); + return; + /** + public static final int TRIM_MEMORY_RUNNING_MODERATE + Added in API level 16 + Level for onTrimMemory(int): the process is not an expendable background process, but the device is running moderately low on memory. Your running process may want to release some unneeded resources for use elsewhere. + Constant Value: 5 (0x00000005) + */ + case TRIM_MEMORY_UI_HIDDEN: + + logNotice("trim memory requested: app is not showing UI anymore"); + return; + + /** + public static final int TRIM_MEMORY_UI_HIDDEN + Level for onTrimMemory(int): the process had been showing a user interface, and is no longer doing so. Large allocations with the UI should be released at this point to allow memory to be better managed. + Constant Value: 20 (0x00000014) + */ + } + + } + private Timer mTorMinder; + + private void startTorMinder () + { + mTorMinder = new Timer(true); + mTorMinder.scheduleAtFixedRate( + new TimerTask() { + public void run() { + + if (currentStatus == STATUS_OFF) + { + mTorMinder.cancel(); + } + else + { + + try { + int foundPrcId = TorServiceUtils.findProcessId(fileTor.getAbsolutePath()); + + if (foundPrcId != -1) + { + mLastProcessId = foundPrcId; + + logNotice("Refreshed Tor process id: " + mLastProcessId); + + } + else + { + logNotice("restarting Tor after it has been killed"); + killTorProcess(); + initTor(); + } + + } catch (Exception e1) { + logException("Error in Tor heartbeat checker",e1); + } + } + + + } + }, 0, 30 * 1000); //every 30 seconds + } + + private void stopTorMinder () + { + if (mTorMinder != null) + mTorMinder.cancel(); + } } _______________________________________________ tor-commits mailing list tor-commits@lists.torproject.org https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits