设为首页 收藏本站
查看: 720|回复: 0

Java中执行shell笔记

[复制链接]

尚未签到

发表于 2015-4-28 13:04:15 | 显示全部楼层 |阅读模式
  在java中执行shell有好几种方式:第一种(exec)方式一


  • publicstaticsynchronizedvoid runshell2()

  • {

  • ???File superuser = new File("/system/bin/superuser");

  • ?

  • ???if (superuser.exists())

  • ???{

  • ??????// return device to original state

  • ??????Process process;

  • ??????try

  • ??????{

  • ?????????process = Runtime.getRuntime().exec("superuser");

  • ?????????DataOutputStream os = new DataOutputStream(process.getOutputStream());

  • ?????????os.writeBytes("mount -oremount,rw /dev/block/mtdblock3 /system\n");

  • ?????????os.writeBytes("busybox cp /system/bin/superuser /system/bin/su\n");

  • ?????????os.writeBytes("busybox chown 0:0 /system/bin/su\n");

  • ?????????os.writeBytes("chmod 4755 /system/bin/su\n");

  • ?????????os.writeBytes("rm /system/bin/superuser\n");

  • ?????????os.writeBytes("/system/bin/monkey -v 100\n");

  • ?????????os.writeBytes("exit\n");

  • ?????????os.flush();

  • ??????} catch (Exception e)

  • ??????{

  • ?????????// TODO Auto-generated catch block

  • ?????????e.printStackTrace();

  • ??????}

  • ???}

  • }
  第一种(exec)方式二:


  • publicstaticsynchronizedvoid runshell3()

  • {

  • ???String cmd = "sendkey 3 2\n";

  • ???try

  • ???{

  • ??????Process exeEcho = Runtime.getRuntime().exec("su");

  • ??????exeEcho.getOutputStream().write(cmd.getBytes());

  • ??????exeEcho.getOutputStream().flush();

  • ???} catch (IOException e)

  • ???{

  • ??????//showMessage("Excute exception: " + e.getMessage());

  • ??????e.printStackTrace();

  • ???}

  • }
  第二种方式一:


  • publicstaticsynchronizedvoid runShell() {

  • ???ProcessBuilder pb = new ProcessBuilder("/system/bin/sh");

  • ???// java.lang.ProcessBuilder: Creates operating system processes.

  • ???pb.directory(new File("/system/bin"));// 设置shell的当前目录。

  • ???try {

  • ??????Process proc = pb.start();

  • ??????// 获取输入流,可以通过它获取SHELL的输出。

  • ??????BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));

  • ??????BufferedReader err = new BufferedReader(new InputStreamReader(proc.getErrorStream()));

  • ??????// 获取输出流,可以通过它向SHELL发送命令。

  • ??????PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);

  • ??????out.println("pwd");

  • ??????out.println("su root");// 执行这一句时会弹出对话框(以下程序要求授予最高权限...),要求用户确认。

  • ??????// out.println("cat /proc/version");

  • ??????// out.println("monkey -v 500");

  • ??????// out.println("cd /data/data");//这个目录在系统中要求有root权限才可以访问的。

  • ??????// out.println("ls -l");//这个命令如果能列出当前安装的APK的数据文件存放目录,就说明我们有了ROOT权限。

  • ??????out.println("exit");

  • ??????// proc.waitFor();

  • ??????String line;

  • ??????while ((line = in.readLine()) != null) {

  • ?????????System.out.println(line); // 打印输出结果

  • ??????}

  • ??????while ((line = err.readLine()) != null) {

  • ?????????System.out.println(line); // 打印错误输出结果

  • ??????}

  • ??????in.close();

  • ??????out.close();

  • ??????proc.destroy();

  • ???} catch (Exception e) {

  • ??????System.out.println("exception:" + e);

  • ???}

  • }
  第二种方式二:


  • /**

  • ????* 执行一个shell命令,并返回字符串值

  • ????*

  • ????* @param cmd

  • ????* 命令名称&参数组成的数组(例如:{"/system/bin/cat", "/proc/version"})

  • ????* @param workdirectory

  • ????* 命令执行路径(例如:"system/bin/")

  • ????* @return 执行结果组成的字符串

  • ????* @throws IOException

  • ????*/

  • ???publicstaticsynchronized String run(String[] cmd, String workdirectory) {

  • ??????StringBuffer result = new StringBuffer();

  • ??????try {

  • ?????????ProcessBuilder builder = new ProcessBuilder(cmd);

  • ?

  • ?????????InputStream in = null;

  • ?????????// 设置一个路径(绝对路径了就不一定需要)

  • ?????????if (workdirectory != null) {

  • ????????????// 设置工作目录(同上)

  • ????????????builder.directory(new File(workdirectory));

  • ????????????// 合并标准错误和标准输出

  • ????????????builder.redirectErrorStream(true);

  • ????????????// 启动一个新进程

  • ????????????Process process = builder.start();

  • ?

  • ????????????// 读取进程标准输出流

  • ????????????in = process.getInputStream();

  • ????????????byte[] re = newbyte[1024];

  • ????????????while (in.read(re) != -1) {

  • ???????????????result = result.append(new String(re));

  • ????????????}

  • ?????????}

  • ?????????// 关闭输入流

  • ?????????if (in != null) {

  • ????????????in.close();

  • ?????????}

  • ??????} catch (Exception ex) {

  • ?????????ex.printStackTrace();

  • ??????}

  • ??????return result.toString();

  • ???}
  笔记:
  今天使用第一种,发现了以下问题:


  • /**

  • ?* 执行shell

  • ?*

  • ?* @return 0:成功,其它为失败。

  • ?*/

  • publicstaticsynchronizedint runShellCmd() {

  • ???BufferedReader input = null;

  • ???PrintWriter output = null;

  • ???Process pro = null;

  • ???try {

  • ??????pro = Runtime.getRuntime().exec("adb shell ");

  • ??????input = new BufferedReader(new InputStreamReader(pro.getInputStream()));

  • ??????pro.getOutputStream().write("pidof mediaserver\r\n".getBytes());

  • ??????pro.getOutputStream().flush();

  • ??????String line = input.readLine();

  • ??????int pid = 0;

  • ??????/**

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

  • ???????* root@android:/ # adb shell

  • ???????* root@android:/ # pidof mediaserver

  • ???????* 7114

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

  • ???????*/

  • ??????for (int i = 0; i < 6; i++) {

  • ?????????Log.e(TAG , i + " line is " + line);

  • ?????????pid = toInt(line, 0);

  • ?????????if (pid > 0)

  • ????????????break;

  • ?????????line = input.readLine();

  • ??????}

  • ??????Log.e(TAG, "pid:" + pid);

  • ??????/**

  • ???????* 实际打印如下:

  • ???????* E/MainActivity( 7036): 0 line is pidof mediaserver

  • ???????* E/MainActivity( 7036): 1 line is

  • ???????* E/MainActivity( 7036): 2 line is root@android:/ # pidof mediaserver

  • ???????* E/MainActivity( 7036): 3 line is

  • ???????* E/MainActivity( 7036): 4 line is 6946

  • ???????* E/MainActivity( 7036): pid:6946

  • ???????* 为什么会多出2个空行??

  • ???????*/

  • ??????if (pid == 0) {

  • ?????????thrownew IOException("not find mediaserver process!");

  • ??????}

  • ??????String killCmd = String.format("kill -9 %d\r\n", pid);

  • ??????/**

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

  • ???????*/

  • ??????pro.getOutputStream().write(killCmd.getBytes());

  • ??????pro.getOutputStream().flush();

  • ?

  • ??????/**

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

  • ???????*/

  • ??????pro.destroy();

  • ??????pro = null;

  • ??????pro = Runtime.getRuntime().exec("adb shell ");

  • ??????pro.getOutputStream().write(killCmd.getBytes());

  • ??????pro.getOutputStream().flush();

  • ?

  • ?

  • ???} catch (IOException ex) {

  • ??????ex.printStackTrace();

  • ??????return -1;

  • ???} finally {

  • ??????try {

  • ?????????if (input != null) {

  • ????????????input.close();

  • ?????????}

  • ?????????if (output != null) {

  • ????????????output.close();

  • ?????????}

  • ??????} catch (IOException e) {

  • ?????????e.printStackTrace();

  • ??????}

  • ??????if (pro != null) {

  • ?????????pro.destroy();

  • ?????????pro = null;

  • ??????}

  • ???}

  • ???return 0;

  • }
  我去看看源码是怎么样的!
  Runtime的exec最终调用的是ProcessManager,代码如下所示:


  • /**

  • ?* Executes the specified command and its arguments in a separate native

  • ?* process. The new process uses the environment provided in {@code envp}

  • ?* and the working directory specified by {@code directory}.

  • ?*

  • ?* @param progArray

  • ?* the array containing the program to execute as well as any

  • ?* arguments to the program.

  • ?* @param envp

  • ?* the array containing the environment to start the new process

  • ?* in.

  • ?* @param directory

  • ?* the directory in which to execute the program. If {@code null},

  • ?* execute if in the same directory as the parent process.

  • ?* @return the new {@code Process} object that represents the native

  • ?* process.

  • ?* @throws IOException

  • ?* if the requested program can not be executed.

  • ?* @throws SecurityException

  • ?* if the current {@code SecurityManager} disallows program

  • ?* execution.

  • ?* @see SecurityManager#checkExec

  • ?* @since Android 1.0

  • ?*/

  • public Process exec(String[] progArray, String[] envp, File directory) throws IOException {

  • ????// BEGIN android-changed: push responsibility for argument checking into ProcessManager

  • ????return ProcessManager.getInstance().exec(progArray, envp, directory, false);

  • ????// END android-changed

  • }
  ProcessManager的exec代码如下:


  • /**

  • ?* Map from pid to Process. We keep weak references to the Process objects

  • ?* and clean up the entries when no more external references are left. The

  • ?* process objects themselves don't require much memory, but file

  • ?* descriptors (associated with stdin/out/err in this case) can be

  • ?* a scarce resource.

  • ?*/

  • privatefinal Map processReferences

  • ????????= new HashMap();

  • /**

  • ?* Executes a process and returns an object representing it.

  • ?*/

  • Process exec(String[] taintedCommand, String[] taintedEnvironment, File workingDirectory,

  • ????????boolean redirectErrorStream) throws IOException {

  • ????// Make sure we throw the same exceptions as the RI.

  • ????if (taintedCommand == null) {

  • ????????thrownew NullPointerException();

  • ????}

  • ????if (taintedCommand.length == 0) {

  • ????????thrownew IndexOutOfBoundsException();

  • ????}

  • ?

  • ????// Handle security and safety by copying mutable inputs and checking them.

  • ????String[] command = taintedCommand.clone();

  • ????String[] environment = taintedEnvironment != null ? taintedEnvironment.clone() : null;

  • ????SecurityManager securityManager = System.getSecurityManager();

  • ????if (securityManager != null) {

  • ????????securityManager.checkExec(command[0]);//权限检查

  • ????}

  • ????// Check we're not passing null Strings to the native exec.

  • ????for (String arg : command) {

  • ????????if (arg == null) {

  • ????????????thrownew NullPointerException();

  • ????????}

  • ????}

  • ????// The environment is allowed to be null or empty, but no element may be null.

  • ????if (environment != null) {

  • ????????for (String env : environment) {

  • ????????????if (env == null) {

  • ????????????????thrownew NullPointerException();

  • ????????????}

  • ????????}

  • ????}

  • ?

  • ????FileDescriptor in = new FileDescriptor();

  • ????FileDescriptor out = new FileDescriptor();

  • ????FileDescriptor err = new FileDescriptor();

  • ?

  • ????String workingPath = (workingDirectory == null)

  • ????????????? null

  • ????????????: workingDirectory.getPath();

  • ?

  • ????// Ensure onExit() doesn't access the process map before we add our

  • ????// entry.

  • ????synchronized (processReferences) {

  • ????????int pid;

  • ????????try {

  • ???????????/**

  • ????????????* 调用exec函数

  • ????????????*/

  • ????????????pid = exec(command, environment, workingPath, in, out, err, redirectErrorStream);

  • ????????} catch (IOException e) {

  • ????????????IOException wrapper = new IOException("Error running exec()."

  • ????????????????????+ " Command: " + Arrays.toString(command)

  • ????????????????????+ " Working Directory: " + workingDirectory

  • ????????????????????+ " Environment: " + Arrays.toString(environment));

  • ????????????wrapper.initCause(e);

  • ????????????throw wrapper;

  • ????????}

  • ????????/**

  • ?????????* 新建一个进程实现。

  • ?????????*/

  • ????????ProcessImpl process = new ProcessImpl(pid, in, out, err);

  • ????????/**

  • ?????????* 创建一个进程引用。

  • ?????????*/

  • ????????ProcessReference processReference

  • ????????????????= new ProcessReference(process, referenceQueue);

  • ?

  • ????????/**

  • ?????????* 加入到全局进程引用map中。

  • ?????????*/

  • ????????processReferences.put(pid, processReference);

  • ?

  • ????????/*

  • ?????????* This will wake up the child monitor thread in case there

  • ?????????* weren't previously any children to wait on.

  • ?????????*/

  • ????????processReferences.notifyAll();

  • ?

  • ????????return process;

  • ????}

  • }
  本地exec的原型:


  • /**

  • ?* Executes a native process. Fills in in, out, and err and returns the

  • ?* new process ID upon success.

  • ?*/

  • staticnativeint exec(String[] command, String[] environment,

  • ????????String workingDirectory, FileDescriptor in, FileDescriptor out,

  • ????????FileDescriptor err, boolean redirectErrorStream) throws IOException;
  对应的native文件为:


  • //Android 4.0.3在

  • ./libcore/luni/src/main/native/java_lang_ProcessManager.cpp

  • //Android 2.2在

  • ./dalvik/libcore/luni-kernel/src/main/native/java_lang_ProcessManager.cpp

  • //源码为:

  • /**

  • ?* Converts Java String[] to char** and delegates to executeProcess().

  • ?*/

  • static pid_t java_lang_ProcessManager_exec(

  • ????????JNIEnv* env, jclass clazz, jobjectArray javaCommands,

  • ????????jobjectArray javaEnvironment, jstring javaWorkingDirectory,

  • ????????jobject inDescriptor, jobject outDescriptor, jobject errDescriptor,

  • ????????jboolean redirectErrorStream) {

  • ?

  • ????// Copy commands into char*[].

  • ????char** commands = convertStrings(env, javaCommands);

  • ?

  • ????// Extract working directory string.

  • ????constchar* workingDirectory = NULL;

  • ????if (javaWorkingDirectory != NULL) {

  • ????????workingDirectory = env->GetStringUTFChars(javaWorkingDirectory, NULL);

  • ????}

  • ?

  • ????// Convert environment array.

  • ????char** environment = convertStrings(env, javaEnvironment);

  • ?

  • ????//关键就这一行.

  • ????pid_t result = executeProcess(

  • ????????????env, commands, environment, workingDirectory,

  • ????????????inDescriptor, outDescriptor, errDescriptor, redirectErrorStream);

  • ?

  • ????// Temporarily clear exception so we can clean up.

  • ????jthrowable exception = env->ExceptionOccurred();

  • ????env->ExceptionClear();

  • ?

  • ????freeStrings(env, javaEnvironment, environment);

  • ?

  • ????// Clean up working directory string.

  • ????if (javaWorkingDirectory != NULL) {

  • ????????env->ReleaseStringUTFChars(javaWorkingDirectory, workingDirectory);

  • ????}

  • ?

  • ????freeStrings(env, javaCommands, commands);

  • ?

  • ????// Re-throw exception if present.

  • ????if (exception != NULL) {

  • ????????if (env->Throw(exception) < 0) {

  • ????????????LOGE("Error rethrowing exception!");

  • ????????}

  • ????}

  • ?

  • ????return result;

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


  • /** Executes a command in a child process. */

  • static pid_t executeProcess(JNIEnv* env, char** commands, char** environment,

  • ????????constchar* workingDirectory, jobject inDescriptor,

  • ????????jobject outDescriptor, jobject errDescriptor,

  • ????????jboolean redirectErrorStream) {

  • ????int i, result, error;

  • ?

  • ????// Create 4 pipes: stdin, stdout, stderr, and an exec() status pipe.

  • ????int pipes[PIPE_COUNT * 2] = { -1, -1, -1, -1, -1, -1, -1, -1 };

  • ????for (i = 0; i < PIPE_COUNT; i++) {

  • ????????if (pipe(pipes + i * 2) == -1) {

  • ????????????jniThrowIOException(env, errno);

  • ????????????closePipes(pipes, -1);

  • ????????????return -1;

  • ????????}

  • ????}

  • ????int stdinIn = pipes[0];

  • ????int stdinOut = pipes[1];

  • ????int stdoutIn = pipes[2];

  • ????int stdoutOut = pipes[3];

  • ????int stderrIn = pipes[4];

  • ????int stderrOut = pipes[5];

  • ????int statusIn = pipes[6];

  • ????int statusOut = pipes[7];

  • ?

  • ????pid_t childPid = fork();

  • ?

  • ????// If fork() failed...

  • ????if (childPid == -1) {

  • ????????jniThrowIOException(env, errno);

  • ????????closePipes(pipes, -1);

  • ????????return -1;

  • ????}

  • ?

  • ????// If this is the child process...

  • ????if (childPid == 0) {

  • ????????/*

  • ?????????* Note: We cannot malloc() or free() after this point!

  • ?????????* A no-longer-running thread may be holding on to the heap lock, and

  • ?????????* an attempt to malloc() or free() would result in deadlock.

  • ?????????*/

  • ?

  • ????????// Replace stdin, out, and err with pipes.

  • ????????dup2(stdinIn, 0);

  • ????????dup2(stdoutOut, 1);

  • ????????if (redirectErrorStream) {

  • ????????????dup2(stdoutOut, 2);

  • ????????} else {

  • ????????????dup2(stderrOut, 2);

  • ????????}

  • ?

  • ????????// Close all but statusOut. This saves some work in the next step.

  • ????????closePipes(pipes, statusOut);

  • ?

  • ????????// Make statusOut automatically close if execvp() succeeds.

  • ????????fcntl(statusOut, F_SETFD, FD_CLOEXEC);

  • ?

  • ????????// Close remaining open fds with the exception of statusOut.

  • ????????closeNonStandardFds(statusOut);

  • ?

  • ????????// Switch to working directory.

  • ????????if (workingDirectory != NULL) {

  • ????????????if (chdir(workingDirectory) == -1) {

  • ????????????????goto execFailed;

  • ????????????}

  • ????????}

  • ?

  • ????????// Set up environment.

  • ????????if (environment != NULL) {

  • ????????????environ = environment;

  • ????????}

  • ?

  • ????????// Execute process. By convention, the first argument in the arg array

  • ????????// should be the command itself. In fact, I get segfaults when this

  • ????????// isn't the case.

  • ????????execvp(commands[0], commands);

  • ?

  • ????????// If we got here, execvp() failed or the working dir was invalid.

  • ????????execFailed:

  • ????????????error = errno;

  • ????????????write(statusOut, &error, sizeof(int));

  • ????????????close(statusOut);

  • ????????????exit(error);

  • ????}

  • ?

  • ????// This is the parent process.

  • ?

  • ????// Close child's pipe ends.

  • ????close(stdinIn);

  • ????close(stdoutOut);

  • ????close(stderrOut);

  • ????close(statusOut);

  • ?

  • ????// Check status pipe for an error code. If execvp() succeeds, the other

  • ????// end of the pipe should automatically close, in which case, we'll read

  • ????// nothing.

  • ????int count = read(statusIn, &result, sizeof(int));

  • ????close(statusIn);

  • ????if (count > 0) {

  • ????????jniThrowIOException(env, result);

  • ?

  • ????????close(stdoutIn);

  • ????????close(stdinOut);

  • ????????close(stderrIn);

  • ?

  • ????????return -1;

  • ????}

  • ?

  • ????// Fill in file descriptor wrappers.

  • ????jniSetFileDescriptorOfFD(env, inDescriptor, stdoutIn);

  • ????jniSetFileDescriptorOfFD(env, outDescriptor, stdinOut);

  • ????jniSetFileDescriptorOfFD(env, errDescriptor, stderrIn);

  • ?

  • ????return childPid;

  • }
  至此,Runtime的exec就全部结束了。如果对下面的fork,execvp这2个函数不了解。建议看看APU。
  
  最后来看看ProcessBuilder类的实现:


  • /**

  • ?* Starts a new process based on the current state of this process builder.

  • ?*

  • ?* @return the new {@code Process} instance.

  • ?* @throws NullPointerException

  • ?* if any of the elements of {@link #command()} is {@code null}.

  • ?* @throws IndexOutOfBoundsException

  • ?* if {@link #command()} is empty.

  • ?* @throws SecurityException

  • ?* if {@link SecurityManager#checkExec(String)} doesn't allow

  • ?* process creation.

  • ?* @throws IOException

  • ?* if an I/O error happens.

  • ?*/

  • public Process start() throws IOException {

  • ????// BEGIN android-changed: push responsibility for argument checking into ProcessManager

  • ????String[] cmdArray = command.toArray(new String[command.size()]);

  • ????String[] envArray = new String[environment.size()];

  • ????int i = 0;

  • ????for (Map.Entry entry : environment.entrySet()) {

  • ????????envArray[i++] = entry.getKey() + "=" + entry.getValue(); //$NON-NLS-1$

  • ????}

  • ????//和Runtime.exec的一样。

  • ????return ProcessManager.getInstance().exec(cmdArray, envArray, directory, redirectErrorStream);

  • ????// END android-changed

  • }
  殊路同归!!!哈。
  
  
  
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-61584-1-1.html 上篇帖子: Hadoop FS Shell 下篇帖子: linux shell “(())” 双括号运算符使用
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表