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

1. public
					static
					synchronized
					void
2. {

3. new File("/system/bin/superuser");

4. 
 
5. if
6.    {

7. // return device to original state
8.       Process process;

9. try
10.       {

11. superuser");

12. new
13. mount -oremount,rw /dev/block/mtdblock3 /system\n");

14. busybox cp /system/bin/superuser /system/bin/su\n");

15. busybox chown 0:0 /system/bin/su\n");

16. chmod 4755 /system/bin/su\n");

17. rm /system/bin/superuser\n");

18. /system/bin/monkey -v 100\n");

19. exit\n");

20.          os.flush();

21. catch
22.       {

23. // TODO Auto-generated catch block
24.          e.printStackTrace();

25.       }

26.    }

27. }

第一种(exec)方式二:

1. public
					static
					synchronized
					void
2. {

3. sendkey 3 2\n";

4. try
5.    {

6. su");

7.       exeEcho.getOutputStream().write(cmd.getBytes());

8.       exeEcho.getOutputStream().flush();

9. catch
10.    {

11. //showMessage("Excute exception: " + e.getMessage());
12.       e.printStackTrace();

13.    }

14. }

第二种方式一:

1. public
					static
					synchronized
					void
2. new ProcessBuilder("/system/bin/sh");

3. // java.lang.ProcessBuilder: Creates operating system processes.
4. new File("/system/bin"));// 设置shell的当前目录。
5. try
6.       Process proc = pb.start();

7. // 获取输入流,可以通过它获取SHELL的输出。
8. new BufferedReader(new
9. new BufferedReader(new
10. // 获取输出流,可以通过它向SHELL发送命令。
11. new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);

12. pwd");

13. 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. exit");

19. // proc.waitFor();
20.       String line;

21. while ((line = in.readLine()) != null) {

22. // 打印输出结果
23.       }

24. while ((line = err.readLine()) != null) {

25. // 打印错误输出结果
26.       }

27.       in.close();

28.       out.close();

29.       proc.destroy();

30. catch
31. 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
12. new
13. try
14. new
15. 
 
16. null;

17. // 设置一个路径(绝对路径了就不一定需要)
18. if (workdirectory != null) {

19. // 设置工作目录(同上)
20. new
21. // 合并标准错误和标准输出
22. true);

23. // 启动一个新进程
24.             Process process = builder.start();

25. 
 
26. // 读取进程标准输出流
27.             in = process.getInputStream();

28. byte[] re = new
					byte[1024];

29. while
30. new
31.             }

32.          }

33. // 关闭输入流
34. if (in != null) {

35.             in.close();

36.          }

37. catch
38.          ex.printStackTrace();

39.       }

40. return
41.    }

笔记:

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

1. /**

2.  * 执行shell

3.  * 

4.  * @return 0:成功,其它为失败。

5.  */
6. public
					static
					synchronized
					int
7. null;

8. null;

9. null;

10. try
11. adb shell ");

12. new BufferedReader(new
13. pidof mediaserver\r\n".getBytes());

14.       pro.getOutputStream().flush();

15.       String line = input.readLine();

16. int
17. /**

18.        * 按道理说直接执行命令打印是这样的:

19.        * root@android:/ # adb shell

20.        * root@android:/ # pidof mediaserver

21.        * 7114

22.        * 也就是说第三行就应该是我取到的pid值,但是实际上却是5行?

23.        */
24. for (int
25.  line is " + line);

26.          pid = toInt(line, 0);

27. if
28. break;

29.          line = input.readLine();

30.       }

31. 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
43. throw
					new IOException("not find mediaserver process!");

44.       }

45. kill -9 %d\r\n", pid);

46. /**

47.        * 直接这么使用不行的,不知道什么原因,执行结果死活不对。

48.        */
49.       pro.getOutputStream().write(killCmd.getBytes());

50.       pro.getOutputStream().flush();

51. 
 
52. /**

53.        * 再一次这么重开就ok了,谁能告诉我原因?

54.        */
55.       pro.destroy();

56. null;

57. adb shell ");

58.       pro.getOutputStream().write(killCmd.getBytes());

59.       pro.getOutputStream().flush();

60. 
 
61. 
 
62. catch
63.       ex.printStackTrace();

64. return
65. finally
66. try
67. if (input != null) {

68.             input.close();

69.          }

70. if (output != null) {

71.             output.close();

72.          }

73. catch
74.          e.printStackTrace();

75.       }

76. if (pro != null) {

77.          pro.destroy();

78. null;

79.       }

80.    }

81. return
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
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
9. new
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
15. // Make sure we throw the same exceptions as the RI.
16. if (taintedCommand == null) {

17. throw
					new
18.     }

19. if
20. throw
					new
21.     }

22. 
 
23. // Handle security and safety by copying mutable inputs and checking them.
24.     String[] command = taintedCommand.clone();

25. null ? taintedEnvironment.clone() : null;

26.     SecurityManager securityManager = System.getSecurityManager();

27. if (securityManager != null) {

28. //权限检查
29.     }

30. // Check we're not passing null Strings to the native exec.
31. for
32. if (arg == null) {

33. throw
					new
34.         }

35.     }

36. // The environment is allowed to be null or empty, but no element may be null.
37. if (environment != null) {

38. for
39. if (env == null) {

40. throw
					new
41.             }

42.         }

43.     }

44. 
 
45. new
46. new
47. new
48. 
 
49. null)

50. null
51.             : workingDirectory.getPath();

52. 
 
53. // Ensure onExit() doesn't access the process map before we add our
54. // entry.
55. synchronized
56. int
57. try
58. /**

59.             * 调用exec函数

60.             */
61.             pid = exec(command, environment, workingPath, in, out, err, redirectErrorStream);

62. catch
63. 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
69.         }

70. /**

71.          * 新建一个进程实现。

72.          */
73. new
74. /**

75.          * 创建一个进程引用。

76.          */
77.         ProcessReference processReference

78. new
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
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
6.         String workingDirectory, FileDescriptor in, FileDescriptor out,

7. boolean redirectErrorStream) throws

对应的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
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
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
40.         env->ReleaseStringUTFChars(javaWorkingDirectory, workingDirectory);

41.     }

42. 
 
43.     freeStrings(env, javaCommands, commands);

44. 
 
45. // Re-throw exception if present.
46. if
47. if
48. Error rethrowing exception!");

49.         }

50.     }

51. 
 
52. return
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
7. 
 
8. // Create 4 pipes: stdin, stdout, stderr, and an exec() status pipe.
9. int
10. for
11. if
12.             jniThrowIOException(env, errno);

13.             closePipes(pipes, -1);

14. return
15.         }

16.     }

17. int
18. int
19. int
20. int
21. int
22. int
23. int
24. int
25. 
 
26.     pid_t childPid = fork();

27. 
 
28. // If fork() failed...
29. if
30.         jniThrowIOException(env, errno);

31.         closePipes(pipes, -1);

32. return
33.     }

34. 
 
35. // If this is the child process...
36. if
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
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
63. if
64. goto
65.             }

66.         }

67. 
 
68. // Set up environment.
69. if
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. 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
100.         jniThrowIOException(env, result);

101. 
 
102.         close(stdoutIn);

103.         close(stdinOut);

104.         close(stderrIn);

105. 
 
106. return
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
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
16. // BEGIN android-changed: push responsibility for argument checking into ProcessManager
17. new
18. new
19. int
20. for
21. =" + entry.getValue(); //$NON-NLS-1$
22.     }

23. //和Runtime.exec的一样。
24. return
25. // END android-changed
26. }

殊路同归!!!哈。