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
This commit is contained in:
Hans-Christoph Steiner 2015-06-04 11:59:22 -04:00
parent 81cf67f955
commit 2f1ad74538
2 changed files with 103 additions and 63 deletions

View File

@ -222,6 +222,7 @@
<string name="hidden_service_on">hidden service on:</string> <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_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_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_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> <string name="pref_use_sys_iptables_summary">use the built-in iptables binary instead of the one bundled with Orbot</string>

View File

@ -429,34 +429,42 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
clearNotifications (); clearNotifications ();
super.onDestroy(); super.onDestroy();
} }
private void stopTor () private void stopTor ()
{ {
try try
{ {
Log.d(TAG,"Tor is stopping NOW"); Log.d(TAG,"Tor is stopping NOW");
shutdownTorProcess (); shutdownTorProcess ();
//stop the foreground priority and make sure to remove the persistant notification //stop the foreground priority and make sure to remove the persistant notification
stopForeground(true); stopForeground(true);
mCurrentStatus = STATUS_OFF; mCurrentStatus = STATUS_OFF;
sendCallbackStatus(mCurrentStatus); sendCallbackStatus(mCurrentStatus);
if (mHasRoot && mEnableTransparentProxy) if (mHasRoot && mEnableTransparentProxy)
{ {
Shell shellRoot = Shell.startRootShell(); Shell shellRoot = Shell.startRootShell();
disableTransparentProxy(shellRoot); disableTransparentProxy(shellRoot);
shellRoot.close(); shellRoot.close();
} }
clearNotifications(); clearNotifications();
sendCallbackLogMessage(getString(R.string.status_disabled)); 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) catch (Exception e)
{ {
Log.d(TAG, "An error occured stopping Tor",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 () private String getHiddenServiceHostname ()
{ {
SharedPreferences prefs = TorServiceUtils.getSharedPrefs(getApplicationContext()); SharedPreferences prefs = TorServiceUtils.getSharedPrefs(getApplicationContext());
boolean enableHiddenServices = prefs.getBoolean("pref_hs_enable", false); boolean enableHiddenServices = prefs.getBoolean("pref_hs_enable", false);
StringBuffer result = new StringBuffer(); StringBuffer result = new StringBuffer();
if (enableHiddenServices) if (enableHiddenServices)
{ {
String hsPorts = prefs.getString("pref_hs_ports",""); String hsPorts = prefs.getString("pref_hs_ports","");
StringTokenizer st = new StringTokenizer (hsPorts,","); StringTokenizer st = new StringTokenizer (hsPorts,",");
String hsPortConfig = null; String hsPortConfig = null;
while (st.hasMoreTokens()) while (st.hasMoreTokens())
{ {
int hsPort = Integer.parseInt(st.nextToken().split(" ")[0]);; int hsPort = Integer.parseInt(st.nextToken().split(" ")[0]);;
File fileDir = new File(appCacheHome, "hs" + hsPort); File fileDir = new File(appCacheHome, "hs" + hsPort);
File file = new File(fileDir, "hostname"); File file = new File(fileDir, "hostname");
if (file.exists()) if (file.exists())
{ {
try { try {
String onionHostname = Utils.readString(new FileInputStream(file)).trim(); String onionHostname = Utils.readString(new FileInputStream(file)).trim();
if (result.length() > 0) if (result.length() > 0)
result.append(","); result.append(",");
result.append(onionHostname); result.append(onionHostname);
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
logException("unable to read onion hostname file",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); 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); showToolbarNotification(getString(R.string.unable_to_read_hidden_service_name), HS_NOTIFY_ID, R.drawable.ic_stat_notifyerr);
return null; return null;
} }
} }
if (result.length() > 0) if (result.length() > 0)
{ {
String onionHostname = result.toString(); String onionHostname = result.toString();
showToolbarNotification(getString(R.string.hidden_service_on) + ' ' + onionHostname, HS_NOTIFY_ID, R.drawable.ic_stat_tor); showToolbarNotification(getString(R.string.hidden_service_on) + ' ' + onionHostname, HS_NOTIFY_ID, R.drawable.ic_stat_tor);
Editor pEdit = prefs.edit(); Editor pEdit = prefs.edit();
pEdit.putString("pref_hs_hostname",onionHostname); pEdit.putString("pref_hs_hostname",onionHostname);
pEdit.commit(); pEdit.commit();
return onionHostname; return onionHostname;
} }
} }
return null; return null;
} }
private void shutdownTorProcess () throws Exception private void shutdownTorProcess () throws Exception
{ {
@ -542,47 +550,69 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
{ {
logNotice("Using control port to shutdown Tor"); logNotice("Using control port to shutdown Tor");
try { try {
logNotice("sending HALT signal to Tor process"); logNotice("sending HALT signal to Tor process");
conn.shutdownTor("HALT"); conn.shutdownTor("HALT");
} catch (Exception e) { } catch (Exception e) {
Log.d(TAG,"error shutting down Tor via connection",e); Log.d(TAG,"error shutting down Tor via connection",e);
} }
conn = null; conn = null;
} }
killProcess(fileTor); killProcess(fileTor);
killProcess(filePolipo); killProcess(filePolipo);
killProcess(fileObfsclient); killProcess(fileObfsclient);
killProcess(fileMeekclient); killProcess(fileMeekclient);
} }
private void killProcess (File fileProcBin) throws IOException public class CannotKillException extends IllegalStateException {
{ private static final long serialVersionUID = -286877277562592501L;
int procId = -1;
Shell shell = Shell.startShell(); public CannotKillException(File f) {
super("Cannot kill " + f.getAbsolutePath());
while ((procId = TorServiceUtils.findProcessId(fileProcBin.getCanonicalPath())) != -1)
{
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);
} }
shell.close();
} }
private void killProcess(File fileProcBin) throws IOException {
int procId = -1;
int killAttempts = 0;
while ((procId = TorServiceUtils.findProcessId(fileProcBin.getCanonicalPath())) != -1) {
killAttempts++;
logNotice("Found " + fileProcBin.getName() + " PID=" + procId + " - killing now...");
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);
}
}
private void logNotice (String msg) private void logNotice (String msg)
{ {
if (msg != null && msg.trim().length() > 0) if (msg != null && msg.trim().length() > 0)
@ -1405,21 +1435,30 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
if (mCurrentStatus == STATUS_OFF) if (mCurrentStatus == STATUS_OFF)
{ {
sendCallbackLogMessage (getString(R.string.status_starting_up)); sendCallbackLogMessage (getString(R.string.status_starting_up));
try try
{ {
boolean found = findExistingProc (); boolean found = findExistingProc ();
if (!found) if (!found)
{ {
killProcess(fileTor); killProcess(fileTor);
killProcess(filePolipo); killProcess(filePolipo);
startTor(); 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) catch (Exception e)
{ {