[Commotion-dev] [PATCH] Refactor MeshService to support stopping olsrd.

Hans-Christoph Steiner hans at guardianproject.info
Wed Jul 4 20:10:38 UTC 2012


Ok, the attached patch worked.  I got it integrated in and its working for me.  Yay, we can finally stop olsrd from the GUI!

One thing I think we could improve is running a single root shell which we feed commands too.  That means SuperUser would only ask once for root access, not for each command.  That makes it much easier to use MeshTether without having to grant it automatic root access.

One other detail: we should probably check if an olsrd is left running in onCreate() or something.  If MeshTether crashes (shudder the thought) it'll leave olsrd running.  Or even better, find a way to always kill olsrd when MeshTether crashes.

.hc

On Jul 2, 2012, at 4:21 PM, Will Hawkins wrote:

> Refactor MeshService.java so that we can properly
> stop olsrd when the user presses Stop. This consolidates
> all the process monitoring into a MeshTetherProcess
> app that handles start, stop and i/o redirection.
> ---
> assets/do_stop_olsrd                               |    8 +
> assets/run                                         |    2 +
> assets/stop_olsrd                                  |    8 +
> .../commotionwireless/meshtether/MeshService.java  |  195 ++++++++++++++------
> .../commotionwireless/meshtether/NativeHelper.java |    6 +
> 5 files changed, 160 insertions(+), 59 deletions(-)
> create mode 100644 assets/do_stop_olsrd
> create mode 100644 assets/stop_olsrd
> 
> diff --git a/assets/do_stop_olsrd b/assets/do_stop_olsrd
> new file mode 100644
> index 0000000..36b060f
> --- /dev/null
> +++ b/assets/do_stop_olsrd
> @@ -0,0 +1,8 @@
> +#!/system/bin/sh
> +# main runner (process manager) for barnacle, root required
> +
> +: ${brncl_path:=.}
> +
> +export brncl_path
> +
> +kill -15 `cat $brncl_path/../app_log/olsrd.pid`
> diff --git a/assets/run b/assets/run
> index 3dab78a..da4c752 100644
> --- a/assets/run
> +++ b/assets/run
> @@ -44,8 +44,10 @@ sleep 1
> 
> # run olsrd
> (./olsrd -f olsrd.conf -i $brncl_if_lan > $brncl_path/../app_log/olsrd.log 2>&1) &
> +echo `ps | grep olsrd | awk '{print $2;}'` > $brncl_path/../app_log/olsrd.pid
> echo "OLSR on http://${brncl_adhoc_ip}:8080"
> 
> +
> # the association loop
> ./wifi assoc
> 
> diff --git a/assets/stop_olsrd b/assets/stop_olsrd
> new file mode 100644
> index 0000000..7c466eb
> --- /dev/null
> +++ b/assets/stop_olsrd
> @@ -0,0 +1,8 @@
> +#!/system/bin/sh
> +# main runner (process manager) for barnacle, root required
> +
> +: ${brncl_path:=.}
> +
> +export brncl_path
> +
> +su -c ${brncl_path}/do_stop_olsrd
> diff --git a/src/net/commotionwireless/meshtether/MeshService.java b/src/net/commotionwireless/meshtether/MeshService.java
> index 3012a14..85efbb7 100644
> --- a/src/net/commotionwireless/meshtether/MeshService.java
> +++ b/src/net/commotionwireless/meshtether/MeshService.java
> @@ -18,6 +18,7 @@
> 
> package net.commotionwireless.meshtether;
> 
> +import java.io.File;
> import java.io.IOException;
> import java.lang.reflect.InvocationTargetException;
> import java.lang.reflect.Method;
> @@ -25,7 +26,6 @@ import java.util.ArrayList;
> import java.util.Map;
> 
> import net.commotionwireless.meshtether.Util.MACAddress;
> -import net.commotionwireless.meshtether.R;
> import android.app.Notification;
> import android.content.BroadcastReceiver;
> import android.content.Context;
> @@ -60,6 +60,7 @@ public class MeshService extends android.app.Service {
>     final static int MSG_ASSOC      = 7;
>     final static int MSG_STATS      = 8;
>     final static int MSG_SET_DNS1_OUTPUT = 9;
> +    final static int MSG_STOP_OLSRD_OUTPUT = 10;
>     // app states
>     public final static int STATE_STOPPED  = 0;
>     public final static int STATE_STARTING = 1;
> @@ -67,10 +68,8 @@ public class MeshService extends android.app.Service {
> 
>     // private state
>     private int state = STATE_STOPPED;
> -    private Process process = null; // native process for ad-hoc config
> -    private Process DnsProcess = null;
> -    // output monitoring threads
> -    private Thread[] threads = new Thread[3];
> +    private MeshTetherProcess WifiProcess = null;
> +
>     private PowerManager.WakeLock wakeLock;
>     private BroadcastReceiver connectivityReceiver = new BroadcastReceiver() {
>         @Override
> @@ -206,7 +205,7 @@ public class MeshService extends android.app.Service {
>             break;
>         case MSG_ERROR:
>             if (state == STATE_STOPPED) return;
> -            if (process == null) return; // don't kill it again...
> +            if (WifiProcess == null) return; // don't kill it again...
>             if (msg.obj != null) {
>                 String line = (String)msg.obj;
>                 log(true, line); // just dump it and ignore it
> @@ -257,7 +256,7 @@ public class MeshService extends android.app.Service {
>         }
>         case MSG_OUTPUT:
>             if (state == STATE_STOPPED) return;
> -            if (process == null) return; // cut the gibberish
> +            if (WifiProcess == null) return; // cut the gibberish
>             String line = (String)msg.obj;
>             if (line == null) {
>                 // ignore it, wait for MSG_ERROR(null)
> @@ -303,10 +302,10 @@ public class MeshService extends android.app.Service {
>         case MSG_NETSCHANGE:
>             int wifiState = wifiManager.getWifiState();
>             String preferredDnsValue = getPrefValue(getString(R.string.adhoc_dns_server));
> -            Log.e(TAG, String.format("NETSCHANGE: %d %d %s", wifiState, state, process == null ? "null" : "proc"));
> +            Log.e(TAG, String.format("NETSCHANGE: %d %d %s", wifiState, state, WifiProcess == null ? "null" : "proc"));
>             if (wifiState == WifiManager.WIFI_STATE_DISABLED) {
>                 // wifi is good (or lost), we can start now...
> -            	if ((state == STATE_STARTING) && (process == null)) {
> +            	if ((state == STATE_STARTING) && (WifiProcess == null)) {
>             		if (app.findIfWan()) {
>             			// TODO if WAN found with checkUplink(), then setup Hna4 routing
>             			log(false, "Found active WAN interface");
> @@ -318,12 +317,9 @@ public class MeshService extends android.app.Service {
>                     }
>             		mOldNetDns1Value = System.getProperty("net.dns1");
>             		try {
> -	            		DnsProcess = Runtime.getRuntime().exec(NativeHelper.SET_NET_DNS1 + " " + preferredDnsValue,
> +            			MeshTetherProcess DnsProcess = new MeshTetherProcess(NativeHelper.SET_NET_DNS1 + " " + preferredDnsValue,
> 	                    		null, NativeHelper.app_bin);
> -	                    threads[2] = new Thread(new OutputMonitor(MSG_SET_DNS1_OUTPUT, DnsProcess.getInputStream()));
> -	                    threads[2].start();
> -	                    DnsProcess.waitFor();
> -	                    DnsProcess.destroy();
> +            			DnsProcess.runUntilExit(mHandler, MSG_SET_DNS1_OUTPUT, MSG_SET_DNS1_OUTPUT);
> 					} catch (IOException e) {
>                         log(false, "Error occurred while setting DNS server: " + e.getMessage());
> 						e.printStackTrace();
> @@ -363,13 +359,11 @@ public class MeshService extends android.app.Service {
>             stopProcess();
>             if (mOldNetDns1Value != null)
>             {
> -            	try {
> -            		DnsProcess = Runtime.getRuntime().exec(NativeHelper.SET_NET_DNS1 + " " + mOldNetDns1Value, 
> -                    		null, NativeHelper.app_bin);
> -                    threads[2] = new Thread(new OutputMonitor(MSG_SET_DNS1_OUTPUT, DnsProcess.getInputStream()));
> -                    threads[2].start();
> -                    DnsProcess.waitFor();
> -                    DnsProcess.destroy();
> +            	try {            		
> +            		MeshTetherProcess DnsProcess = new MeshTetherProcess(NativeHelper.SET_NET_DNS1 + " " + mOldNetDns1Value, 
> +            				null, NativeHelper.app_bin);
> +            		DnsProcess.runUntilExit(mHandler, MSG_SET_DNS1_OUTPUT, MSG_SET_DNS1_OUTPUT);
> +
> 				} catch (IOException e) {
>                     log(false, "Error occurred while resetting DNS server: " + e.getMessage());
> 					e.printStackTrace();
> @@ -434,6 +428,82 @@ public class MeshService extends android.app.Service {
>             }
>         }
>     }
> +    
> +    private class MeshTetherProcess {
> +    	private final static int INPUT_THREAD = 0;
> +    	private final static int ERROR_THREAD = 1;
> +    	
> +    	private boolean mRunning;
> +    	private Thread mIoThreads[] = new Thread[2];
> +    	private Process mProcess = null;
> +    	private String mProg;
> +    	private String[] mEnvp;
> +    	private File mDirectory;
> +    	private int mExitValue;
> +    	
> +    	public MeshTetherProcess(String prog, String[] envp, File directory) {
> +    		mProg = prog;
> +    		mEnvp = envp;
> +    		mDirectory = directory;
> +    		mRunning = false;
> +    		mExitValue = 0;
> +    	}
> +    	
> +    	public void stop() throws IOException, InterruptedException {
> +    		if (mProcess != null) {
> +    			mProcess.getOutputStream().close();
> +    			mProcess.getErrorStream().close();
> +    			
> +    			mIoThreads[INPUT_THREAD].interrupt();
> +    			mIoThreads[ERROR_THREAD].interrupt();
> +    			
> +    			mIoThreads[INPUT_THREAD] = null;
> +    			mIoThreads[ERROR_THREAD] = null;
> +
> +    			mProcess.destroy();
> +    			mProcess.waitFor();
> +    			mExitValue = mProcess.exitValue();
> +    			mProcess = null;
> +    			mRunning = false;
> +    		}
> +    	}
> +    	
> +    	public void run(Handler handler, int outputTag, int errorTag) throws IOException {
> +    		mProcess = Runtime.getRuntime().exec(mProg, mEnvp, mDirectory);
> +    		mIoThreads[INPUT_THREAD] = new Thread(new OutputMonitor(outputTag, mProcess.getInputStream()));
> +    		mIoThreads[ERROR_THREAD] = new Thread(new OutputMonitor(errorTag, mProcess.getErrorStream()));
> +    		mIoThreads[INPUT_THREAD].start();
> +    		mIoThreads[ERROR_THREAD].start();
> +    		mRunning = true;
> +    	}
> +    	
> +    	public void tell(byte[] msg) throws IOException {
> +    		if (mRunning)
> +    			mProcess.getOutputStream().write(msg);
> +    	}
> +    	public void runUntilExit(Handler handler, int outputTag, int errorTag) throws IOException, InterruptedException {
> +    		run(handler,outputTag,errorTag);
> +    		mProcess.waitFor();
> +    		
> +			mIoThreads[INPUT_THREAD].interrupt();
> +			mIoThreads[ERROR_THREAD].interrupt();
> +			
> +			mIoThreads[INPUT_THREAD] = null;
> +			mIoThreads[ERROR_THREAD] = null;
> +			
> +    		mProcess.destroy();
> +			mExitValue = mProcess.exitValue();
> +
> +    		mProcess = null;
> +    		mRunning = false;
> +    	}
> +    	public int exitValue() {
> +    		if (!mRunning)
> +    			return mExitValue;
> +    		else
> +    			return 0;
> +    	}
> +    }
> 
>     private void clientAdded(ClientData cd) {
> 
> @@ -551,12 +621,8 @@ public class MeshService extends android.app.Service {
>     	// calling 'su -c' from Java doesn't work so we use a helper script
>     	String cmd = NativeHelper.SU_C;
>         try {
> -            process = Runtime.getRuntime().exec(cmd,
> -            		buildEnvFromPrefs(), NativeHelper.app_bin);
> -            threads[0] = new Thread(new OutputMonitor(MSG_OUTPUT, process.getInputStream()));
> -            threads[1] = new Thread(new OutputMonitor(MSG_ERROR, process.getErrorStream()));
> -            threads[0].start();
> -            threads[1].start();
> +        	WifiProcess = new MeshTetherProcess(cmd, buildEnvFromPrefs(), NativeHelper.app_bin);
> +        	WifiProcess.run(mHandler, MSG_OUTPUT, MSG_ERROR);
>         } catch (Exception e) {
>             log(true, String.format(getString(R.string.execerr), cmd));
>             Log.e(TAG, "start failed " + e.toString());
> @@ -564,47 +630,58 @@ public class MeshService extends android.app.Service {
>         }
>         return true;
>     }
> +    
> +    private void stopProcess() {
> +    	/*
> +    	 * TODO: UN copy and paste!!
> +    	 */
> +    	if (state != STATE_STOPPED) {
> +    		try {	
> +    			MeshTetherProcess StopOlsrProcess = new MeshTetherProcess(NativeHelper.STOP_OLSRD,
> +    					null, NativeHelper.app_bin);
> +    			StopOlsrProcess.runUntilExit(mHandler, MSG_STOP_OLSRD_OUTPUT, MSG_STOP_OLSRD_OUTPUT);
> +
> +    		} catch (IOException e) {
> +    			log(false, "Error occurred while stopping Olsrd: " + e.getMessage());
> +    			e.printStackTrace();
> +    		} catch (InterruptedException e) {
> +    			log(false, "Error occurred while stopping Olsrd: " + e.getMessage());
> +    			e.printStackTrace();
> +    		}
> +
> +    		if (WifiProcess != null) {
> +    			// first, just close the stream
> +    			if (state != STATE_STOPPED) {
> +    				try {
> +    					WifiProcess.stop();
> +    				} catch (Exception e) {
> +    					Log.w(TAG, "Exception while closing process");
> +    				}
> +    			}
> +
> +    			try {
> +    				int exit_status = WifiProcess.exitValue();
> +    				Log.i(TAG, "Wifi Process exited with status: " + exit_status);
> +    			} catch (IllegalThreadStateException e) {
> +    				// this is not good
> +    				log(true, getString(R.string.dirtystop));
> +    			}
> +    			WifiProcess = null;
> +    		}
> +    	}
> +    }
> +
> 
>     private boolean tellProcess(String msg) {
> -        if (process != null) {
> +        if (WifiProcess != null) {
>             try {
> -                process.getOutputStream().write((msg+"\n").getBytes());
> +                WifiProcess.tell((msg+"\n").getBytes());
>                 return true;
>             } catch (Exception e) {} // just ignore it
>         }
>         return false;
>     }
> 
> -    private void stopProcess() {
> -        if (process != null) {
> -            // first, just close the stream
> -            if (state != STATE_STOPPED) {
> -                try {
> -                    process.getOutputStream().close();
> -                } catch (Exception e) {
> -                    Log.w(TAG, "Exception while closing process");
> -                }
> -            }
> -            try {
> -                process.waitFor(); // blocking!
> -            } catch (InterruptedException e) {
> -                Log.e(TAG, "");
> -            }
> -
> -            try {
> -                int exit_status = process.exitValue();
> -                Log.i(TAG, "Process exited with status: " + exit_status);
> -            } catch (IllegalThreadStateException e) {
> -                // this is not good
> -                log(true, getString(R.string.dirtystop));
> -            }
> -            process.destroy();
> -            process = null;
> -            threads[0].interrupt();
> -            threads[1].interrupt();
> -        }
> -    }
> -
>     @Override
>     public IBinder onBind(Intent intent) {
>         return null;
> diff --git a/src/net/commotionwireless/meshtether/NativeHelper.java b/src/net/commotionwireless/meshtether/NativeHelper.java
> index e72597b..bedc6d6 100644
> --- a/src/net/commotionwireless/meshtether/NativeHelper.java
> +++ b/src/net/commotionwireless/meshtether/NativeHelper.java
> @@ -27,6 +27,8 @@ public class NativeHelper {
> 
>     static String SU_C;
>     static String RUN;
> +    static String STOP_OLSRD;
> +    static String DO_STOP_OLSRD;
>     static String OLSRD;
>     static String WIFI;
>     static String SET_NET_DNS1;
> @@ -38,6 +40,8 @@ public class NativeHelper {
> 		publicFiles = new File(Environment.getExternalStorageDirectory(),
> 				"Android/data/" + context.getPackageName() + "/files/");
> 		SU_C = new File(app_bin, "su_c").getAbsolutePath();
> +		STOP_OLSRD = new File(app_bin, "stop_olsrd").getAbsolutePath();
> +		DO_STOP_OLSRD = new File(app_bin, "do_stop_olsrd").getAbsolutePath();
> 		RUN = new File(app_bin, "run").getAbsolutePath();
> 		OLSRD = new File(app_bin, "olsrd").getAbsolutePath();
> 		WIFI = new File(app_bin, "wifi").getAbsolutePath();
> @@ -86,6 +90,8 @@ public class NativeHelper {
> 		}
> 		chmod("0750", new File(SU_C));
> 		chmod("0750", new File(RUN));
> +		chmod("0750", new File(STOP_OLSRD));
> +		chmod("0750", new File(DO_STOP_OLSRD));
> 		chmod("0750", new File(OLSRD));
> 		chmod("0750", new File(WIFI));
> 		chmod("0750", new File(SET_NET_DNS1));
> -- 
> 1.7.9.5
> 



More information about the Commotion-dev mailing list