Bug 934012 - Add execext command to sutagent; r=jmaher
authorGeoff Brown <gbrown@mozilla.com>
Tue, 05 Nov 2013 10:53:32 -0700
changeset 153634 58d7c1291d4c8b997df417dcb413e80d0be3d48e
parent 153633 cd1a07426d4c80c65fe44a7795740fd8786ef391
child 153635 8b89e662629832fcd4902760bcd9a96654c19a0e
child 153654 208198d2bbddfe9ae5896ee2ae912a1c6239e26c
push id25596
push userryanvm@gmail.com
push dateTue, 05 Nov 2013 20:28:59 +0000
treeherdermozilla-central@8b89e6626298 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmaher
bugs934012
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 934012 - Add execext command to sutagent; r=jmaher
build/mobile/sutagent/android/DoCommand.java
--- a/build/mobile/sutagent/android/DoCommand.java
+++ b/build/mobile/sutagent/android/DoCommand.java
@@ -102,25 +102,28 @@ public class DoCommand {
 
     String    currentDir = "/";
     String    sErrorPrefix = "##AGENT-WARNING## ";
     boolean bTraceOn = false;
 
     String ffxProvider = "org.mozilla.ffxcp";
     String fenProvider = "org.mozilla.fencp";
 
+    private static final int DEFAULT_STARTPRG_TIMEOUT_SECONDS = 300;
+
     private final String prgVersion = "SUTAgentAndroid Version 1.19";
 
     public enum Command
         {
         RUN ("run"),
         EXEC ("exec"),
         EXECSU ("execsu"),
         EXECCWD ("execcwd"),
         EXECCWDSU ("execcwdsu"),
+        EXECEXT ("execext"),
         ENVRUN ("envrun"),
         KILL ("kill"),
         PS ("ps"),
         DEVINFO ("info"),
         OS ("os"),
         ID ("id"),
         UPTIME ("uptime"),
         UPTIMEMILLIS ("uptimemillis"),
@@ -718,17 +721,17 @@ public class DoCommand {
                     {
                     String [] theArgs = new String [Argc - 1];
 
                     for (int lcv = 1; lcv < Argc; lcv++)
                         {
                         theArgs[lcv - 1] = Argv[lcv];
                         }
 
-                    strReturn = StartPrg2(theArgs, cmdOut, null, false);
+                    strReturn = StartPrg2(theArgs, cmdOut, null, false, DEFAULT_STARTPRG_TIMEOUT_SECONDS);
                     }
                 else
                     {
                     strReturn = sErrorPrefix + "Wrong number of arguments for " + Argv[0] + " command!";
                     }
                 break;
 
             case EXECSU:
@@ -736,17 +739,17 @@ public class DoCommand {
                     {
                     String [] theArgs = new String [Argc - 1];
 
                     for (int lcv = 1; lcv < Argc; lcv++)
                         {
                         theArgs[lcv - 1] = Argv[lcv];
                         }
 
-                    strReturn = StartPrg2(theArgs, cmdOut, null, true);
+                    strReturn = StartPrg2(theArgs, cmdOut, null, true, DEFAULT_STARTPRG_TIMEOUT_SECONDS);
                     }
                 else
                     {
                     strReturn = sErrorPrefix + "Wrong number of arguments for " + Argv[0] + " command!";
                     }
                 break;
 
             case EXECCWD:
@@ -754,17 +757,17 @@ public class DoCommand {
                     {
                     String [] theArgs = new String [Argc - 2];
 
                     for (int lcv = 2; lcv < Argc; lcv++)
                         {
                         theArgs[lcv - 2] = Argv[lcv];
                         }
 
-                    strReturn = StartPrg2(theArgs, cmdOut, Argv[1], false);
+                    strReturn = StartPrg2(theArgs, cmdOut, Argv[1], false, DEFAULT_STARTPRG_TIMEOUT_SECONDS);
                     }
                 else
                     {
                     strReturn = sErrorPrefix + "Wrong number of arguments for " + Argv[0] + " command!";
                     }
                 break;
 
             case EXECCWDSU:
@@ -772,17 +775,17 @@ public class DoCommand {
                     {
                     String [] theArgs = new String [Argc - 2];
 
                     for (int lcv = 2; lcv < Argc; lcv++)
                         {
                         theArgs[lcv - 2] = Argv[lcv];
                         }
 
-                    strReturn = StartPrg2(theArgs, cmdOut, Argv[1], true);
+                    strReturn = StartPrg2(theArgs, cmdOut, Argv[1], true, DEFAULT_STARTPRG_TIMEOUT_SECONDS);
                     }
                 else
                     {
                     strReturn = sErrorPrefix + "Wrong number of arguments for " + Argv[0] + " command!";
                     }
                 break;
 
             case RUN:
@@ -791,26 +794,82 @@ public class DoCommand {
                     String [] theArgs = new String [Argc - 1];
 
                     for (int lcv = 1; lcv < Argc; lcv++)
                         {
                         theArgs[lcv - 1] = Argv[lcv];
                         }
 
                     if (Argv[1].contains("/") || Argv[1].contains("\\") || !Argv[1].contains("."))
-                        strReturn = StartPrg(theArgs, cmdOut, false);
+                        strReturn = StartPrg(theArgs, cmdOut, false, DEFAULT_STARTPRG_TIMEOUT_SECONDS);
                     else
                         strReturn = StartJavaPrg(theArgs, null);
                     }
                 else
                     {
                     strReturn = sErrorPrefix + "Wrong number of arguments for " + Argv[0] + " command!";
                     }
                 break;
 
+            case EXECEXT:
+                // An "extended" exec command with format:
+                //    execext [su] [cwd=<path>] [t=<timeout in seconds>] arg1 ...
+                if (Argc >= 2)
+                    {
+                    boolean su = false;
+                    String cwd = null;
+                    int timeout = DEFAULT_STARTPRG_TIMEOUT_SECONDS;
+                    int extra;
+                    for (extra = 1; extra < Argc; extra++)
+                        {
+                        if (Argv[extra].equals("su"))
+                            {
+                            su = true;
+                            }
+                        else if (Argv[extra].startsWith("cwd="))
+                            {
+                            cwd = Argv[extra].substring(4);
+                            }
+                        else if (Argv[extra].startsWith("t="))
+                            {
+                            timeout = Integer.parseInt(Argv[extra].substring(2));
+                            if (timeout < 1 || timeout > 4*60*60)
+                                {
+                                Log.e("SUTAgentAndroid", 
+                                  "invalid execext timeout "+Argv[extra].substring(2)+"; using default instead");
+                                timeout = DEFAULT_STARTPRG_TIMEOUT_SECONDS;
+                                }
+                            }
+                        else
+                            {
+                            break;
+                            }
+                        }
+
+                    if (extra < Argc)
+                        {
+                        String [] theArgs = new String [Argc - extra];
+                        for (int lcv = extra; lcv < Argc; lcv++)
+                            {
+                            theArgs[lcv - extra] = Argv[lcv];
+                            }
+
+                        strReturn = StartPrg2(theArgs, cmdOut, cwd, su, timeout);
+                        }
+                    else
+                        {
+                        strReturn = sErrorPrefix + "No regular arguments for " + Argv[0] + " command!";
+                        }
+                    }
+                else
+                    {
+                    strReturn = sErrorPrefix + "Wrong number of arguments for " + Argv[0] + " command!";
+                    }
+                break;
+
             case KILL:
                 if (Argc == 2)
                     strReturn = KillProcess(Argv[1], cmdOut);
                 else
                     strReturn = sErrorPrefix + "Wrong number of arguments for kill command!";
                 break;
 
             case DISK:
@@ -3589,17 +3648,17 @@ private void CancelNotification()
         catch (InterruptedException e) {
             e.printStackTrace();
         }
 
         ctx = null;
         return (sRet);
         }
 
-    public String StartPrg(String [] progArray, OutputStream out, boolean startAsRoot)
+    public String StartPrg(String [] progArray, OutputStream out, boolean startAsRoot, int timeoutSeconds)
         {
         String sRet = "";
         int    lcv = 0;
 
         try {
             if (startAsRoot)
                 {
                     // we need to requote the program string here, in case
@@ -3620,57 +3679,53 @@ private void CancelNotification()
                     pProc = Runtime.getRuntime().exec(this.getSuArgs(TextUtils.join(" ", quotedProgList)));
                 }
             else
                 {
                     pProc = Runtime.getRuntime().exec(progArray);
                 }
             RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
             outThrd.start();
-            while (lcv < 30) {
-                try {
-                    outThrd.join(10000);
-                    int nRetCode = pProc.exitValue();
-                    sRet = "return code [" + nRetCode + "]";
-                    break;
-                    }
-                catch (IllegalThreadStateException itse) {
-                    lcv++;
-                    }
+            try {
+                outThrd.join(timeoutSeconds * 1000);
+                int nRetCode = pProc.exitValue();
+                sRet = "return code [" + nRetCode + "]";
+                }
+            catch (IllegalThreadStateException itse) {
                 }
             outThrd.stopRedirect();
             }
         catch (IOException e)
             {
             e.printStackTrace();
             }
         catch (InterruptedException e)
             {
             e.printStackTrace();
             sRet = "Timed out!";
             }
 
         return (sRet);
         }
 
-    public String StartPrg2(String [] progArray, OutputStream out, String cwd, boolean startAsRoot)
+    public String StartPrg2(String [] progArray, OutputStream out, String cwd, boolean startAsRoot, int timeoutSeconds)
         {
         String sRet = "";
 
         int    nArraySize = 0;
         int    nArgs = progArray.length - 1; // 1st arg is the environment string
         int    lcv    = 0;
         int    temp = 0;
 
         String sEnvString = progArray[0];
 
         if (!sEnvString.contains("=") && (sEnvString.length() > 0))
             {
             if (sEnvString.contains("/") || sEnvString.contains("\\") || !sEnvString.contains("."))
-                sRet = StartPrg(progArray, out, startAsRoot);
+                sRet = StartPrg(progArray, out, startAsRoot, timeoutSeconds);
             else
                 sRet = StartJavaPrg(progArray, null);
             return(sRet);
             }
 
         // Set up command line args stripping off the environment string
         String [] theArgs = new String [nArgs];
         for (lcv = 0; lcv < nArgs; lcv++)
@@ -3749,28 +3804,22 @@ private void CancelNotification()
                 else
                     {
                     pProc = Runtime.getRuntime().exec(theArgs, envArray);
                     }
 
                 RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
                 outThrd.start();
 
-                lcv = 0;
-
-                while (lcv < 30) {
-                    try {
-                        outThrd.join(10000);
-                        int nRetCode = pProc.exitValue();
-                        sRet = "return code [" + nRetCode + "]";
-                        lcv = 30;
-                        }
-                    catch (IllegalThreadStateException itse) {
-                        lcv++;
-                        }
+                try {
+                    outThrd.join(timeoutSeconds * 1000);
+                    int nRetCode = pProc.exitValue();
+                    sRet = "return code [" + nRetCode + "]";
+                    }
+                catch (IllegalThreadStateException itse) {
                     }
                 outThrd.stopRedirect();
                 }
             else
                 {
                 Intent preIntent = new Intent();
                 for (lcv = 0; lcv < envArray.length; lcv++)
                     {
@@ -3893,34 +3942,34 @@ private void CancelNotification()
         }
 
     private String PrintUsage()
         {
         String sRet =
             "run [cmdline]                   - start program no wait\n" +
             "exec [env pairs] [cmdline]      - start program no wait optionally pass env\n" +
             "                                  key=value pairs (comma separated)\n" +
-            "execcwd [env pairs] [cmdline]   - start program from specified directory\n" +
+            "execcwd <dir> [env pairs] [cmdline] - start program from specified directory\n" +
             "execsu [env pairs] [cmdline]    - start program as privileged user\n" +
-            "execcwdsu [env pairs] [cmdline] - start program from specified directory as privileged user\n" +
+            "execcwdsu <dir> [env pairs] [cmdline] - start program from specified directory as privileged user\n" +
+            "execext [su] [cwd=<dir>] [t=<timeout>] [env pairs] [cmdline] - start program with extended options\n" +
             "kill [program name]             - kill program no path\n" +
             "killall                         - kill all processes started\n" +
             "ps                              - list of running processes\n" +
             "info                            - list of device info\n" +
             "        [os]                    - os version for device\n" +
             "        [id]                    - unique identifier for device\n" +
             "        [uptime]                - uptime for device\n" +
             "        [uptimemillis]          - uptime for device in milliseconds\n" +
             "        [sutuptimemillis]       - uptime for SUT in milliseconds\n" +
             "        [systime]               - current system time\n" +
             "        [screen]                - width, height and bits per pixel for device\n" +
             "        [memory]                - physical, free, available, storage memory\n" +
             "                                  for device\n" +
             "        [processes]             - list of running processes see 'ps'\n" +
-            "deadman timeout                 - set the duration for the deadman timer\n" +
             "alrt [on/off]                   - start or stop sysalert behavior\n" +
             "disk [arg]                      - prints disk space info\n" +
             "cp file1 file2                  - copy file1 to file2\n" +
             "time file                       - timestamp for file\n" +
             "hash file                       - generate hash for file\n" +
             "cd directory                    - change cwd\n" +
             "cat file                        - cat file\n" +
             "cwd                             - display cwd\n" +