Ravenwood support for `wtf()`, wrap logging.
There are some tests triggering `wtf()` during the normal course of
operation, and we haven't been able to reproduce them yet. This
change gives us a valid `wtf()` implementation to aid debugging.
It's also a bit jarring to have log-style messages interleaved with
raw `System.out`, so also add `redirectLogStreams()` to match the
logging behavior that developers observe on physical devices.
Bug: 322805216
Test: atest FrameworksCoreTestsRavenwood FrameworksUtilTestsRavenwood
Change-Id: I8ea2d12638cd998e3962aaa8af09a3335fcd0d51
diff --git a/core/java/android/util/Slog.java b/core/java/android/util/Slog.java
index c0ceb9ea..9ecb4cb 100644
--- a/core/java/android/util/Slog.java
+++ b/core/java/android/util/Slog.java
@@ -217,7 +217,6 @@
* @see Log#wtf(String, String)
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @android.ravenwood.annotation.RavenwoodThrow
public static int wtf(@Nullable String tag, @NonNull String msg) {
return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null, false, true);
}
@@ -263,7 +262,6 @@
*
* @see Log#wtf(String, Throwable)
*/
- @android.ravenwood.annotation.RavenwoodThrow
public static int wtf(@Nullable String tag, @Nullable Throwable tr) {
return Log.wtf(Log.LOG_ID_SYSTEM, tag, tr.getMessage(), tr, false, true);
}
@@ -284,7 +282,6 @@
* @see Log#wtf(String, String, Throwable)
*/
@UnsupportedAppUsage
- @android.ravenwood.annotation.RavenwoodThrow
public static int wtf(@Nullable String tag, @NonNull String msg, @Nullable Throwable tr) {
return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, tr, false, true);
}
diff --git a/core/java/com/android/internal/os/AndroidPrintStream.java b/core/java/com/android/internal/os/AndroidPrintStream.java
index a6e41ff..bb388bb 100644
--- a/core/java/com/android/internal/os/AndroidPrintStream.java
+++ b/core/java/com/android/internal/os/AndroidPrintStream.java
@@ -24,6 +24,7 @@
*
* {@hide}
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
class AndroidPrintStream extends LoggingPrintStream {
private final int priority;
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 28b98d6..cdac097 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -39,6 +39,7 @@
import libcore.content.type.MimeMap;
+import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@@ -50,6 +51,7 @@
* public consumption.
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepPartialClass
public class RuntimeInit {
final static String TAG = "AndroidRuntime";
final static boolean DEBUG = false;
@@ -67,7 +69,15 @@
private static volatile ApplicationWtfHandler sDefaultApplicationWtfHandler;
+ /**
+ * Stored values of System.out and System.err before they've been replaced by
+ * redirectLogStreams(). Kept open here for other Ravenwood internals to use.
+ */
+ public static PrintStream sOut$ravenwood;
+ public static PrintStream sErr$ravenwood;
+
private static final native void nativeFinishInit();
+
private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);
private static int Clog_e(String tag, String msg, Throwable tr) {
@@ -385,6 +395,7 @@
/**
* Redirect System.out and System.err to the Android log.
*/
+ @android.ravenwood.annotation.RavenwoodReplace
public static void redirectLogStreams() {
System.out.close();
System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));
@@ -392,6 +403,17 @@
System.setErr(new AndroidPrintStream(Log.WARN, "System.err"));
}
+ public static void redirectLogStreams$ravenwood() {
+ if (sOut$ravenwood == null) {
+ sOut$ravenwood = System.out;
+ System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));
+ }
+ if (sErr$ravenwood == null) {
+ sErr$ravenwood = System.err;
+ System.setErr(new AndroidPrintStream(Log.WARN, "System.err"));
+ }
+ }
+
/**
* Report a serious error in the current process. May or may not cause
* the process to terminate (depends on system settings).
@@ -399,6 +421,7 @@
* @param tag to record with the error
* @param t exception describing the error site and conditions
*/
+ @android.ravenwood.annotation.RavenwoodReplace
public static void wtf(String tag, Throwable t, boolean system) {
try {
boolean exit = false;
@@ -436,6 +459,11 @@
}
}
+ public static void wtf$ravenwood(String tag, Throwable t, boolean system) {
+ // We've already emitted to logs, so there's nothing more to do here,
+ // as we don't have a DropBox pipeline configured
+ }
+
/**
* Set the default {@link ApplicationWtfHandler}, in case the ActivityManager is not ready yet.
*/
diff --git a/core/tests/coretests/src/android/util/LogTest.java b/core/tests/coretests/src/android/util/LogTest.java
index f9966a1..15caac9 100644
--- a/core/tests/coretests/src/android/util/LogTest.java
+++ b/core/tests/coretests/src/android/util/LogTest.java
@@ -37,6 +37,13 @@
private static final String LOG_TAG = "LogTest";
@Test
+ public void testWtf() {
+ Log.wtf(LOG_TAG, "Message");
+ Log.wtf(LOG_TAG, "Message", new Throwable("Throwable"));
+ Log.wtf(LOG_TAG, new Throwable("Throwable"));
+ }
+
+ @Test
@Ignore
public void testIsLoggable() {
// First clear any SystemProperty setting for our test key.
diff --git a/core/tests/utiltests/src/android/util/SlogTest.java b/core/tests/utiltests/src/android/util/SlogTest.java
index 6f761e3..738c668 100644
--- a/core/tests/utiltests/src/android/util/SlogTest.java
+++ b/core/tests/utiltests/src/android/util/SlogTest.java
@@ -44,4 +44,11 @@
Slog.w(TAG, MSG, THROWABLE);
Slog.e(TAG, MSG, THROWABLE);
}
+
+ @Test
+ public void testWtf() {
+ Slog.wtf(TAG, MSG);
+ Slog.wtf(TAG, MSG, THROWABLE);
+ Slog.wtf(TAG, THROWABLE);
+ }
}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
index 5588f4f..3670459 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -24,6 +24,8 @@
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.internal.os.RuntimeInit;
+
import org.junit.runner.Description;
import java.io.PrintStream;
@@ -53,6 +55,8 @@
}
public static void init(RavenwoodRule rule) {
+ RuntimeInit.redirectLogStreams();
+
android.os.Process.init$ravenwood(rule.mUid, rule.mPid);
android.os.Binder.init$ravenwood();
android.os.SystemProperties.init$ravenwood(
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt
index b775f9a..e49b64e 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/ravenwood-annotation-allowed-classes.txt
@@ -5,6 +5,7 @@
com.android.internal.logging.MetricsLogger
com.android.internal.logging.testing.FakeMetricsLogger
com.android.internal.logging.testing.UiEventLoggerFake
+com.android.internal.os.AndroidPrintStream
com.android.internal.os.BatteryStatsHistory
com.android.internal.os.BatteryStatsHistory$TraceDelegate
com.android.internal.os.BatteryStatsHistory$VarintParceler
@@ -16,6 +17,7 @@
com.android.internal.os.PowerProfile
com.android.internal.os.PowerStats
com.android.internal.os.PowerStats$Descriptor
+com.android.internal.os.RuntimeInit
com.android.internal.power.ModemPowerProfile
android.util.AtomicFile
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/EventLog_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/EventLog_host.java
index 292e8da..6480cfc 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/EventLog_host.java
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/EventLog_host.java
@@ -15,9 +15,9 @@
*/
package com.android.hoststubgen.nativesubstitution;
-import android.util.Log;
-import android.util.Log.Level;
+import com.android.internal.os.RuntimeInit;
+import java.io.PrintStream;
import java.util.Collection;
public class EventLog_host {
@@ -54,7 +54,7 @@
}
}
sb.append(']');
- System.out.println(sb.toString());
+ getRealOut().println(sb.toString());
return sb.length();
}
@@ -66,4 +66,16 @@
Collection<android.util.EventLog.Event> output) {
throw new UnsupportedOperationException();
}
+
+ /**
+ * Return the "real" {@code System.out} if it's been swapped by {@code RavenwoodRuleImpl}, so
+ * that we don't end up in a recursive loop.
+ */
+ private static PrintStream getRealOut() {
+ if (RuntimeInit.sOut$ravenwood != null) {
+ return RuntimeInit.sOut$ravenwood;
+ } else {
+ return System.out;
+ }
+ }
}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Log_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Log_host.java
index ee55c7a..cdfa302 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Log_host.java
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Log_host.java
@@ -18,6 +18,8 @@
import android.util.Log;
import android.util.Log.Level;
+import com.android.internal.os.RuntimeInit;
+
import java.io.PrintStream;
public class Log_host {
@@ -27,7 +29,6 @@
}
public static int println_native(int bufID, int priority, String tag, String msg) {
- final PrintStream out = System.out;
final String buffer;
switch (bufID) {
case Log.LOG_ID_MAIN: buffer = "main"; break;
@@ -50,7 +51,7 @@
};
for (String s : msg.split("\\n")) {
- out.println(String.format("logd: [%s] %s %s: %s", buffer, prio, tag, s));
+ getRealOut().println(String.format("logd: [%s] %s %s: %s", buffer, prio, tag, s));
}
return msg.length();
}
@@ -58,4 +59,16 @@
public static int logger_entry_max_payload_native() {
return 4068; // [ravenwood] This is what people use in various places.
}
+
+ /**
+ * Return the "real" {@code System.out} if it's been swapped by {@code RavenwoodRuleImpl}, so
+ * that we don't end up in a recursive loop.
+ */
+ private static PrintStream getRealOut() {
+ if (RuntimeInit.sOut$ravenwood != null) {
+ return RuntimeInit.sOut$ravenwood;
+ } else {
+ return System.out;
+ }
+ }
}