在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. }
殊路同归!!!哈。