【问题标题】:Android - Interactive shell (Runtime.getRuntime().exec())Android - 交互式外壳 (Runtime.getRuntime().exec())
【发布时间】:2015-09-26 13:58:35
【问题描述】:

如何在 android 上运行交互式 shell? (根设备)

我需要接下来的步骤:

1 - 执行 shell 进程(onCreate)

Process p = Runtime.getRuntime().exec(String[]{"su","-c","sh"});

2 - 获取输出 (onCreate)

BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream));
//dos is a field (a class attribute)
dos = new DataOutputStream(p.getOutputStream());
new Thread(new Runnable() {

    @Override
    public void run() {
         String l;
         //wait the console output and write it
         while((l = br.readLine()) != null) {
              Log.v("info", l);
         }
    }
}).start();

3 - 执行命令 (Button -> onClick())

cmd("wpa_cli");

cmd方法是:

public void cmd(String cmd) {
   dos.writeBytes(cmd + "\n");
   dos.flush();
}

日志从不显示控制台输出。

下一步:

4 - 获取 wpa_cli 子命令的输出(另一个 Button -> onClick())

cmd("help");

应该显示 wpa_cli 帮助,但它不起作用。
如果我多次按下按钮出现不完整的输出(帮助)

在创建 Activity 并使其保持活动状态以进行交互时,初始化进程的正确方法是什么?

谢谢。

邮政数据
我换了行Log.v("info", l);

fos.write(l);
Message msg = handlerTest.obtainMessage();
msg.obj = l;
handlerTest.sendMessage(msg);

fos -> FileOutputStream 对象

Handler handlerTest = new Handler() {
    @Override
    handleMessage(Message msg) {
       if (msg != null) {
         //alert... (String)msg.obj;
       }
    }
}; 

并且只显示来自直接命令的警报,例如help。命令status 仅在流关闭时有效。 (执行cmd("quit");cmd("exit");后)

我不明白。标准输出不止一个?我可以在不关闭流的情况下与输出交互吗?

使用adb shell,我读取了输出文件(在关闭流后创建),它就完成了。

PostData2:

问题是缓冲区。在二进制文件(已执行)输出和 java 进程之间,我可以在不使用本机 I/O 的情况下禁用缓冲区吗? Android Terminal Emulator 工作正常,是用 NIO 吗?

【问题讨论】:

  • 看看这篇文章 - 特别是它谈论刷新和重定向任何它与操作系统的不同之处:javaworld.com/article/2071275/core-java/…
  • 非常感谢@Mick 的帮助。
  • @Mick 在所有示例中都预期进程结束。就我而言,它是不确定的;我需要在流程结束之前从流程中接收数据。 (与之交互)我认为它一定是一些带有 Channel 的 PipedInputStream 和 PipedOutputStream。我一直在寻找更多信息。

标签: android shell process bufferedreader interactive


【解决方案1】:

OP 的解决方案。

没有在Android中使用stdbuf(coreutils的)工具,我找到了下一个解决方案:

我正在使用两个名为 process1 和 process2 的进程:都 -> new ProcessBuilder(new String[]{"su", "-c", "sh"}).start();

在我运行wpa_cli的第一个进程中

dos1.write("wpa_cli".getBytes());
dos1.flush();

在一个线程中,我等待 5 秒,然后在第二个进程中运行 wpa_cli。

dos2.write("wpa_cli".getBytes());
dos2.flush();

要从 wpa_cli 获取输出,必须使用 quit 关闭它

dos1.write("quit".getBytes());
dos1.flush();

与两个进程一起工作的主线程:

new Thread(new Runnable() {
                @Override
                public void run() {
                    boolean firstProcess = true;
                    while (follow) {
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        if (follow) {
                            if (firstProcess) {
                                cmd("wpa_cli", dos2);
                                cmd("quit", dos1);
                            } else {
                                cmd("wpa_cli", dos1);
                                cmd("quit", dos2);
                            }
                            firstProcess = !firstProcess;
                        }
                    }
                }
            }).start();

重要:两个进程都有这个(当创建进程时):

new Thread(new Runnable() {
                    @Override
                    public void run() {
                        BufferedReader br = new BufferedReader(new InputStreamReader(process1.getInputStream()));
                        String l;
                        try {
                            Message msg;
                            while ((l = br.readLine()) != null) {
                                msg = handlerStdout.obtainMessage();
                                msg.obj = l;
                                handlerStdout.sendMessage(msg);
                            }

                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();

处理程序handlerStdout 执行所需的工作。它每 5 秒接收一次wpa_cli 的输出:输出来自 process1 和 process2 交替


另一种解决方案是为 Android 编译 coreutils 或 stdbuf。或者从http://forum.xda-developers.com/showthread.php?t=2613243 安装已编译的coreutils(对我来说,stdbuf 不起作用,因为找不到libstdbuf.so

使用stdbuf -oL wpa_cli,输出不会被缓冲(缓冲一行)。没有它,输出将被缓冲(4k)。

【讨论】:

  • 我不明白 StackOverflow 的工作原理。这是我的答案。
  • @VasileM 你把你的答案放在你自己的问题中。由于这不是获得解决方案的正确方法,因此我将其从您的问题中移开,并将其放在自己的答案中,@ 987654322@。我把它做成了一个社区 wiki,但如果你喜欢在你的帐户下发布它,请随意这样做,然后快速告诉我,以便我可以删除社区 wiki 帖子。您也可以从修订历史记录中获得the source code of the post
  • @VasileM 或者,您可以简单地接受这个社区 wiki 帖子(带有绿色复选标记)。
猜你喜欢
  • 2018-07-11
  • 2016-04-16
  • 1970-01-01
  • 1970-01-01
  • 2015-04-27
  • 2014-01-11
  • 1970-01-01
  • 2021-09-28
  • 2013-04-28
相关资源
最近更新 更多