• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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          */
out(@ullable String line)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          */
err(@ullable String line)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      */
grabProcessOutput( @onNull final Process process, Wait waitMode, @Nullable final IProcessOutput output)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