【问题标题】:Java ADB shell returns nothingJava ADB shell 不返回任何内容
【发布时间】:2014-01-25 21:12:48
【问题描述】:

我想编写一个 java 程序来查找设备并列出其内容。为此,我首先通过 Java 的 Process 类触发“adb devices”并解析输出,它只适用于 finde。然后我想触发这个命令:

adb shell -s DEVICE-SERIAL /sdcard/

当我将它放入终端时,我得到了正确的输出,即 /sdcard/ 根目录下所有文件夹和文件的列表。

当我把它放到 Java 代码中时,什么都没有返回。然而,当您拼错 adb 命令时,Stderr 包含您获得的标准帮助页面。有趣的是:为了调试,我输出发送给 ADB 的每个命令。如果我运行我的程序并复制完全相同的生成命令并在我的终端中运行它,它就可以正常工作。

这是为什么呢?作为参考,这是我的代码摘录:

ADB.java:

public static String runShellCommand(Device d, String command) {
    return runCommand(d, "shell " + command);
}

public static String runCommand(Device d, String command) {
    Runtime runtime = Runtime.getRuntime();
    String full = "";
    String error = "";

    try {
        if (d != null) {
            command = "-s " + d.getSerial() + " " + command;
        }

        System.out.println("Running command: adb " + command);
        Process process = runtime.exec(new String[] {ADB_LOCATION, command});

            process.waitFor();

        BufferedReader stdin = new BufferedReader(new InputStreamReader(process.getInputStream()));
        BufferedReader errin = new BufferedReader(new InputStreamReader(process.getErrorStream()));

        String line;

        while ((line = stdin.readLine()) != null) {
            full += line;
        }

        while ((line = errin.readLine()) != null) {
            error += line;
        }

        if (!error.isEmpty()) {
            System.err.println("\n=== ADB reports: ===");
            System.err.println(error);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } catch (InterruptedException e) {
        System.out.println("App was overenthuasiastic. Couldn't wait for thread to finish.");
    }

    return full;
}

Device.java:

public ArrayList<Folder> getFoldersInDirectory(String dir) {
    String[] list = ls(dir);

    for (String s: list) {
        System.out.println(s);
        System.out.println(isFolderOrFile(dir + s));
    }

    // Just for debugging, gets completed once this runs.
    return null;
}

protected String[] ls(String dir) {
    String result = ADB.runShellCommand(this, "ls " + dir);
    System.out.println(result);

    return result.split("\n");
}

正如我之前所说,所有其他命令都运行良好(我测试了设备、get-state、get-serialno)。

输出:

【问题讨论】:

  • ADB.runShellCommand() 在您的ADB.java sn-p 中丢失
  • runShellCommand 基本上只是调用 runCommand 并将“shell”放在它前面,但我会发布它。

标签: java android shell process adb


【解决方案1】:

runtime.exec() 的参数错误。当你应该使用{'adb', '-s', 'xxxx', 'shell', 'ls /sdcard/'}时,你正在使用{'adb', '-s xxxx shell "ls /sdcard/"'}

【讨论】:

  • 出于调试目的,我只是手动编写了它,但它也不起作用。还是没有输出。这一次,stderr 也是空的。
  • 空的/sdcard 文件夹?
  • 不,已填满。我偶然发现了一个解决方案,我会在稍后发布它。
【解决方案2】:

对于 OP 来说可能有点太晚了,但可能对后来的观众有用。

最近我不得不集成一个系统以通过 adb 与真实设备紧密协作。花了一些时间来弄清楚如何“正确”地做到这一点。然后我想创建一个库来处理至少一些基本的 adb 命令(adb devices、shell、pull、push、install)。它可以在本地机器上执行 adb,也可以在远程机器上通过 ssh(带有密钥交换设置)使用相同的 API。不要与 adb shell 转发混淆;)。

它在 apache 2.0 许可下: https://github.com/lesavsoftware/rem-adb-exec

【讨论】:

    【解决方案3】:

    感谢 Alex P。我找到了一个可行的解决方案(尽管需要解析输出,但这是另一回事):

    我刚刚修改了 runCommand() 以将参数放在一个字符串数组中并将其提供给 exec:

    public static String runCommand(Device d, String command) {
            Runtime runtime = Runtime.getRuntime();
            String full = "";
            String error = "";
    
            try {
                String[] cmdWithDevice = new String[5];
                String[] cmdWithoutDevice = new String[2];
    
                if (d != null) {
                    cmdWithDevice[0] = ADB_LOCATION;
                    cmdWithDevice[1] = "-s";
                    cmdWithDevice[2] = d.getSerial();
                    cmdWithDevice[3] = "shell";
                    cmdWithDevice[4] = command;
    
                    command = "-s " + d.getSerial() + " " + command;
                } else {
                    cmdWithoutDevice[0] = ADB_LOCATION;
                    cmdWithoutDevice[1] = command;
                }
    
                System.out.println("Running command: adb " + command);
                // Process process = runtime.exec(new String[] {ADB_LOCATION, command});
                Process process = runtime.exec(cmdWithDevice[0] == null ? cmdWithoutDevice : cmdWithDevice);
    
                BufferedReader stdin = new BufferedReader(new InputStreamReader(process.getInputStream()));
                BufferedReader errin = new BufferedReader(new InputStreamReader(process.getErrorStream()));
    
                process.waitFor();
    
                String line;
    
                while ((line = stdin.readLine()) != null) {
                    full += line;
                }
    
                while ((line = errin.readLine()) != null) {
                    error += line;
                }
    
                if (!error.isEmpty()) {
                    System.err.println("\n=== ADB reports: ===");
                    System.err.println(error);
                }
    
                stdin.close();
                errin.close();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                System.out.println("App was overenthuasiastic. Couldn't wait for thread to finish.");
            }
    
            return full;
        }
    

    由于某种原因,如果我使用传入的参数手动运行 runtime.exec,仅以编程方式运行,它将不起作用。

    不过,这个解决方案有点老套,需要适当的实施。此解决方案还假定每个特定于设备的命令都是针对 shell 的。

    【讨论】:

      猜你喜欢
      • 2020-12-23
      • 1970-01-01
      • 2017-11-25
      • 2013-05-04
      • 1970-01-01
      • 1970-01-01
      • 2020-04-27
      • 2019-04-06
      • 2012-02-15
      相关资源
      最近更新 更多