0

android start-serverJava 内から外部プロセスとして実行しようとすると、さまざまな問題が発生します。Java は Gradle によって呼び出されます。さまざまなシナリオで正確に何が起こっているかを説明しましょう。

環境

  • ウィンドウズ 7 X64
  • Java 7
  • commons-exec-1.1
  • グラドル 1.6
  • Android API 17
  • IntelliJ IDEA 12.1.4 コミュニティ版


を呼び出すと adb デーモンが強制終了され、起動されると仮定adb start-serverします。

ケース1

このコード:

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

runアプリケーション プラグインのGradle タスクから実行すると、次のような start-server 出力が表示されます。

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

そしてハングします。つまり、「Checkpoint!」です。ログに記録されることはありません。プロセスadb.exeを手動で強制終了すると、コードの実行が続行されます。

質問1

この呼び出しがブロックされる理由 コマンドが端末から実行されるとadb start-server、数秒後に制御が端末に返されるのに、コードでそれが起こらないのはなぜですか?

ケース 2

代わりに、次のように Java ランタイムを直接使用する場合:

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

以前のように Gradle から呼び出す場合、「Checkpoint!」記録されます。ただし、実行は保留されSystem.exit(0)ます。手動adb.exeで強制終了すると、再び Gradle 呼び出しが終了します。

この場合、 の出力adb start-serverは表示されません。

興味深いことに、Gradle の代わりに、Gradle のものを模倣したビルド設定で IntelliJ IDEA からアプリケーションを実行すると、すべてが正常に機能し、アプリケーションが正常に終了します。

質問2

Gradle がハングアップしSystem.exit(0)、IntelliJ がハングアップしないのはなぜですか? これは、Gradle 自体が内部的に Java を呼び出すプロセスであり、IntelliJ の場合、Java が間接的に直接呼び出されるという事実と何らかの関係がありますか? なぜそれが重要なのですか?

質問 3

最終的には、これを Gradle からハングアップすることなく実行できるようにしたいと考えています。のログ出力はadb start-serverおまけです。これを行う方法のヒントをいただければ幸いです。

4

2 に答える 2

0

最終的に、次のことを行うことで問題を解決しました。

  1. プログラム内では、 を呼び出すために、 Java の もadb start-server使用しなくなりました。 代わりに、 を使用します。は Java 7 で追加され、開始されたプロセスの stdout などをオンラインで読み取ることができることに注意してください。編集IntelliJ IDEA によって呼び出されるのではなく、Gradle が CLI から直接呼び出された場合、Gradle 内は効果がありません。詳細については、この質問を参照してください。おそらくここで説明されているように実装すると、問題が解決するでしょう。org.apache.commons.exec.DefaultExecutor.execute("adb start-server")Runtime.getRuntime().exec("adb start-server")
    java.lang.ProcessBuilder("adb start-server").inheritIO().start().waitFor()inheritIO()
    inheritIO()StreamGobbler

  2. Gradle では、Gradle のアプリケーション プラグインrunタスクの代わりに、再びタスク変数をProcessBuilder再利用します。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();
        }
    }

挙動不審の理由については、明確な答えがありませんので、これ以上のコメントは差し控えさせていただきます。

編集 2013 年 7 月 9 日
この質問は、質問 2 に対する答えを指摘しているようです: Windows では、親プロセスは終了する前に子プロセスを待ちます。残念ながら、そこで提案された解決策は、質問 1 で述べた問題のために機能しません。

これが役に立てば幸いです、
コンラッド

于 2013-06-25T17:50:18.463 に答える