1 /*
2  * Copyright (C) 2018 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 package com.android.dumpviewer.utils;
17 
18 import android.util.Log;
19 
20 import com.android.dumpviewer.DumpActivity;
21 
22 import java.io.BufferedReader;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.InputStreamReader;
26 import java.util.ArrayList;
27 import java.util.concurrent.TimeUnit;
28 import java.util.concurrent.atomic.AtomicReference;
29 import java.util.function.Consumer;
30 
31 public class Exec {
32     public static final String TAG = DumpActivity.TAG;
33 
Exec()34     private Exec() {
35     }
36 
runForStream( String commandLine, Consumer<String> messenger, Runnable onCanceled, Consumer<Exception> onException, int timeoutSeconds )37     public static InputStream runForStream(
38             String commandLine,
39             Consumer<String> messenger,
40             Runnable onCanceled,
41             Consumer<Exception> onException,
42             int timeoutSeconds
43             )
44             throws IOException {
45         messenger.accept("Running: " + commandLine);
46         Log.v(TAG, "Running: " + commandLine);
47 
48         final Process p = Runtime.getRuntime().exec(
49                 new String[]{"/system/bin/sh", "-c", commandLine});
50         final InputStream in = p.getInputStream();
51 
52         final AtomicReference<Throwable> th = new AtomicReference<>();
53         new Thread(() -> {
54             try {
55                 Log.v(TAG, "Waiting for process: " + p);
56                 final boolean success = p.waitFor(timeoutSeconds, TimeUnit.SECONDS);
57                 if (success) {
58                     Log.v(TAG, String.format("Command %s finished with code %d", commandLine,
59                             p.exitValue()));
60                 } else {
61                     messenger.accept(String.format("Command %s timed out", commandLine));
62                     onCanceled.run();
63                     try {
64                         p.destroyForcibly();
65                         in.close();
66                     } catch (Exception ignore) {
67                     }
68                 }
69             } catch (Exception e) {
70                 th.set(e);
71             }
72         }).start();
73 
74         return in;
75     }
76 
runForStrings( String commandLine, Consumer<String> messenger, Runnable onCanceled, Consumer<Exception> onException, int timeoutSeconds)77     public static String[] runForStrings(
78             String commandLine,
79             Consumer<String> messenger,
80             Runnable onCanceled,
81             Consumer<Exception> onException,
82             int timeoutSeconds)
83             throws IOException {
84         final ArrayList<String> ret = new ArrayList<>(128);
85         try (BufferedReader rd = new BufferedReader(new InputStreamReader(
86                 runForStream(commandLine, messenger, onCanceled, onException, timeoutSeconds)))) {
87             while (true) {
88                 String line = rd.readLine();
89                 if (line == null) {
90                     break;
91                 }
92                 ret.add(line);
93             }
94         }
95         return ret.toArray(new String[ret.size()]);
96     }
97 }
98