1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.sdklib.util; 18 19 import com.android.annotations.NonNull; 20 import com.android.annotations.Nullable; 21 22 import java.io.BufferedReader; 23 import java.io.IOException; 24 import java.io.InputStreamReader; 25 26 public class GrabProcessOutput { 27 28 public enum Wait { 29 /** 30 * Doesn't wait for the exec to complete. 31 * This still monitors the output but does not wait for the process to finish. 32 * In this mode the process return code is unknown and always 0. 33 */ 34 ASYNC, 35 /** 36 * This waits for the process to finish. 37 * In this mode, {@link GrabProcessOutput#grabProcessOutput} returns the 38 * error code from the process. 39 * In some rare cases and depending on the OS, the process might not have 40 * finished dumping data into stdout/stderr. 41 * <p/> 42 * Use this when you don't particularly care for the output but instead 43 * care for the return code of the executed process. 44 */ 45 WAIT_FOR_PROCESS, 46 /** 47 * This waits for the process to finish <em>and</em> for the stdout/stderr 48 * threads to complete. 49 * In this mode, {@link GrabProcessOutput#grabProcessOutput} returns the 50 * error code from the process. 51 * <p/> 52 * Use this one when capturing all the output from the process is important. 53 */ 54 WAIT_FOR_READERS, 55 } 56 57 public interface IProcessOutput { 58 /** 59 * Processes an stdout message line. 60 * @param line The stdout message line. Null when the reader reached the end of stdout. 61 */ 62 public void out(@Nullable String line); 63 /** 64 * Processes an stderr message line. 65 * @param line The stderr message line. Null when the reader reached the end of stderr. 66 */ 67 public void err(@Nullable String line); 68 } 69 70 /** 71 * Get the stderr/stdout outputs of a process and return when the process is done. 72 * Both <b>must</b> be read or the process will block on windows. 73 * 74 * @param process The process to get the ouput from. 75 * @param output Optional object to capture stdout/stderr. 76 * Note that on Windows capturing the output is not optional. If output is null 77 * the stdout/stderr will be captured and discarded. 78 * @param waitMode Whether to wait for the process and/or the readers to finish. 79 * @return the process return code. 80 * @throws InterruptedException if {@link Process#waitFor()} was interrupted. 81 */ 82 public static int grabProcessOutput( 83 @NonNull final Process process, 84 Wait waitMode, 85 @Nullable final IProcessOutput output) throws InterruptedException { 86 // read the lines as they come. if null is returned, it's 87 // because the process finished 88 Thread threadErr = new Thread("stderr") { 89 @Override 90 public void run() { 91 // create a buffer to read the stderr output 92 InputStreamReader is = new InputStreamReader(process.getErrorStream()); 93 BufferedReader errReader = new BufferedReader(is); 94 95 try { 96 while (true) { 97 String line = errReader.readLine(); 98 if (output != null) { 99 output.err(line); 100 } 101 if (line == null) { 102 break; 103 } 104 } 105 } catch (IOException e) { 106 // do nothing. 107 } 108 } 109 }; 110 111 Thread threadOut = new Thread("stdout") { 112 @Override 113 public void run() { 114 InputStreamReader is = new InputStreamReader(process.getInputStream()); 115 BufferedReader outReader = new BufferedReader(is); 116 117 try { 118 while (true) { 119 String line = outReader.readLine(); 120 if (output != null) { 121 output.out(line); 122 } 123 if (line == null) { 124 break; 125 } 126 } 127 } catch (IOException e) { 128 // do nothing. 129 } 130 } 131 }; 132 133 threadErr.start(); 134 threadOut.start(); 135 136 if (waitMode == Wait.ASYNC) { 137 return 0; 138 } 139 140 // it looks like on windows process#waitFor() can return 141 // before the thread have filled the arrays, so we wait for both threads and the 142 // process itself. 143 if (waitMode == Wait.WAIT_FOR_READERS) { 144 try { 145 threadErr.join(); 146 } catch (InterruptedException e) { 147 } 148 try { 149 threadOut.join(); 150 } catch (InterruptedException e) { 151 } 152 } 153 154 // get the return code from the process 155 return process.waitFor(); 156 } 157 } 158