zoukankan      html  css  js  c++  java
  • Java中执行shell笔记

    在java中执行shell有好几种方式:第一种(exec)方式一

    1. public static synchronized void runshell2()
    2. {
    3.    File superuser = new File("/system/bin/superuser");
    4.  
    5.    if (superuser.exists())
    6.    {
    7.       // return device to original state
    8.       Process process;
    9.       try
    10.       {
    11.          process = Runtime.getRuntime().exec("superuser");
    12.          DataOutputStream os = new DataOutputStream(process.getOutputStream());
    13.          os.writeBytes("mount -oremount,rw /dev/block/mtdblock3 /system ");
    14.          os.writeBytes("busybox cp /system/bin/superuser /system/bin/su ");
    15.          os.writeBytes("busybox chown 0:0 /system/bin/su ");
    16.          os.writeBytes("chmod 4755 /system/bin/su ");
    17.          os.writeBytes("rm /system/bin/superuser ");
    18.          os.writeBytes("/system/bin/monkey -v 100 ");
    19.          os.writeBytes("exit ");
    20.          os.flush();
    21.       } catch (Exception e)
    22.       {
    23.          // TODO Auto-generated catch block
    24.          e.printStackTrace();
    25.       }
    26.    }
    27. }

    第一种(exec)方式二:

    1. public static synchronized void runshell3()
    2. {
    3.    String cmd = "sendkey 3 2 ";
    4.    try
    5.    {
    6.       Process exeEcho = Runtime.getRuntime().exec("su");
    7.       exeEcho.getOutputStream().write(cmd.getBytes());
    8.       exeEcho.getOutputStream().flush();
    9.    } catch (IOException e)
    10.    {
    11.       //showMessage("Excute exception: " + e.getMessage());
    12.       e.printStackTrace();
    13.    }
    14. }

    第二种方式一:

    1. public static synchronized void runShell() {
    2.    ProcessBuilder pb = new ProcessBuilder("/system/bin/sh");
    3.    // java.lang.ProcessBuilder: Creates operating system processes.
    4.    pb.directory(new File("/system/bin"));// 设置shell的当前目录。
    5.    try {
    6.       Process proc = pb.start();
    7.       // 获取输入流,可以通过它获取SHELL的输出。
    8.       BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
    9.       BufferedReader err = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
    10.       // 获取输出流,可以通过它向SHELL发送命令。
    11.       PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);
    12.       out.println("pwd");
    13.       out.println("su root");// 执行这一句时会弹出对话框(以下程序要求授予最高权限...),要求用户确认。
    14.       // out.println("cat /proc/version");
    15.       // out.println("monkey -v 500");
    16.       // out.println("cd /data/data");//这个目录在系统中要求有root权限才可以访问的。
    17.       // out.println("ls -l");//这个命令如果能列出当前安装的APK的数据文件存放目录,就说明我们有了ROOT权限。
    18.       out.println("exit");
    19.       // proc.waitFor();
    20.       String line;
    21.       while ((line = in.readLine()) != null) {
    22.          System.out.println(line); // 打印输出结果
    23.       }
    24.       while ((line = err.readLine()) != null) {
    25.          System.out.println(line); // 打印错误输出结果
    26.       }
    27.       in.close();
    28.       out.close();
    29.       proc.destroy();
    30.    } catch (Exception e) {
    31.       System.out.println("exception:" + e);
    32.    }
    33. }

    第二种方式二:

    1. /**
    2.     * 执行一个shell命令,并返回字符串值
    3.     *
    4.     * @param cmd
    5.     * 命令名称&参数组成的数组(例如:{"/system/bin/cat", "/proc/version"})
    6.     * @param workdirectory
    7.     * 命令执行路径(例如:"system/bin/")
    8.     * @return 执行结果组成的字符串
    9.     * @throws IOException
    10.     */
    11.    public static synchronized String run(String[] cmd, String workdirectory) {
    12.       StringBuffer result = new StringBuffer();
    13.       try {
    14.          ProcessBuilder builder = new ProcessBuilder(cmd);
    15.  
    16.          InputStream in = null;
    17.          // 设置一个路径(绝对路径了就不一定需要)
    18.          if (workdirectory != null) {
    19.             // 设置工作目录(同上)
    20.             builder.directory(new File(workdirectory));
    21.             // 合并标准错误和标准输出
    22.             builder.redirectErrorStream(true);
    23.             // 启动一个新进程
    24.             Process process = builder.start();
    25.  
    26.             // 读取进程标准输出流
    27.             in = process.getInputStream();
    28.             byte[] re = new byte[1024];
    29.             while (in.read(re) != -1) {
    30.                result = result.append(new String(re));
    31.             }
    32.          }
    33.          // 关闭输入流
    34.          if (in != null) {
    35.             in.close();
    36.          }
    37.       } catch (Exception ex) {
    38.          ex.printStackTrace();
    39.       }
    40.       return result.toString();
    41.    }

    笔记:

    今天使用第一种,发现了以下问题:

    1. /**
    2.  * 执行shell
    3.  *
    4.  * @return 0:成功,其它为失败。
    5.  */
    6. public static synchronized int runShellCmd() {
    7.    BufferedReader input = null;
    8.    PrintWriter output = null;
    9.    Process pro = null;
    10.    try {
    11.       pro = Runtime.getRuntime().exec("adb shell ");
    12.       input = new BufferedReader(new InputStreamReader(pro.getInputStream()));
    13.       pro.getOutputStream().write("pidof mediaserver ".getBytes());
    14.       pro.getOutputStream().flush();
    15.       String line = input.readLine();
    16.       int pid = 0;
    17.       /**
    18.        * 按道理说直接执行命令打印是这样的:
    19.        * root@android:/ # adb shell
    20.        * root@android:/ # pidof mediaserver
    21.        * 7114
    22.        * 也就是说第三行就应该是我取到的pid值,但是实际上却是5行?
    23.        */
    24.       for (int i = 0; i < 6; i++) {
    25.          Log.e(TAG , i + " line is " + line);
    26.          pid = toInt(line, 0);
    27.          if (pid > 0)
    28.             break;
    29.          line = input.readLine();
    30.       }
    31.       Log.e(TAG, "pid:" + pid);
    32.       /**
    33.        * 实际打印如下:
    34.        * E/MainActivity( 7036): 0 line is pidof mediaserver
    35.        * E/MainActivity( 7036): 1 line is
    36.        * E/MainActivity( 7036): 2 line is root@android:/ # pidof mediaserver
    37.        * E/MainActivity( 7036): 3 line is
    38.        * E/MainActivity( 7036): 4 line is 6946
    39.        * E/MainActivity( 7036): pid:6946
    40.        * 为什么会多出2个空行??
    41.        */
    42.       if (pid == 0) {
    43.          throw new IOException("not find mediaserver process!");
    44.       }
    45.       String killCmd = String.format("kill -9 %d ", pid);
    46.       /**
    47.        * 直接这么使用不行的,不知道什么原因,执行结果死活不对。
    48.        */
    49.       pro.getOutputStream().write(killCmd.getBytes());
    50.       pro.getOutputStream().flush();
    51.  
    52.       /**
    53.        * 再一次这么重开就ok了,谁能告诉我原因?
    54.        */
    55.       pro.destroy();
    56.       pro = null;
    57.       pro = Runtime.getRuntime().exec("adb shell ");
    58.       pro.getOutputStream().write(killCmd.getBytes());
    59.       pro.getOutputStream().flush();
    60.  
    61.  
    62.    } catch (IOException ex) {
    63.       ex.printStackTrace();
    64.       return -1;
    65.    } finally {
    66.       try {
    67.          if (input != null) {
    68.             input.close();
    69.          }
    70.          if (output != null) {
    71.             output.close();
    72.          }
    73.       } catch (IOException e) {
    74.          e.printStackTrace();
    75.       }
    76.       if (pro != null) {
    77.          pro.destroy();
    78.          pro = null;
    79.       }
    80.    }
    81.    return 0;
    82. }

    我去看看源码是怎么样的!

    Runtime的exec最终调用的是ProcessManager,代码如下所示:

    1. /**
    2.  * Executes the specified command and its arguments in a separate native
    3.  * process. The new process uses the environment provided in {@code envp}
    4.  * and the working directory specified by {@code directory}.
    5.  *
    6.  * @param progArray
    7.  * the array containing the program to execute as well as any
    8.  * arguments to the program.
    9.  * @param envp
    10.  * the array containing the environment to start the new process
    11.  * in.
    12.  * @param directory
    13.  * the directory in which to execute the program. If {@code null},
    14.  * execute if in the same directory as the parent process.
    15.  * @return the new {@code Process} object that represents the native
    16.  * process.
    17.  * @throws IOException
    18.  * if the requested program can not be executed.
    19.  * @throws SecurityException
    20.  * if the current {@code SecurityManager} disallows program
    21.  * execution.
    22.  * @see SecurityManager#checkExec
    23.  * @since Android 1.0
    24.  */
    25. public Process exec(String[] progArray, String[] envp, File directory) throws IOException {
    26.     // BEGIN android-changed: push responsibility for argument checking into ProcessManager
    27.     return ProcessManager.getInstance().exec(progArray, envp, directory, false);
    28.     // END android-changed
    29. }

    ProcessManager的exec代码如下:

    1. /**
    2.  * Map from pid to Process. We keep weak references to the Process objects
    3.  * and clean up the entries when no more external references are left. The
    4.  * process objects themselves don't require much memory, but file
    5.  * descriptors (associated with stdin/out/err in this case) can be
    6.  * a scarce resource.
    7.  */
    8. private final Map<Integer, ProcessReference> processReferences
    9.         = new HashMap<Integer, ProcessReference>();
    10. /**
    11.  * Executes a process and returns an object representing it.
    12.  */
    13. Process exec(String[] taintedCommand, String[] taintedEnvironment, File workingDirectory,
    14.         boolean redirectErrorStream) throws IOException {
    15.     // Make sure we throw the same exceptions as the RI.
    16.     if (taintedCommand == null) {
    17.         throw new NullPointerException();
    18.     }
    19.     if (taintedCommand.length == 0) {
    20.         throw new IndexOutOfBoundsException();
    21.     }
    22.  
    23.     // Handle security and safety by copying mutable inputs and checking them.
    24.     String[] command = taintedCommand.clone();
    25.     String[] environment = taintedEnvironment != null ? taintedEnvironment.clone() : null;
    26.     SecurityManager securityManager = System.getSecurityManager();
    27.     if (securityManager != null) {
    28.         securityManager.checkExec(command[0]);//权限检查
    29.     }
    30.     // Check we're not passing null Strings to the native exec.
    31.     for (String arg : command) {
    32.         if (arg == null) {
    33.             throw new NullPointerException();
    34.         }
    35.     }
    36.     // The environment is allowed to be null or empty, but no element may be null.
    37.     if (environment != null) {
    38.         for (String env : environment) {
    39.             if (env == null) {
    40.                 throw new NullPointerException();
    41.             }
    42.         }
    43.     }
    44.  
    45.     FileDescriptor in = new FileDescriptor();
    46.     FileDescriptor out = new FileDescriptor();
    47.     FileDescriptor err = new FileDescriptor();
    48.  
    49.     String workingPath = (workingDirectory == null)
    50.             ? null
    51.             : workingDirectory.getPath();
    52.  
    53.     // Ensure onExit() doesn't access the process map before we add our
    54.     // entry.
    55.     synchronized (processReferences) {
    56.         int pid;
    57.         try {
    58.            /**
    59.             * 调用exec函数
    60.             */
    61.             pid = exec(command, environment, workingPath, in, out, err, redirectErrorStream);
    62.         } catch (IOException e) {
    63.             IOException wrapper = new IOException("Error running exec()."
    64.                     + " Command: " + Arrays.toString(command)
    65.                     + " Working Directory: " + workingDirectory
    66.                     + " Environment: " + Arrays.toString(environment));
    67.             wrapper.initCause(e);
    68.             throw wrapper;
    69.         }
    70.         /**
    71.          * 新建一个进程实现。
    72.          */
    73.         ProcessImpl process = new ProcessImpl(pid, in, out, err);
    74.         /**
    75.          * 创建一个进程引用。
    76.          */
    77.         ProcessReference processReference
    78.                 = new ProcessReference(process, referenceQueue);
    79.  
    80.         /**
    81.          * 加入到全局进程引用map中。
    82.          */
    83.         processReferences.put(pid, processReference);
    84.  
    85.         /*
    86.          * This will wake up the child monitor thread in case there
    87.          * weren't previously any children to wait on.
    88.          */
    89.         processReferences.notifyAll();
    90.  
    91.         return process;
    92.     }
    93. }

    本地exec的原型:

    1. /**
    2.  * Executes a native process. Fills in in, out, and err and returns the
    3.  * new process ID upon success.
    4.  */
    5. static native int exec(String[] command, String[] environment,
    6.         String workingDirectory, FileDescriptor in, FileDescriptor out,
    7.         FileDescriptor err, boolean redirectErrorStream) throws IOException;

    对应的native文件为:

    1. //Android 4.0.3在
    2. ./libcore/luni/src/main/native/java_lang_ProcessManager.cpp
    3. //Android 2.2在
    4. ./dalvik/libcore/luni-kernel/src/main/native/java_lang_ProcessManager.cpp
    5. //源码为:
    6. /**
    7.  * Converts Java String[] to char** and delegates to executeProcess().
    8.  */
    9. static pid_t java_lang_ProcessManager_exec(
    10.         JNIEnv* env, jclass clazz, jobjectArray javaCommands,
    11.         jobjectArray javaEnvironment, jstring javaWorkingDirectory,
    12.         jobject inDescriptor, jobject outDescriptor, jobject errDescriptor,
    13.         jboolean redirectErrorStream) {
    14.  
    15.     // Copy commands into char*[].
    16.     char** commands = convertStrings(env, javaCommands);
    17.  
    18.     // Extract working directory string.
    19.     const char* workingDirectory = NULL;
    20.     if (javaWorkingDirectory != NULL) {
    21.         workingDirectory = env->GetStringUTFChars(javaWorkingDirectory, NULL);
    22.     }
    23.  
    24.     // Convert environment array.
    25.     char** environment = convertStrings(env, javaEnvironment);
    26.  
    27.     //关键就这一行.
    28.     pid_t result = executeProcess(
    29.             env, commands, environment, workingDirectory,
    30.             inDescriptor, outDescriptor, errDescriptor, redirectErrorStream);
    31.  
    32.     // Temporarily clear exception so we can clean up.
    33.     jthrowable exception = env->ExceptionOccurred();
    34.     env->ExceptionClear();
    35.  
    36.     freeStrings(env, javaEnvironment, environment);
    37.  
    38.     // Clean up working directory string.
    39.     if (javaWorkingDirectory != NULL) {
    40.         env->ReleaseStringUTFChars(javaWorkingDirectory, workingDirectory);
    41.     }
    42.  
    43.     freeStrings(env, javaCommands, commands);
    44.  
    45.     // Re-throw exception if present.
    46.     if (exception != NULL) {
    47.         if (env->Throw(exception) < 0) {
    48.             LOGE("Error rethrowing exception!");
    49.         }
    50.     }
    51.  
    52.     return result;
    53. }

    看看executeProcess接口,其实源码注释写的很清楚。

    1. /** Executes a command in a child process. */
    2. static pid_t executeProcess(JNIEnv* env, char** commands, char** environment,
    3.         const char* workingDirectory, jobject inDescriptor,
    4.         jobject outDescriptor, jobject errDescriptor,
    5.         jboolean redirectErrorStream) {
    6.     int i, result, error;
    7.  
    8.     // Create 4 pipes: stdin, stdout, stderr, and an exec() status pipe.
    9.     int pipes[PIPE_COUNT * 2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
    10.     for (i = 0; i < PIPE_COUNT; i++) {
    11.         if (pipe(pipes + i * 2) == -1) {
    12.             jniThrowIOException(env, errno);
    13.             closePipes(pipes, -1);
    14.             return -1;
    15.         }
    16.     }
    17.     int stdinIn = pipes[0];
    18.     int stdinOut = pipes[1];
    19.     int stdoutIn = pipes[2];
    20.     int stdoutOut = pipes[3];
    21.     int stderrIn = pipes[4];
    22.     int stderrOut = pipes[5];
    23.     int statusIn = pipes[6];
    24.     int statusOut = pipes[7];
    25.  
    26.     pid_t childPid = fork();
    27.  
    28.     // If fork() failed...
    29.     if (childPid == -1) {
    30.         jniThrowIOException(env, errno);
    31.         closePipes(pipes, -1);
    32.         return -1;
    33.     }
    34.  
    35.     // If this is the child process...
    36.     if (childPid == 0) {
    37.         /*
    38.          * Note: We cannot malloc() or free() after this point!
    39.          * A no-longer-running thread may be holding on to the heap lock, and
    40.          * an attempt to malloc() or free() would result in deadlock.
    41.          */
    42.  
    43.         // Replace stdin, out, and err with pipes.
    44.         dup2(stdinIn, 0);
    45.         dup2(stdoutOut, 1);
    46.         if (redirectErrorStream) {
    47.             dup2(stdoutOut, 2);
    48.         } else {
    49.             dup2(stderrOut, 2);
    50.         }
    51.  
    52.         // Close all but statusOut. This saves some work in the next step.
    53.         closePipes(pipes, statusOut);
    54.  
    55.         // Make statusOut automatically close if execvp() succeeds.
    56.         fcntl(statusOut, F_SETFD, FD_CLOEXEC);
    57.  
    58.         // Close remaining open fds with the exception of statusOut.
    59.         closeNonStandardFds(statusOut);
    60.  
    61.         // Switch to working directory.
    62.         if (workingDirectory != NULL) {
    63.             if (chdir(workingDirectory) == -1) {
    64.                 goto execFailed;
    65.             }
    66.         }
    67.  
    68.         // Set up environment.
    69.         if (environment != NULL) {
    70.             environ = environment;
    71.         }
    72.  
    73.         // Execute process. By convention, the first argument in the arg array
    74.         // should be the command itself. In fact, I get segfaults when this
    75.         // isn't the case.
    76.         execvp(commands[0], commands);
    77.  
    78.         // If we got here, execvp() failed or the working dir was invalid.
    79.         execFailed:
    80.             error = errno;
    81.             write(statusOut, &error, sizeof(int));
    82.             close(statusOut);
    83.             exit(error);
    84.     }
    85.  
    86.     // This is the parent process.
    87.  
    88.     // Close child's pipe ends.
    89.     close(stdinIn);
    90.     close(stdoutOut);
    91.     close(stderrOut);
    92.     close(statusOut);
    93.  
    94.     // Check status pipe for an error code. If execvp() succeeds, the other
    95.     // end of the pipe should automatically close, in which case, we'll read
    96.     // nothing.
    97.     int count = read(statusIn, &result, sizeof(int));
    98.     close(statusIn);
    99.     if (count > 0) {
    100.         jniThrowIOException(env, result);
    101.  
    102.         close(stdoutIn);
    103.         close(stdinOut);
    104.         close(stderrIn);
    105.  
    106.         return -1;
    107.     }
    108.  
    109.     // Fill in file descriptor wrappers.
    110.     jniSetFileDescriptorOfFD(env, inDescriptor, stdoutIn);
    111.     jniSetFileDescriptorOfFD(env, outDescriptor, stdinOut);
    112.     jniSetFileDescriptorOfFD(env, errDescriptor, stderrIn);
    113.  
    114.     return childPid;
    115. }

    至此,Runtime的exec就全部结束了。如果对下面的fork,execvp这2个函数不了解。建议看看APU。

     

    最后来看看ProcessBuilder类的实现:

    1. /**
    2.  * Starts a new process based on the current state of this process builder.
    3.  *
    4.  * @return the new {@code Process} instance.
    5.  * @throws NullPointerException
    6.  * if any of the elements of {@link #command()} is {@code null}.
    7.  * @throws IndexOutOfBoundsException
    8.  * if {@link #command()} is empty.
    9.  * @throws SecurityException
    10.  * if {@link SecurityManager#checkExec(String)} doesn't allow
    11.  * process creation.
    12.  * @throws IOException
    13.  * if an I/O error happens.
    14.  */
    15. public Process start() throws IOException {
    16.     // BEGIN android-changed: push responsibility for argument checking into ProcessManager
    17.     String[] cmdArray = command.toArray(new String[command.size()]);
    18.     String[] envArray = new String[environment.size()];
    19.     int i = 0;
    20.     for (Map.Entry<String, String> entry : environment.entrySet()) {
    21.         envArray[i++] = entry.getKey() + "=" + entry.getValue(); //$NON-NLS-1$
    22.     }
    23.     //和Runtime.exec的一样。
    24.     return ProcessManager.getInstance().exec(cmdArray, envArray, directory, redirectErrorStream);
    25.     // END android-changed
    26. }

    殊路同归!!!哈。

     

     

     

     

  • 相关阅读:
    codeforces 616B Dinner with Emma
    codeforces 616A Comparing Two Long Integers
    codeforces 615C Running Track
    codeforces 612C Replace To Make Regular Bracket Sequence
    codeforces 612B HDD is Outdated Technology
    重写父类中的成员属性
    子类继承父类
    访问修饰符
    方法的参数
    实例化类
  • 原文地址:https://www.cnblogs.com/jevan/p/3169617.html
Copyright © 2011-2022 走看看