Ubuntu 19.10下Java如何实时读取终端持续输出以监控Android设备?
Hey there! I've run into exactly this issue when working with adb commands from Java, so I can help you out—you don't need Socket connections at all. The problem is how Java handles the output streams of the spawned process, not any "terminal locking."
First, let's break down the root cause: Java's Process class buffers standard output and error streams separately. If you only read one stream (e.g., stdout) and ignore the other, the unread stream's buffer will fill up eventually, blocking the child process (like tcpdump or logcat) from producing more output until the buffer is emptied. That's why you only get all output once you kill the process—all buffered data gets flushed at termination.
Step 1: Use a Stream Gobbler Thread
The fix is to read both stdout and stderr in separate dedicated threads. Here's a reusable StreamGobbler class that handles real-time output processing:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; public class StreamGobbler implements Runnable { private InputStream inputStream; private String streamType; private OutputHandler handler; public interface OutputHandler { void onOutput(String line); } public StreamGobbler(InputStream inputStream, String streamType, OutputHandler handler) { this.inputStream = inputStream; this.streamType = streamType; this.handler = handler; } @Override public void run() { try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { String line; while ((line = reader.readLine()) != null) { // Pass each line to your custom handler for real-time validation/logging handler.onOutput(String.format("[%s] %s", streamType, line)); } } catch (IOException e) { e.printStackTrace(); } } }
Step 2: Spawn the Process and Start Gobblers
Use ProcessBuilder (preferred over Runtime.exec() for better control) to launch your terminal command, then start the gobbler threads for both streams. Here's an example for adb logcat:
public class CommandRunner { public static void main(String[] args) throws IOException, InterruptedException { // Example: Launch adb logcat to monitor Android device logs ProcessBuilder pb = new ProcessBuilder("adb", "logcat"); // Optional: Merge stderr into stdout if you don't need to distinguish error output // pb.redirectErrorStream(true); Process process = pb.start(); // Define handlers for real-time output processing StreamGobbler.OutputHandler stdoutHandler = line -> { // Replace this with your validation logic (e.g., check for specific log messages) System.out.println(line); }; StreamGobbler.OutputHandler stderrHandler = line -> { // Handle errors like adb connection failures System.err.println(line); }; // Start gobbler threads to read streams in parallel new Thread(new StreamGobbler(process.getInputStream(), "STDOUT", stdoutHandler)).start(); new Thread(new StreamGobbler(process.getErrorStream(), "STDERR", stderrHandler)).start(); // To stop the command programmatically (simulate Ctrl+C): // process.destroy(); // Sends SIGTERM; for graceful shutdown (e.g., tcpdump), use: // Runtime.getRuntime().exec("kill -INT " + process.pid()); } }
Key Tips for Your Ubuntu/IntelliJ Setup
- Avoid
Runtime.exec():ProcessBuildergives you finer control over environment variables and stream handling, which is critical for long-running commands. - Ubuntu Permissions: Ensure your user can run
adbortcpdumpwithout sudo:- For adb: Add yourself to the
plugdevgroup withsudo usermod -aG plugdev $USER - For tcpdump: Grant raw network access with
sudo setcap cap_net_raw,cap_net_admin=eip /usr/sbin/tcpdump
- For adb: Add yourself to the
- Graceful Shutdown: If you need to stop
tcpdumpproperly (to avoid corrupt capture files), send aSIGINTsignal instead of usingprocess.destroy().
Why Socket Isn't Needed
Socket connections are for network or isolated inter-process communication. In this case, you're spawning a local child process, so using the process's built-in input/output streams is the correct, efficient approach. Adding a Socket would only introduce unnecessary complexity.
内容的提问来源于stack exchange,提问作者Eyal

