summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jeff Sharkey <jsharkey@google.com> 2023-11-16 10:57:43 -0700
committer Jeff Sharkey <jsharkey@google.com> 2023-11-20 08:49:29 -0700
commitce9f0d06ecdd4df817d1983a4a21802ab31be8c6 (patch)
tree9ccb9eba97d1b6adde6b1991a87070f322b1e263
parentcb4a047ed5d0ce8cc9dbb2cdabc30940a630093d (diff)
More `android.util` internals, with tests.
Internal test authors are likely going to want to use internal utilities that aren't in the official API surface. This change adds those to Ravenwood, along with local tests to confirm they work. Bug: 292141694 Test: atest-dev FrameworksUtilTestsRavenwood Change-Id: I0f4df50416d153418d4525bd8ec5c4dbf04521a2
-rw-r--r--core/java/android/util/DataUnit.java1
-rw-r--r--core/java/android/util/EventLog.java23
-rw-r--r--core/java/android/util/IntArray.java1
-rw-r--r--core/java/android/util/LongArray.java1
-rw-r--r--core/java/android/util/Slog.java6
-rw-r--r--core/java/android/util/TimeUtils.java19
-rw-r--r--core/tests/utiltests/Android.bp20
-rw-r--r--core/tests/utiltests/src/android/util/DataUnitTest.java (renamed from core/tests/coretests/src/android/util/DataUnitTest.java)11
-rw-r--r--core/tests/utiltests/src/android/util/EventLogTest.java (renamed from core/tests/coretests/src/android/util/EventLogTest.java)21
-rw-r--r--core/tests/utiltests/src/android/util/LocalLogTest.java (renamed from core/tests/coretests/src/android/util/LocalLogTest.java)13
-rw-r--r--core/tests/utiltests/src/android/util/SlogTest.java47
-rw-r--r--core/tests/utiltests/src/android/util/TimeUtilsTest.java117
-rw-r--r--ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeep.java3
-rw-r--r--ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeepPartialClass.java34
-rw-r--r--ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeepStaticInitializer.java33
-rw-r--r--ravenwood/framework-minus-apex-ravenwood-policies.txt3
-rw-r--r--ravenwood/ravenwood-annotation-allowed-classes.txt6
-rw-r--r--ravenwood/ravenwood-standard-options.txt6
-rw-r--r--tools/hoststubgen/hoststubgen/framework-policy-override.txt3
-rw-r--r--tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/EventLog_host.java69
20 files changed, 428 insertions, 9 deletions
diff --git a/core/java/android/util/DataUnit.java b/core/java/android/util/DataUnit.java
index cc33af32ba93..10905e1b1908 100644
--- a/core/java/android/util/DataUnit.java
+++ b/core/java/android/util/DataUnit.java
@@ -32,6 +32,7 @@ import java.util.concurrent.TimeUnit;
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public enum DataUnit {
KILOBYTES { @Override public long toBytes(long v) { return v * 1_000; } },
MEGABYTES { @Override public long toBytes(long v) { return v * 1_000_000; } },
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index 4654dbfa9531..d2c5975ea356 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -48,6 +48,9 @@ import java.util.regex.Pattern;
* They carry a payload of one or more int, long, or String values. The
* event-log-tags file defines the payload contents for each type code.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
+@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
+ "com.android.hoststubgen.nativesubstitution.EventLog_host")
public class EventLog {
/** @hide */ public EventLog() {}
@@ -416,6 +419,7 @@ public class EventLog {
/**
* Read TAGS_FILE, populating sTagCodes and sTagNames, if not already done.
*/
+ @android.ravenwood.annotation.RavenwoodReplace
private static synchronized void readTagsFile() {
if (sTagCodes != null && sTagNames != null) return;
@@ -441,8 +445,7 @@ public class EventLog {
try {
int num = Integer.parseInt(m.group(1));
String name = m.group(2);
- sTagCodes.put(name, num);
- sTagNames.put(num, name);
+ registerTagLocked(num, name);
} catch (NumberFormatException e) {
Log.wtf(TAG, "Error in " + TAGS_FILE + ": " + line, e);
}
@@ -454,4 +457,20 @@ public class EventLog {
try { if (reader != null) reader.close(); } catch (IOException e) {}
}
}
+
+ private static void registerTagLocked(int num, String name) {
+ sTagCodes.put(name, num);
+ sTagNames.put(num, name);
+ }
+
+ private static synchronized void readTagsFile$ravenwood() {
+ // TODO: restore parsing logic once we carry into runtime
+ sTagCodes = new HashMap<String, Integer>();
+ sTagNames = new HashMap<Integer, String>();
+
+ // Hard-code a few common tags
+ registerTagLocked(524288, "sysui_action");
+ registerTagLocked(524290, "sysui_count");
+ registerTagLocked(524291, "sysui_histogram");
+ }
}
diff --git a/core/java/android/util/IntArray.java b/core/java/android/util/IntArray.java
index c04a71c4d31b..413ae1f5cbcf 100644
--- a/core/java/android/util/IntArray.java
+++ b/core/java/android/util/IntArray.java
@@ -26,6 +26,7 @@ import java.util.Arrays;
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class IntArray implements Cloneable {
private static final int MIN_CAPACITY_INCREMENT = 12;
diff --git a/core/java/android/util/LongArray.java b/core/java/android/util/LongArray.java
index 3101c0da6986..4c7ef08ddfcb 100644
--- a/core/java/android/util/LongArray.java
+++ b/core/java/android/util/LongArray.java
@@ -30,6 +30,7 @@ import java.util.Arrays;
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class LongArray implements Cloneable {
private static final int MIN_CAPACITY_INCREMENT = 12;
diff --git a/core/java/android/util/Slog.java b/core/java/android/util/Slog.java
index 3aeeccaba250..c0ceb9ea8204 100644
--- a/core/java/android/util/Slog.java
+++ b/core/java/android/util/Slog.java
@@ -31,6 +31,7 @@ import android.os.Build;
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class Slog {
private Slog() {
@@ -216,6 +217,7 @@ public final class Slog {
* @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);
}
@@ -223,6 +225,7 @@ public final class Slog {
/**
* Similar to {@link #wtf(String, String)}, but does not output anything to the log.
*/
+ @android.ravenwood.annotation.RavenwoodThrow
public static void wtfQuiet(@Nullable String tag, @NonNull String msg) {
Log.wtfQuiet(Log.LOG_ID_SYSTEM, tag, msg, true);
}
@@ -241,6 +244,7 @@ public final class Slog {
* @see Log#wtfStack(String, String)
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ @android.ravenwood.annotation.RavenwoodThrow
public static int wtfStack(@Nullable String tag, @NonNull String msg) {
return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null, true, true);
}
@@ -259,6 +263,7 @@ public final class Slog {
*
* @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);
}
@@ -279,6 +284,7 @@ public final class Slog {
* @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/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index d06b0ce1a2d8..bff8db13ad14 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -41,6 +41,8 @@ import java.util.List;
/**
* A class containing utility methods related to time zones.
*/
+@android.ravenwood.annotation.RavenwoodKeepPartialClass
+@android.ravenwood.annotation.RavenwoodKeepStaticInitializer
public class TimeUtils {
/** @hide */ public TimeUtils() {}
/** {@hide} */
@@ -180,6 +182,7 @@ public class TimeUtils {
private static char[] sFormatStr = new char[HUNDRED_DAY_FIELD_LEN+10];
private static char[] sTmpFormatStr = new char[HUNDRED_DAY_FIELD_LEN+10];
+ @android.ravenwood.annotation.RavenwoodKeep
static private int accumField(int amt, int suffix, boolean always, int zeropad) {
if (amt > 999) {
int num = 0;
@@ -202,6 +205,7 @@ public class TimeUtils {
return 0;
}
+ @android.ravenwood.annotation.RavenwoodKeep
static private int printFieldLocked(char[] formatStr, int amt, char suffix, int pos,
boolean always, int zeropad) {
if (always || amt > 0) {
@@ -242,6 +246,7 @@ public class TimeUtils {
return pos;
}
+ @android.ravenwood.annotation.RavenwoodKeep
private static int formatDurationLocked(long duration, int fieldLen) {
if (sFormatStr.length < fieldLen) {
sFormatStr = new char[fieldLen];
@@ -314,6 +319,7 @@ public class TimeUtils {
}
/** @hide Just for debugging; not internationalized. */
+ @android.ravenwood.annotation.RavenwoodKeep
public static void formatDuration(long duration, StringBuilder builder) {
synchronized (sFormatSync) {
int len = formatDurationLocked(duration, 0);
@@ -322,6 +328,7 @@ public class TimeUtils {
}
/** @hide Just for debugging; not internationalized. */
+ @android.ravenwood.annotation.RavenwoodKeep
public static void formatDuration(long duration, StringBuilder builder, int fieldLen) {
synchronized (sFormatSync) {
int len = formatDurationLocked(duration, fieldLen);
@@ -331,6 +338,7 @@ public class TimeUtils {
/** @hide Just for debugging; not internationalized. */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ @android.ravenwood.annotation.RavenwoodKeep
public static void formatDuration(long duration, PrintWriter pw, int fieldLen) {
synchronized (sFormatSync) {
int len = formatDurationLocked(duration, fieldLen);
@@ -340,6 +348,7 @@ public class TimeUtils {
/** @hide Just for debugging; not internationalized. */
@TestApi
+ @android.ravenwood.annotation.RavenwoodKeep
public static String formatDuration(long duration) {
synchronized (sFormatSync) {
int len = formatDurationLocked(duration, 0);
@@ -349,11 +358,13 @@ public class TimeUtils {
/** @hide Just for debugging; not internationalized. */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ @android.ravenwood.annotation.RavenwoodKeep
public static void formatDuration(long duration, PrintWriter pw) {
formatDuration(duration, pw, 0);
}
/** @hide Just for debugging; not internationalized. */
+ @android.ravenwood.annotation.RavenwoodKeep
public static void formatDuration(long time, long now, StringBuilder sb) {
if (time == 0) {
sb.append("--");
@@ -363,6 +374,7 @@ public class TimeUtils {
}
/** @hide Just for debugging; not internationalized. */
+ @android.ravenwood.annotation.RavenwoodKeep
public static void formatDuration(long time, long now, PrintWriter pw) {
if (time == 0) {
pw.print("--");
@@ -372,16 +384,19 @@ public class TimeUtils {
}
/** @hide Just for debugging; not internationalized. */
+ @android.ravenwood.annotation.RavenwoodKeep
public static String formatUptime(long time) {
return formatTime(time, SystemClock.uptimeMillis());
}
/** @hide Just for debugging; not internationalized. */
+ @android.ravenwood.annotation.RavenwoodKeep
public static String formatRealtime(long time) {
return formatTime(time, SystemClock.elapsedRealtime());
}
/** @hide Just for debugging; not internationalized. */
+ @android.ravenwood.annotation.RavenwoodKeep
public static String formatTime(long time, long referenceTime) {
long diff = time - referenceTime;
if (diff > 0) {
@@ -402,6 +417,7 @@ public class TimeUtils {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @android.ravenwood.annotation.RavenwoodKeep
public static String logTimeOfDay(long millis) {
Calendar c = Calendar.getInstance();
if (millis >= 0) {
@@ -413,6 +429,7 @@ public class TimeUtils {
}
/** {@hide} */
+ @android.ravenwood.annotation.RavenwoodKeep
public static String formatForLogging(long millis) {
if (millis <= 0) {
return "unknown";
@@ -426,6 +443,7 @@ public class TimeUtils {
*
* @hide
*/
+ @android.ravenwood.annotation.RavenwoodKeep
public static void dumpTime(PrintWriter pw, long time) {
pw.print(sDumpDateFormat.format(new Date(time)));
}
@@ -457,6 +475,7 @@ public class TimeUtils {
*
* @hide
*/
+ @android.ravenwood.annotation.RavenwoodKeep
public static void dumpTimeWithDelta(PrintWriter pw, long time, long now) {
pw.print(sDumpDateFormat.format(new Date(time)));
if (time == now) {
diff --git a/core/tests/utiltests/Android.bp b/core/tests/utiltests/Android.bp
index 580e73c331a1..06340a222ac6 100644
--- a/core/tests/utiltests/Android.bp
+++ b/core/tests/utiltests/Android.bp
@@ -35,6 +35,7 @@ android_test {
"androidx.test.ext.junit",
"truth",
"servicestests-utils",
+ "ravenwood-junit",
],
libs: [
@@ -50,3 +51,22 @@ android_test {
test_suites: ["device-tests"],
}
+
+android_ravenwood_test {
+ name: "FrameworksUtilTestsRavenwood",
+ static_libs: [
+ "androidx.annotation_annotation",
+ "androidx.test.rules",
+ ],
+ srcs: [
+ "src/android/util/DataUnitTest.java",
+ "src/android/util/EventLogTest.java",
+ "src/android/util/IndentingPrintWriterTest.java",
+ "src/android/util/IntArrayTest.java",
+ "src/android/util/LocalLogTest.java",
+ "src/android/util/LongArrayTest.java",
+ "src/android/util/SlogTest.java",
+ "src/android/util/TimeUtilsTest.java",
+ ],
+ auto_gen_config: true,
+}
diff --git a/core/tests/coretests/src/android/util/DataUnitTest.java b/core/tests/utiltests/src/android/util/DataUnitTest.java
index 034cbddc0144..af9ebc833d4b 100644
--- a/core/tests/coretests/src/android/util/DataUnitTest.java
+++ b/core/tests/utiltests/src/android/util/DataUnitTest.java
@@ -16,12 +16,18 @@
package android.util;
+import static org.junit.Assert.assertEquals;
+
import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
@SmallTest
-public class DataUnitTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class DataUnitTest {
+ @Test
public void testSi() throws Exception {
assertEquals(12_000L, DataUnit.KILOBYTES.toBytes(12));
assertEquals(12_000_000L, DataUnit.MEGABYTES.toBytes(12));
@@ -29,6 +35,7 @@ public class DataUnitTest extends TestCase {
assertEquals(12_000_000_000_000L, DataUnit.TERABYTES.toBytes(12));
}
+ @Test
public void testIec() throws Exception {
assertEquals(12_288L, DataUnit.KIBIBYTES.toBytes(12));
assertEquals(12_582_912L, DataUnit.MEBIBYTES.toBytes(12));
diff --git a/core/tests/coretests/src/android/util/EventLogTest.java b/core/tests/utiltests/src/android/util/EventLogTest.java
index 94e72c4a8d52..0ebf2c163d19 100644
--- a/core/tests/coretests/src/android/util/EventLogTest.java
+++ b/core/tests/utiltests/src/android/util/EventLogTest.java
@@ -16,23 +16,42 @@
package android.util;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.util.EventLog.Event;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import junit.framework.AssertionFailedError;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
/** Unit tests for {@link android.util.EventLog} */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
public class EventLogTest {
+ @Rule public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
+ @Test
+ public void testSimple() throws Throwable {
+ EventLog.writeEvent(42, 42);
+ EventLog.writeEvent(42, 42L);
+ EventLog.writeEvent(42, 42f);
+ EventLog.writeEvent(42, "forty-two");
+ EventLog.writeEvent(42, 42, "forty-two", null, 42);
+ }
@Test
+ @IgnoreUnderRavenwood(reason = "Reading not yet supported")
public void testWithNewData() throws Throwable {
Event event = createEvent(() -> {
EventLog.writeEvent(314, 123);
diff --git a/core/tests/coretests/src/android/util/LocalLogTest.java b/core/tests/utiltests/src/android/util/LocalLogTest.java
index d4861cd391a8..5025a3d0980c 100644
--- a/core/tests/coretests/src/android/util/LocalLogTest.java
+++ b/core/tests/utiltests/src/android/util/LocalLogTest.java
@@ -16,9 +16,13 @@
package android.util;
+import static org.junit.Assert.assertTrue;
+
import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -27,13 +31,16 @@ import java.util.Collections;
import java.util.List;
@LargeTest
-public class LocalLogTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class LocalLogTest {
+ @Test
public void testA_localTimestamps() {
boolean localTimestamps = true;
doTestA(localTimestamps);
}
+ @Test
public void testA_nonLocalTimestamps() {
boolean localTimestamps = false;
doTestA(localTimestamps);
@@ -49,6 +56,7 @@ public class LocalLogTest extends TestCase {
testcase(new LocalLog(10, localTimestamps), lines, want);
}
+ @Test
public void testB() {
String[] lines = {
"foo",
@@ -59,6 +67,7 @@ public class LocalLogTest extends TestCase {
testcase(new LocalLog(0), lines, want);
}
+ @Test
public void testC() {
String[] lines = {
"dropped",
diff --git a/core/tests/utiltests/src/android/util/SlogTest.java b/core/tests/utiltests/src/android/util/SlogTest.java
new file mode 100644
index 000000000000..6f761e348dbe
--- /dev/null
+++ b/core/tests/utiltests/src/android/util/SlogTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class SlogTest {
+ private static final String TAG = "tag";
+ private static final String MSG = "msg";
+ private static final Throwable THROWABLE = new Throwable();
+
+ @Test
+ public void testSimple() {
+ Slog.v(TAG, MSG);
+ Slog.d(TAG, MSG);
+ Slog.i(TAG, MSG);
+ Slog.w(TAG, MSG);
+ Slog.e(TAG, MSG);
+ }
+
+ @Test
+ public void testThrowable() {
+ Slog.v(TAG, MSG, THROWABLE);
+ Slog.d(TAG, MSG, THROWABLE);
+ Slog.i(TAG, MSG, THROWABLE);
+ Slog.w(TAG, MSG, THROWABLE);
+ Slog.e(TAG, MSG, THROWABLE);
+ }
+}
diff --git a/core/tests/utiltests/src/android/util/TimeUtilsTest.java b/core/tests/utiltests/src/android/util/TimeUtilsTest.java
new file mode 100644
index 000000000000..e8246c83e086
--- /dev/null
+++ b/core/tests/utiltests/src/android/util/TimeUtilsTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.function.Consumer;
+
+@RunWith(AndroidJUnit4.class)
+public class TimeUtilsTest {
+ public static final long SECOND_IN_MILLIS = 1000;
+ public static final long MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60;
+ public static final long HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60;
+ public static final long DAY_IN_MILLIS = HOUR_IN_MILLIS * 24;
+ public static final long WEEK_IN_MILLIS = DAY_IN_MILLIS * 7;
+
+ @Test
+ public void testFormatTime() {
+ assertEquals("1672556400000 (now)",
+ TimeUtils.formatTime(1672556400000L, 1672556400000L));
+ assertEquals("1672556400000 (in 10 ms)",
+ TimeUtils.formatTime(1672556400000L, 1672556400000L - 10));
+ assertEquals("1672556400000 (10 ms ago)",
+ TimeUtils.formatTime(1672556400000L, 1672556400000L + 10));
+
+ // Uses formatter above, so we just care that it doesn't crash
+ TimeUtils.formatRealtime(1672556400000L);
+ TimeUtils.formatUptime(1672556400000L);
+ }
+
+ @Test
+ public void testFormatDuration_Zero() {
+ assertEquals("0", TimeUtils.formatDuration(0));
+ }
+
+ @Test
+ public void testFormatDuration_Negative() {
+ assertEquals("-10ms", TimeUtils.formatDuration(-10));
+ }
+
+ @Test
+ public void testFormatDuration() {
+ long accum = 900;
+ assertEquals("+900ms", TimeUtils.formatDuration(accum));
+
+ accum += 59 * SECOND_IN_MILLIS;
+ assertEquals("+59s900ms", TimeUtils.formatDuration(accum));
+
+ accum += 59 * MINUTE_IN_MILLIS;
+ assertEquals("+59m59s900ms", TimeUtils.formatDuration(accum));
+
+ accum += 23 * HOUR_IN_MILLIS;
+ assertEquals("+23h59m59s900ms", TimeUtils.formatDuration(accum));
+
+ accum += 6 * DAY_IN_MILLIS;
+ assertEquals("+6d23h59m59s900ms", TimeUtils.formatDuration(accum));
+ }
+
+ @Test
+ public void testDumpTime() {
+ assertEquals("2023-01-01 00:00:00.000", runWithPrintWriter((pw) -> {
+ TimeUtils.dumpTime(pw, 1672556400000L);
+ }));
+ assertEquals("2023-01-01 00:00:00.000 (now)", runWithPrintWriter((pw) -> {
+ TimeUtils.dumpTimeWithDelta(pw, 1672556400000L, 1672556400000L);
+ }));
+ assertEquals("2023-01-01 00:00:00.000 (-10ms)", runWithPrintWriter((pw) -> {
+ TimeUtils.dumpTimeWithDelta(pw, 1672556400000L, 1672556400000L + 10);
+ }));
+ }
+
+ @Test
+ public void testFormatForLogging() {
+ assertEquals("unknown", TimeUtils.formatForLogging(0));
+ assertEquals("unknown", TimeUtils.formatForLogging(-1));
+ assertEquals("unknown", TimeUtils.formatForLogging(Long.MIN_VALUE));
+ assertEquals("2023-01-01 00:00:00", TimeUtils.formatForLogging(1672556400000L));
+ }
+
+ @Test
+ public void testLogTimeOfDay() {
+ assertEquals("01-01 00:00:00.000", TimeUtils.logTimeOfDay(1672556400000L));
+ }
+
+ public static String runWithPrintWriter(Consumer<PrintWriter> consumer) {
+ final StringWriter sw = new StringWriter();
+ consumer.accept(new PrintWriter(sw));
+ return sw.toString();
+ }
+
+ public static String runWithStringBuilder(Consumer<StringBuilder> consumer) {
+ final StringBuilder sb = new StringBuilder();
+ consumer.accept(sb);
+ return sb.toString();
+ }
+}
diff --git a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeep.java b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeep.java
index 1d315798d647..f02f06c056bd 100644
--- a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeep.java
+++ b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeep.java
@@ -18,7 +18,6 @@ package android.ravenwood.annotation;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -32,7 +31,7 @@ import java.lang.annotation.Target;
*
* @hide
*/
-@Target({TYPE, FIELD, METHOD, CONSTRUCTOR})
+@Target({FIELD, METHOD, CONSTRUCTOR})
@Retention(RetentionPolicy.CLASS)
public @interface RavenwoodKeep {
}
diff --git a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeepPartialClass.java b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeepPartialClass.java
new file mode 100644
index 000000000000..784727410188
--- /dev/null
+++ b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeepPartialClass.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.ravenwood.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * TODO: Javadoc
+ *
+ * @hide
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+public @interface RavenwoodKeepPartialClass {
+}
diff --git a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeepStaticInitializer.java b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeepStaticInitializer.java
new file mode 100644
index 000000000000..eeebee985e4a
--- /dev/null
+++ b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeepStaticInitializer.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.ravenwood.annotation;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * @hide
+ */
+@Target(TYPE)
+@Retention(RetentionPolicy.CLASS)
+public @interface RavenwoodKeepStaticInitializer {
+}
diff --git a/ravenwood/framework-minus-apex-ravenwood-policies.txt b/ravenwood/framework-minus-apex-ravenwood-policies.txt
index 28639d4960a4..48e93280f73f 100644
--- a/ravenwood/framework-minus-apex-ravenwood-policies.txt
+++ b/ravenwood/framework-minus-apex-ravenwood-policies.txt
@@ -17,12 +17,14 @@ class android.util.MapCollections stubclass
class android.util.Log stubclass
class android.util.Log !com.android.hoststubgen.nativesubstitution.Log_host
class android.util.LogPrinter stubclass
+class android.util.LocalLog stubclass
# String Manipulation
class android.util.Printer stubclass
class android.util.PrintStreamPrinter stubclass
class android.util.PrintWriterPrinter stubclass
class android.util.StringBuilderPrinter stubclass
+class android.util.IndentingPrintWriter stubclass
# Properties
class android.util.Property stubclass
@@ -76,6 +78,7 @@ class android.util.Patterns stubclass
class android.util.UtilConfig stubclass
# Internals
+class com.android.internal.util.FastPrintWriter stubclass
class com.android.internal.util.GrowingArrayUtils stubclass
class com.android.internal.util.LineBreakBufferedWriter stubclass
class com.android.internal.util.Preconditions stubclass
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt
index df44fde2ed72..a791f682fecf 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/ravenwood-annotation-allowed-classes.txt
@@ -2,6 +2,12 @@
com.android.internal.util.ArrayUtils
+android.util.DataUnit
+android.util.EventLog
+android.util.IntArray
+android.util.LongArray
+android.util.Slog
+android.util.TimeUtils
android.util.Xml
android.os.Binder
diff --git a/ravenwood/ravenwood-standard-options.txt b/ravenwood/ravenwood-standard-options.txt
index 4b07ef6e35a8..f842f33bc95b 100644
--- a/ravenwood/ravenwood-standard-options.txt
+++ b/ravenwood/ravenwood-standard-options.txt
@@ -18,6 +18,9 @@
--keep-annotation
android.ravenwood.annotation.RavenwoodKeep
+--keep-annotation
+ android.ravenwood.annotation.RavenwoodKeepPartialClass
+
--keep-class-annotation
android.ravenwood.annotation.RavenwoodKeepWholeClass
@@ -35,3 +38,6 @@
--class-load-hook-annotation
android.ravenwood.annotation.RavenwoodClassLoadHook
+
+--keep-static-initializer-annotation
+ android.ravenwood.annotation.RavenwoodKeepStaticInitializer
diff --git a/tools/hoststubgen/hoststubgen/framework-policy-override.txt b/tools/hoststubgen/hoststubgen/framework-policy-override.txt
index ff0fe32ad267..493ad56a5cbb 100644
--- a/tools/hoststubgen/hoststubgen/framework-policy-override.txt
+++ b/tools/hoststubgen/hoststubgen/framework-policy-override.txt
@@ -78,6 +78,9 @@ class android.util.Log !com.android.hoststubgen.nativesubstitution.Log_host
class com.android.internal.util.FastPrintWriter keepclass
class com.android.internal.util.LineBreakBufferedWriter keepclass
+class android.util.EventLog stubclass
+class android.util.EventLog !com.android.hoststubgen.nativesubstitution.EventLog_host
+class android.util.EventLog$Event stubclass
# Expose Context because it's referred to by AndroidTestCase, but don't need to expose any of
# its members.
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
new file mode 100644
index 000000000000..292e8da0de10
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/EventLog_host.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.nativesubstitution;
+
+import android.util.Log;
+import android.util.Log.Level;
+
+import java.util.Collection;
+
+public class EventLog_host {
+ public static int writeEvent(int tag, int value) {
+ return writeEvent(tag, (Object) value);
+ }
+
+ public static int writeEvent(int tag, long value) {
+ return writeEvent(tag, (Object) value);
+ }
+
+ public static int writeEvent(int tag, float value) {
+ return writeEvent(tag, (Object) value);
+ }
+
+ public static int writeEvent(int tag, String str) {
+ return writeEvent(tag, (Object) str);
+ }
+
+ public static int writeEvent(int tag, Object... list) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("logd: [event] ");
+ final String tagName = android.util.EventLog.getTagName(tag);
+ if (tagName != null) {
+ sb.append(tagName);
+ } else {
+ sb.append(tag);
+ }
+ sb.append(": [");
+ for (int i = 0; i < list.length; i++) {
+ sb.append(String.valueOf(list[i]));
+ if (i < list.length - 1) {
+ sb.append(',');
+ }
+ }
+ sb.append(']');
+ System.out.println(sb.toString());
+ return sb.length();
+ }
+
+ public static void readEvents(int[] tags, Collection<android.util.EventLog.Event> output) {
+ throw new UnsupportedOperationException();
+ }
+
+ public static void readEventsOnWrapping(int[] tags, long timestamp,
+ Collection<android.util.EventLog.Event> output) {
+ throw new UnsupportedOperationException();
+ }
+}