【问题标题】:"adb start-server", Java, Gradle and apache-commons-exec: how to make it right?“adb start-server”、Java、Gradle 和 apache-commons-exec:如何使其正确?
【发布时间】:2013-06-24 18:08:12
【问题描述】:

我在尝试从 Java 中将 android start-server 作为外部进程运行时遇到了各种问题。 Java 由 Gradle 调用。让我向您描述一下在各种情况下到底发生了什么:

环境

  • Windows 7 X64
  • Java 7
  • commons-exec-1.1
  • Gradle 1.6
  • Android API 17
  • IntelliJ IDEA 12.1.4 社区版

假设
adb 守护进程被杀死并在调用adb start-server 时启动。

案例一

这段代码:

DefaultExecutor executor = new org.apache.commons.exec.DefaultExecutor();
executor.execute(org.apache.commons.exec.CommandLine.parse("adb start-server"));
log.info("Checkpoint!");

从应用插件的 Gradle run 任务运行时,将显示启动服务器输出,即:

* daemon not running. starting it now on port 5037 *
* daemon started successfully *

然后它将挂起,即“检查点!”永远不会被记录。手动杀死adb.exe 进程会导致代码继续执行。

问题 1

为什么这个调用会阻塞?从终端运行adb start-server 命令时,几秒钟后控制权返回到终端,那为什么代码中没有发生呢?

案例 2

如果我像这样直接使用 Java 运行时:

Runtime.getRuntime().exec(new String[]{"adb", "start-server"});
log.info("Checkpoint!");
System.exit(0);

如果像以前一样从 Gradle 调用,“检查点!”将被记录。但是,执行将在System.exit(0) 上挂起。手动杀死 adb.exe 将再次使 Gradle 调用完成。

在这种情况下,不会显示adb start-server 的输出。

有趣的是,当我从 IntelliJ IDEA 运行应用程序而不是 Gradle 时,使用模仿 Gradle 的构建设置运行应用程序时,一切正常并且应用程序正常完成。

问题 2

为什么 Gradle 挂在 System.exit(0) 而 IntelliJ 没有?这是否与 Gradle 本身是一个内部调用 Java 的进程以及在 IntelliJ 的情况下,Java 被立即调用而没有任何间接的事实有关?为什么重要?

问题 3

最终,我希望能够从 Gradle 运行它而不会出现任何挂起。 adb start-server 的日志输出将是一个奖励。我将不胜感激任何提示如何做到这一点。

【问题讨论】:

    标签: java gradle adb apache-commons-exec


    【解决方案1】:

    如果我回答错了问题,请原谅我,但如果我想从 gradle 启动服务器(我们正在为 tomcat、sonicMQ、ApacheDS 和 EnterpriseDB 执行此操作),我将从 gradle Exec 任务开始,并且只如果不够,请尝试其他方法。

    task startADB(type: Exec) {
        commandLine 'adb', 'start-server'
    }
    

    很遗憾,我无法回答您关于各种代码挂起的任何问题,因为我一无所知!我只知道如果我想从 gradle 启动服务器,我会这样做。事实上,我就是这样做的。另一个稍微复杂一点的选项是使用the tanuki wrapper 或类似的东西。您仍然可以从 gradle 启动和停止它,但您可以获得一些高级功能。

    【讨论】:

    • 谢谢!我实际上正在考虑从外部启动 adb 以规避我遇到的所有问题。目前我认为 Gradle 挂起是因为 应用程序插件 的“运行”任务在流缓冲as described here 方面存在问题(我偷看了源代码)。也许出于同样的原因 commons-exec 挂起。我继续调查...
    • tanuki 包装器允许您将任何东西作为服务安装(在 Windows 和 linux 中),并且它可以在不挂起的情况下更好地启动。 gradle Exec 变成一个简单的“net start”或“/etc/init.d/foo start”。
    • 我检查了:Gradle 的 Exec 任务也挂在 System.exit(0) 上。但是,此命令可以正常工作:new ProcessBuilder("adb", "start-server").inheritIO().start(); 它不会在任何配置中挂起并显示输出。
    【解决方案2】:

    最终我通过以下方式解决了这个问题:

    1. 在我的程序中,为了调用adb start-server,我不再使用org.apache.commons.exec.DefaultExecutor.execute("adb start-server"),也不再使用Java 的Runtime.getRuntime().exec("adb start-server")。
      相反,我使用java.lang.ProcessBuilder("adb start-server").inheritIO().start().waitFor()。请注意,inheritIO() 是在 Java 7 中添加的,它允许在线读取已启动的进程标准输出等。
      编辑从 CLI 调用 Gradle 时,Gradle 中的 inheritIO() 无效直接而不是被 IntelliJ IDEA 调用。有关详细信息,请参阅this question。 可能按照here 的描述实现StreamGobbler 可以解决问题。

    2. 在 Gradle 中,我再次使用 ProcessBuilder 重用 run 任务变量,而不是 Gradle 的 application plugin 的 run 任务。看起来是这样的:

    apply plugin: 'java'
    apply plugin: 'application'
    
    sourceCompatibility = '1.7'
    targetCompatibility = '1.7'
    
    // configuration-time of the original run task
    run { 
        main = com.example.MainClass; // without this, our custom run will try to run "null"
    }
    
    task myRun(dependsOn: build) {
    
            // execution-time of our custom run task.
            doFirst {
    
                ProcessBuilder pb = new ProcessBuilder(tasks['run'].commandLine);
                pb.directory(tasks['run'].workingDir);
    
                // works when the gradle command is executed from IntelliJ IDEA, has no effect when executed from standalone CLI interface.
                pb.inheritIO(); 
    
                Process proc = pb.start();
                proc.waitFor();
            }
        }
    

    至于奇怪行为的原因,我没有明确的答案,所以我避免进一步的cmets。

    编辑 2013 年 7 月 9 日
    This question 似乎指出问题 2 的答案是:在 Windows 上,父进程在终止之前等待子进程。不幸的是,由于问题 1 中所述的问题,那里提出的解决方案不起作用。

    希望这会有所帮助,
    康拉德

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-02
      • 1970-01-01
      相关资源
      最近更新 更多