From 3c7a6d363ede7806530c99621b4b1cf4bc7da3ed Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Wed, 1 Nov 2023 00:31:33 +0100 Subject: [PATCH] Disable default stdout/stderr for Xiaomi devices Xiaomi device ROMs print internal errors using e.printStackTRace(), flooding the console with irrelevant errors. To get rid of them, on Xiaomi devices, trash the messages printed to the console by direct calls to System.out and System.err. Refs #994 Refs #4213 --- .../main/java/com/genymobile/scrcpy/Ln.java | 41 ++++++++++---- .../com/genymobile/scrcpy/Workarounds.java | 56 +++++++++++++++++++ 2 files changed, 86 insertions(+), 11 deletions(-) diff --git a/server/src/main/java/com/genymobile/scrcpy/Ln.java b/server/src/main/java/com/genymobile/scrcpy/Ln.java index 199c29be..564901b4 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Ln.java +++ b/server/src/main/java/com/genymobile/scrcpy/Ln.java @@ -8,6 +8,11 @@ import android.util.Log; */ public final class Ln { + public interface ConsolePrinter { + void printOut(String message); + void printErr(String message, Throwable throwable); + } + private static final String TAG = "scrcpy"; private static final String PREFIX = "[server] "; @@ -15,12 +20,17 @@ public final class Ln { VERBOSE, DEBUG, INFO, WARN, ERROR } + private static ConsolePrinter consolePrinter = new DefaultConsolePrinter(); private static Level threshold = Level.INFO; private Ln() { // not instantiable } + public static void setConsolePrinter(ConsolePrinter consolePrinter) { + Ln.consolePrinter = consolePrinter; + } + /** * Initialize the log level. *

@@ -39,31 +49,28 @@ public final class Ln { public static void v(String message) { if (isEnabled(Level.VERBOSE)) { Log.v(TAG, message); - System.out.print(PREFIX + "VERBOSE: " + message + '\n'); + consolePrinter.printOut(PREFIX + "VERBOSE: " + message + '\n'); } } public static void d(String message) { if (isEnabled(Level.DEBUG)) { Log.d(TAG, message); - System.out.print(PREFIX + "DEBUG: " + message + '\n'); + consolePrinter.printOut(PREFIX + "DEBUG: " + message + '\n'); } } public static void i(String message) { if (isEnabled(Level.INFO)) { Log.i(TAG, message); - System.out.print(PREFIX + "INFO: " + message + '\n'); + consolePrinter.printOut(PREFIX + "INFO: " + message + '\n'); } } public static void w(String message, Throwable throwable) { if (isEnabled(Level.WARN)) { Log.w(TAG, message, throwable); - System.err.print(PREFIX + "WARN: " + message + '\n'); - if (throwable != null) { - throwable.printStackTrace(); - } + consolePrinter.printErr(PREFIX + "WARN: " + message + '\n', throwable); } } @@ -74,14 +81,26 @@ public final class Ln { public static void e(String message, Throwable throwable) { if (isEnabled(Level.ERROR)) { Log.e(TAG, message, throwable); - System.err.print(PREFIX + "ERROR: " + message + "\n"); - if (throwable != null) { - throwable.printStackTrace(); - } + consolePrinter.printErr(PREFIX + "ERROR: " + message + '\n', throwable); } } public static void e(String message) { e(message, null); } + + public static class DefaultConsolePrinter implements ConsolePrinter { + @Override + public void printOut(String message) { + System.out.print(message); + } + + @Override + public void printErr(String message, Throwable throwable) { + System.err.print(message); + if (throwable != null) { + throwable.printStackTrace(); + } + } + } } diff --git a/server/src/main/java/com/genymobile/scrcpy/Workarounds.java b/server/src/main/java/com/genymobile/scrcpy/Workarounds.java index b8ee68ca..4fbe5962 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Workarounds.java +++ b/server/src/main/java/com/genymobile/scrcpy/Workarounds.java @@ -14,6 +14,12 @@ import android.os.Build; import android.os.Looper; import android.os.Parcel; +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringWriter; import java.lang.ref.WeakReference; import java.lang.reflect.Constructor; import java.lang.reflect.Field; @@ -55,6 +61,12 @@ public final class Workarounds { mustFillAppInfo = true; mustFillBaseContext = true; mustFillAppContext = true; + } else if (Build.MANUFACTURER.equalsIgnoreCase("xiaomi")) { + // Trash the messages printed to the console by direct calls to System.out and System.err. + // Xiaomi device ROMs may print internal errors using e.printStackTrace(), flooding the console with irrelevant errors. + ExclusiveConsolePrinter exclusiveConsolePrinter = new ExclusiveConsolePrinter(); + exclusiveConsolePrinter.installNullSystemStreams(); + Ln.setConsolePrinter(new ExclusiveConsolePrinter()); } if (audio && Build.VERSION.SDK_INT == Build.VERSION_CODES.R) { @@ -306,4 +318,48 @@ public final class Workarounds { throw new RuntimeException("Cannot create AudioRecord"); } } + + static class ExclusiveConsolePrinter implements Ln.ConsolePrinter { + + static class NullOutputStream extends OutputStream { + @Override + public void write(byte[] b) { + // ignore + } + + @Override + public void write(byte[] b, int off, int len) { + // ignore + } + + @Override + public void write(int b) { + // ignore + } + } + + private final PrintStream realOut = new PrintStream(new FileOutputStream(FileDescriptor.out)); + private final PrintStream realErr = new PrintStream(new FileOutputStream(FileDescriptor.err)); + + void installNullSystemStreams() { + PrintStream nullStream = new PrintStream(new NullOutputStream()); + System.setOut(nullStream); + System.setErr(nullStream); + } + + @Override + public void printOut(String message) { + realOut.print(message); + } + + @Override + public void printErr(String message, Throwable throwable) { + realErr.print(message); + if (throwable != null) { + StringWriter errors = new StringWriter(); + throwable.printStackTrace(new PrintWriter(errors)); + realErr.print(errors); + } + } + } }