Java ADB shell什么都不返回

时间:2014-01-07 23:43:00

标签: java android shell process adb

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

adb shell -s DEVICE-SERIAL /sdcard/

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

当我把它放入Java代码时,不会返回任何内容。但是,Stderr包含拼写adb命令时获得的标准帮助页面。这是有趣的事情:对于调试我输出发送到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)。

输出: Outputs

3 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分:1)

runtime.exec()的参数错误。当您使用{'adb', '-s xxxx shell "ls /sdcard/"'}

时,您正在使用{'adb', '-s', 'xxxx', 'shell', 'ls /sdcard/'}

答案 2 :(得分:1)

感谢Alex P.我找到了一个有效的解决方案(但需要解析输出,但这是一个不同的故事):

我刚刚修改了runCommand()以将参数放在String-array中并将其赋予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,它只能以编程方式运行。

这个解决方案有点hacky,但需要正确实施。此解决方案还假设每个特定于设备的命令都适用于shell。