commit 2f1ad745386d599c4ad042bf0aed1fcf2a52b655 Author: Hans-Christoph Steiner hans@eds.org Date: Thu Jun 4 11:59:22 2015 -0400
put up error notification if Orbot cannot kill a process
There are a couple of different times when Orbot will be unable to kill the running processes. One example is when Orbot is running, then uninstalled, then installed again.
closes #5254 https://dev.guardianproject.info/issues/5254 --- res/values/strings.xml | 1 + src/org/torproject/android/service/TorService.java | 161 ++++++++++++-------- 2 files changed, 101 insertions(+), 61 deletions(-)
diff --git a/res/values/strings.xml b/res/values/strings.xml index 87f205c..0f98f5e 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -222,6 +222,7 @@ <string name="hidden_service_on">hidden service on:</string> <string name="unable_to_read_hidden_service_name">unable to read hidden service name</string> <string name="unable_to_start_tor">Unable to start Tor:</string> + <string name="unable_to_reset_tor">Reboot your device, unable to reset Tor!</string> <string name="pref_use_sys_iptables_title">Use Default Iptables</string> <string name="pref_use_sys_iptables_summary">use the built-in iptables binary instead of the one bundled with Orbot</string>
diff --git a/src/org/torproject/android/service/TorService.java b/src/org/torproject/android/service/TorService.java index 50792b8..195fe98 100644 --- a/src/org/torproject/android/service/TorService.java +++ b/src/org/torproject/android/service/TorService.java @@ -429,34 +429,42 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon clearNotifications (); super.onDestroy(); } - + private void stopTor () { - + try - { + { Log.d(TAG,"Tor is stopping NOW"); - + shutdownTorProcess (); - + //stop the foreground priority and make sure to remove the persistant notification stopForeground(true); - + mCurrentStatus = STATUS_OFF; sendCallbackStatus(mCurrentStatus); - + if (mHasRoot && mEnableTransparentProxy) { Shell shellRoot = Shell.startRootShell(); disableTransparentProxy(shellRoot); shellRoot.close(); } - + clearNotifications(); - + sendCallbackLogMessage(getString(R.string.status_disabled));
} + catch (CannotKillException e) + { + Log.d(TAG, "An error occured stopping Tor", e); + logNotice("An error occured stopping Tor: " + e.getMessage()); + sendCallbackLogMessage(getString(R.string.unable_to_reset_tor)); + showToolbarNotification(getString(R.string.unable_to_reset_tor), + ERROR_NOTIFY_ID, R.drawable.ic_stat_notifyerr); + } catch (Exception e) { Log.d(TAG, "An error occured stopping Tor",e); @@ -465,44 +473,44 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
} } - - + + private String getHiddenServiceHostname () {
SharedPreferences prefs = TorServiceUtils.getSharedPrefs(getApplicationContext()); - + boolean enableHiddenServices = prefs.getBoolean("pref_hs_enable", false); - + StringBuffer result = new StringBuffer(); - + if (enableHiddenServices) { String hsPorts = prefs.getString("pref_hs_ports",""); - + StringTokenizer st = new StringTokenizer (hsPorts,","); String hsPortConfig = null; - + while (st.hasMoreTokens()) - { - + { + int hsPort = Integer.parseInt(st.nextToken().split(" ")[0]);; - + File fileDir = new File(appCacheHome, "hs" + hsPort); File file = new File(fileDir, "hostname"); - - + + if (file.exists()) { try { String onionHostname = Utils.readString(new FileInputStream(file)).trim(); - + if (result.length() > 0) result.append(","); - + result.append(onionHostname); - - + + } catch (FileNotFoundException e) { logException("unable to read onion hostname file",e); showToolbarNotification(getString(R.string.unable_to_read_hidden_service_name), HS_NOTIFY_ID, R.drawable.ic_stat_notifyerr); @@ -513,28 +521,28 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon { showToolbarNotification(getString(R.string.unable_to_read_hidden_service_name), HS_NOTIFY_ID, R.drawable.ic_stat_notifyerr); return null; - + } } - + if (result.length() > 0) { String onionHostname = result.toString(); - + showToolbarNotification(getString(R.string.hidden_service_on) + ' ' + onionHostname, HS_NOTIFY_ID, R.drawable.ic_stat_tor); Editor pEdit = prefs.edit(); pEdit.putString("pref_hs_hostname",onionHostname); pEdit.commit(); - + return onionHostname; } - + } - + return null; } - - + + private void shutdownTorProcess () throws Exception {
@@ -542,47 +550,69 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon {
logNotice("Using control port to shutdown Tor"); - - + + try { logNotice("sending HALT signal to Tor process"); conn.shutdownTor("HALT"); - + } catch (Exception e) { Log.d(TAG,"error shutting down Tor via connection",e); } - + conn = null; } - + killProcess(fileTor); - + killProcess(filePolipo); killProcess(fileObfsclient); killProcess(fileMeekclient); - - } - - private void killProcess (File fileProcBin) throws IOException - { + + public class CannotKillException extends IllegalStateException { + private static final long serialVersionUID = -286877277562592501L; + + public CannotKillException(File f) { + super("Cannot kill " + f.getAbsolutePath()); + } + } + + private void killProcess(File fileProcBin) throws IOException { int procId = -1; - Shell shell = Shell.startShell(); - - while ((procId = TorServiceUtils.findProcessId(fileProcBin.getCanonicalPath())) != -1) - { - + int killAttempts = 0; + + while ((procId = TorServiceUtils.findProcessId(fileProcBin.getCanonicalPath())) != -1) { + killAttempts++; logNotice("Found " + fileProcBin.getName() + " PID=" + procId + " - killing now..."); - - SimpleCommand killCommand = new SimpleCommand("toolbox kill -9 " + procId); - shell.add(killCommand); - killCommand = new SimpleCommand("kill -9 " + procId); - shell.add(killCommand); + String pidString = String.valueOf(procId); + /* + * first try as the normal app user to be safe, then if that fails, + * try root since the process might be left over from + * uninstall/reinstall with different UID. + */ + Shell shell; + if (mHasRoot && killAttempts > 2) { + shell = Shell.startRootShell(); + Log.i(TAG, "using a root shell"); + } else { + shell = Shell.startShell(); + } + shell.add(new SimpleCommand("busybox killall " + fileProcBin.getName())); + shell.add(new SimpleCommand("toolbox kill -9 " + pidString)); + shell.add(new SimpleCommand("busybox kill -9 " + pidString)); + shell.add(new SimpleCommand("kill -9 " + pidString)); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // ignored + } + shell.close(); + if (killAttempts > 4) + throw new CannotKillException(fileProcBin); } - - shell.close(); } - + private void logNotice (String msg) { if (msg != null && msg.trim().length() > 0) @@ -1405,21 +1435,30 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon if (mCurrentStatus == STATUS_OFF) { sendCallbackLogMessage (getString(R.string.status_starting_up)); - - + + try {
boolean found = findExistingProc (); - + if (!found) { killProcess(fileTor); killProcess(filePolipo); - + startTor(); } } + catch (CannotKillException e) + { + logException(e.getMessage(), e); + mCurrentStatus = STATUS_OFF; + sendCallbackStatus(mCurrentStatus); + showToolbarNotification(getString(R.string.unable_to_reset_tor), + ERROR_NOTIFY_ID, R.drawable.ic_stat_notifyerr); + stopTor(); + } catch (Exception e) {
tor-commits@lists.torproject.org