summaryrefslogtreecommitdiff
path: root/ravenwood/runtime-helper-src
diff options
context:
space:
mode:
author John Wu <topjohnwu@google.com> 2024-09-26 22:59:40 +0000
committer John Wu <topjohnwu@google.com> 2024-09-26 22:59:40 +0000
commit983461633b96db0bc58205a657edeffad3ce4080 (patch)
tree8df76979756f92a675ea35ac852917a2369d152f /ravenwood/runtime-helper-src
parent6f7665370b368b3f4164cdce501ae224b3351c9b (diff)
Cherry-pick Ravenwood "core" code
- Copied f/b/r and f/b/t/h - Ported files under f/b/core, only what needed to for run-ravenwood-tests.sh to pass - Local changes because of missing resoucres support - Added @DisabledOnRavenwood(reason="AOSP is missing resources support") to tests under f/b/r that depends on resources bivalentinst and servicestest - Added try-catch around ResourcesManager.setInstance() Flag: EXEMPT host test change only Bug: 292141694 Test: $ANDROID_BUILD_TOP/frameworks/base/ravenwood/scripts/run-ravenwood-tests.sh Merged-in: I8a9b8374be3ae052ba4f152eb43af20d0871597f Change-Id: Iefd574dbded8c4ab2e244c4918c26641364a3432
Diffstat (limited to 'ravenwood/runtime-helper-src')
-rw-r--r--ravenwood/runtime-helper-src/framework/android/database/CursorWindow_host.java (renamed from ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/CursorWindow_host.java)29
-rw-r--r--ravenwood/runtime-helper-src/framework/android/os/MessageQueue_host.java (renamed from ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/MessageQueue_host.java)2
-rw-r--r--ravenwood/runtime-helper-src/framework/android/os/SystemProperties_host.java (renamed from ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java)29
-rw-r--r--ravenwood/runtime-helper-src/framework/android/util/EventLog_host.java (renamed from ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/EventLog_host.java)12
-rw-r--r--ravenwood/runtime-helper-src/framework/android/util/Log_host.java (renamed from ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java)7
-rw-r--r--ravenwood/runtime-helper-src/framework/com/android/internal/os/LongArrayContainer_host.java63
-rw-r--r--ravenwood/runtime-helper-src/framework/com/android/internal/os/LongArrayMultiStateCounter_host.java (renamed from ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongArrayMultiStateCounter_host.java)48
-rw-r--r--ravenwood/runtime-helper-src/framework/com/android/internal/os/LongMultiStateCounter_host.java (renamed from ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongMultiStateCounter_host.java)2
-rw-r--r--ravenwood/runtime-helper-src/framework/com/android/internal/ravenwood/RavenwoodEnvironment_host.java46
-rw-r--r--ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Parcel_host.java529
-rw-r--r--ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java58
-rw-r--r--ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java168
-rw-r--r--ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java30
-rw-r--r--ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodJdkPatch.java (renamed from ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/ParcelFileDescriptor_host.java)32
-rw-r--r--ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java (renamed from ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/common/RavenwoodRuntimeNative.java)8
-rw-r--r--ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java14
-rw-r--r--ravenwood/runtime-helper-src/libcore-fake/libcore/io/IoUtils.java26
-rw-r--r--ravenwood/runtime-helper-src/libcore-fake/libcore/util/FP16.java814
-rw-r--r--ravenwood/runtime-helper-src/libcore-fake/libcore/util/NativeAllocationRegistry.java2
19 files changed, 1065 insertions, 854 deletions
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/CursorWindow_host.java b/ravenwood/runtime-helper-src/framework/android/database/CursorWindow_host.java
index f38d5653d3a9..e21a9cd71a2d 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/CursorWindow_host.java
+++ b/ravenwood/runtime-helper-src/framework/android/database/CursorWindow_host.java
@@ -13,9 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.platform.test.ravenwood.nativesubstitution;
+package android.database;
-import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.os.Parcel;
import android.util.Base64;
@@ -35,8 +34,8 @@ public class CursorWindow_host {
private String mName;
private int mColumnNum;
private static class Row {
- String[] fields;
- int[] types;
+ String[] mFields;
+ int[] mTypes;
}
private final List<Row> mRows = new ArrayList<>();
@@ -69,9 +68,9 @@ public class CursorWindow_host {
public static boolean nativeAllocRow(long windowPtr) {
CursorWindow_host instance = sInstances.get(windowPtr);
Row row = new Row();
- row.fields = new String[instance.mColumnNum];
- row.types = new int[instance.mColumnNum];
- Arrays.fill(row.types, Cursor.FIELD_TYPE_NULL);
+ row.mFields = new String[instance.mColumnNum];
+ row.mTypes = new int[instance.mColumnNum];
+ Arrays.fill(row.mTypes, Cursor.FIELD_TYPE_NULL);
instance.mRows.add(row);
return true;
}
@@ -82,8 +81,8 @@ public class CursorWindow_host {
return false;
}
Row r = instance.mRows.get(row);
- r.fields[column] = value;
- r.types[column] = type;
+ r.mFields[column] = value;
+ r.mTypes[column] = type;
return true;
}
@@ -93,7 +92,7 @@ public class CursorWindow_host {
return Cursor.FIELD_TYPE_NULL;
}
- return instance.mRows.get(row).types[column];
+ return instance.mRows.get(row).mTypes[column];
}
public static boolean nativePutString(long windowPtr, String value,
@@ -107,7 +106,7 @@ public class CursorWindow_host {
return null;
}
- return instance.mRows.get(row).fields[column];
+ return instance.mRows.get(row).mFields[column];
}
public static boolean nativePutLong(long windowPtr, long value, int row, int column) {
@@ -170,8 +169,8 @@ public class CursorWindow_host {
parcel.writeInt(window.mColumnNum);
parcel.writeInt(window.mRows.size());
for (int row = 0; row < window.mRows.size(); row++) {
- parcel.writeStringArray(window.mRows.get(row).fields);
- parcel.writeIntArray(window.mRows.get(row).types);
+ parcel.writeStringArray(window.mRows.get(row).mFields);
+ parcel.writeIntArray(window.mRows.get(row).mTypes);
}
}
@@ -183,8 +182,8 @@ public class CursorWindow_host {
int rowCount = parcel.readInt();
for (int row = 0; row < rowCount; row++) {
Row r = new Row();
- r.fields = parcel.createStringArray();
- r.types = parcel.createIntArray();
+ r.mFields = parcel.createStringArray();
+ r.mTypes = parcel.createIntArray();
window.mRows.add(r);
}
return windowPtr;
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/MessageQueue_host.java b/ravenwood/runtime-helper-src/framework/android/os/MessageQueue_host.java
index 5e81124b6e70..1b63adc4319f 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/MessageQueue_host.java
+++ b/ravenwood/runtime-helper-src/framework/android/os/MessageQueue_host.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.platform.test.ravenwood.nativesubstitution;
+package android.os;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java b/ravenwood/runtime-helper-src/framework/android/os/SystemProperties_host.java
index e7479d313918..b09bf3119cfa 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java
+++ b/ravenwood/runtime-helper-src/framework/android/os/SystemProperties_host.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.platform.test.ravenwood.nativesubstitution;
+package android.os;
import android.util.SparseArray;
@@ -36,9 +36,6 @@ public class SystemProperties_host {
/** Predicate tested to determine if a given key can be written. */
@GuardedBy("sLock")
private static Predicate<String> sKeyWritablePredicate;
- /** Callback to trigger when values are changed */
- @GuardedBy("sLock")
- private static Runnable sChangeCallback;
/**
* Reverse mapping that provides a way back to an original key from the
@@ -48,7 +45,7 @@ public class SystemProperties_host {
private static SparseArray<String> sKeyHandles = new SparseArray<>();
/**
- * Basically the same as {@link #native_init$ravenwood}, but it'll only run if no values are
+ * Basically the same as {@link #init$ravenwood}, but it'll only run if no values are
* set yet.
*/
public static void initializeIfNeeded(Map<String, String> values,
@@ -57,30 +54,32 @@ public class SystemProperties_host {
if (sValues != null) {
return; // Already initialized.
}
- native_init$ravenwood(values, keyReadablePredicate, keyWritablePredicate,
- () -> {});
+ init$ravenwood(values, keyReadablePredicate, keyWritablePredicate);
}
}
- public static void native_init$ravenwood(Map<String, String> values,
- Predicate<String> keyReadablePredicate, Predicate<String> keyWritablePredicate,
- Runnable changeCallback) {
+ public static void init$ravenwood(Map<String, String> values,
+ Predicate<String> keyReadablePredicate, Predicate<String> keyWritablePredicate) {
synchronized (sLock) {
sValues = Objects.requireNonNull(values);
sKeyReadablePredicate = Objects.requireNonNull(keyReadablePredicate);
sKeyWritablePredicate = Objects.requireNonNull(keyWritablePredicate);
- sChangeCallback = Objects.requireNonNull(changeCallback);
sKeyHandles.clear();
+ synchronized (SystemProperties.sChangeCallbacks) {
+ SystemProperties.sChangeCallbacks.clear();
+ }
}
}
- public static void native_reset$ravenwood() {
+ public static void reset$ravenwood() {
synchronized (sLock) {
sValues = null;
sKeyReadablePredicate = null;
sKeyWritablePredicate = null;
- sChangeCallback = null;
sKeyHandles.clear();
+ synchronized (SystemProperties.sChangeCallbacks) {
+ SystemProperties.sChangeCallbacks.clear();
+ }
}
}
@@ -101,7 +100,7 @@ public class SystemProperties_host {
} else {
sValues.put(key, val);
}
- sChangeCallback.run();
+ SystemProperties.callChangeCallbacks();
}
}
@@ -183,7 +182,7 @@ public class SystemProperties_host {
// Report through callback always registered via init above
synchronized (sLock) {
Preconditions.requireNonNullViaRavenwoodRule(sValues);
- sChangeCallback.run();
+ SystemProperties.callChangeCallbacks();
}
}
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/EventLog_host.java b/ravenwood/runtime-helper-src/framework/android/util/EventLog_host.java
index 55d4ffb41e78..878a0ff57a1d 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/EventLog_host.java
+++ b/ravenwood/runtime-helper-src/framework/android/util/EventLog_host.java
@@ -13,12 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.platform.test.ravenwood.nativesubstitution;
+package android.util;
import com.android.internal.os.RuntimeInit;
import java.io.PrintStream;
-import java.util.Collection;
public class EventLog_host {
public static int writeEvent(int tag, int value) {
@@ -58,15 +57,6 @@ public class EventLog_host {
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();
- }
-
/**
* 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.
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java b/ravenwood/runtime-helper-src/framework/android/util/Log_host.java
index f301b9c46b0e..d232ef2076be 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java
+++ b/ravenwood/runtime-helper-src/framework/android/util/Log_host.java
@@ -13,9 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.platform.test.ravenwood.nativesubstitution;
+package android.util;
-import android.util.Log;
import android.util.Log.Level;
import com.android.internal.os.RuntimeInit;
@@ -44,7 +43,7 @@ public class Log_host {
case Log.LOG_ID_SYSTEM: buffer = "system"; break;
case Log.LOG_ID_CRASH: buffer = "crash"; break;
default: buffer = "buf:" + bufID; break;
- };
+ }
final String prio;
switch (priority) {
@@ -55,7 +54,7 @@ public class Log_host {
case Log.ERROR: prio = "E"; break;
case Log.ASSERT: prio = "A"; break;
default: prio = "prio:" + priority; break;
- };
+ }
for (String s : msg.split("\\n")) {
getRealOut().println(String.format("logd: [%s] %s %s: %s", buffer, prio, tag, s));
diff --git a/ravenwood/runtime-helper-src/framework/com/android/internal/os/LongArrayContainer_host.java b/ravenwood/runtime-helper-src/framework/com/android/internal/os/LongArrayContainer_host.java
new file mode 100644
index 000000000000..c18c307ad1e3
--- /dev/null
+++ b/ravenwood/runtime-helper-src/framework/com/android/internal/os/LongArrayContainer_host.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2024 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.internal.os;
+
+import java.util.Arrays;
+import java.util.HashMap;
+
+public class LongArrayContainer_host {
+ private static final HashMap<Long, long[]> sInstances = new HashMap<>();
+ private static long sNextId = 1;
+
+ public static long native_init(int arrayLength) {
+ long[] array = new long[arrayLength];
+ long instanceId = sNextId++;
+ sInstances.put(instanceId, array);
+ return instanceId;
+ }
+
+ static long[] getInstance(long instanceId) {
+ return sInstances.get(instanceId);
+ }
+
+ public static void native_setValues(long instanceId, long[] values) {
+ System.arraycopy(values, 0, getInstance(instanceId), 0, values.length);
+ }
+
+ public static void native_getValues(long instanceId, long[] values) {
+ System.arraycopy(getInstance(instanceId), 0, values, 0, values.length);
+ }
+
+ public static boolean native_combineValues(long instanceId, long[] array, int[] indexMap) {
+ long[] values = getInstance(instanceId);
+
+ boolean nonZero = false;
+ Arrays.fill(array, 0);
+
+ for (int i = 0; i < values.length; i++) {
+ int index = indexMap[i];
+ if (index < 0 || index >= array.length) {
+ throw new IndexOutOfBoundsException("Index " + index + " is out of bounds: [0, "
+ + (array.length - 1) + "]");
+ }
+ if (values[i] != 0) {
+ array[index] += values[i];
+ nonZero = true;
+ }
+ }
+ return nonZero;
+ }
+}
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongArrayMultiStateCounter_host.java b/ravenwood/runtime-helper-src/framework/com/android/internal/os/LongArrayMultiStateCounter_host.java
index 0f65544f8b66..9ce8ea8e16ef 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongArrayMultiStateCounter_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/internal/os/LongArrayMultiStateCounter_host.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.platform.test.ravenwood.nativesubstitution;
+package com.android.internal.os;
import android.os.BadParcelableException;
import android.os.Parcel;
@@ -28,7 +28,7 @@ import java.util.HashMap;
public class LongArrayMultiStateCounter_host {
/**
- * A reimplementation of {@link com.android.internal.os.LongArrayMultiStateCounter}, only in
+ * A reimplementation of {@link LongArrayMultiStateCounter}, only in
* Java instead of native. The majority of the code (in C++) can be found in
* /frameworks/native/libs/battery/MultiStateCounter.h
*/
@@ -257,50 +257,6 @@ public class LongArrayMultiStateCounter_host {
}
}
- public static class LongArrayContainer_host {
- private static final HashMap<Long, long[]> sInstances = new HashMap<>();
- private static long sNextId = 1;
-
- public static long native_init(int arrayLength) {
- long[] array = new long[arrayLength];
- long instanceId = sNextId++;
- sInstances.put(instanceId, array);
- return instanceId;
- }
-
- static long[] getInstance(long instanceId) {
- return sInstances.get(instanceId);
- }
-
- public static void native_setValues(long instanceId, long[] values) {
- System.arraycopy(values, 0, getInstance(instanceId), 0, values.length);
- }
-
- public static void native_getValues(long instanceId, long[] values) {
- System.arraycopy(getInstance(instanceId), 0, values, 0, values.length);
- }
-
- public static boolean native_combineValues(long instanceId, long[] array, int[] indexMap) {
- long[] values = getInstance(instanceId);
-
- boolean nonZero = false;
- Arrays.fill(array, 0);
-
- for (int i = 0; i < values.length; i++) {
- int index = indexMap[i];
- if (index < 0 || index >= array.length) {
- throw new IndexOutOfBoundsException("Index " + index + " is out of bounds: [0, "
- + (array.length - 1) + "]");
- }
- if (values[i] != 0) {
- array[index] += values[i];
- nonZero = true;
- }
- }
- return nonZero;
- }
- }
-
private static final HashMap<Long, LongArrayMultiStateCounterRavenwood> sInstances =
new HashMap<>();
private static long sNextId = 1;
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongMultiStateCounter_host.java b/ravenwood/runtime-helper-src/framework/com/android/internal/os/LongMultiStateCounter_host.java
index 9486651ce48d..1d95aa143549 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongMultiStateCounter_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/internal/os/LongMultiStateCounter_host.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.platform.test.ravenwood.nativesubstitution;
+package com.android.internal.os;
import android.os.BadParcelableException;
import android.os.Parcel;
diff --git a/ravenwood/runtime-helper-src/framework/com/android/internal/ravenwood/RavenwoodEnvironment_host.java b/ravenwood/runtime-helper-src/framework/com/android/internal/ravenwood/RavenwoodEnvironment_host.java
new file mode 100644
index 000000000000..e12ff240c4d9
--- /dev/null
+++ b/ravenwood/runtime-helper-src/framework/com/android/internal/ravenwood/RavenwoodEnvironment_host.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 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.internal.ravenwood;
+
+import com.android.ravenwood.common.JvmWorkaround;
+import com.android.ravenwood.common.RavenwoodCommonUtils;
+
+public class RavenwoodEnvironment_host {
+ private RavenwoodEnvironment_host() {
+ }
+
+ /**
+ * Called from {@link RavenwoodEnvironment#ensureRavenwoodInitialized()}.
+ */
+ public static void ensureRavenwoodInitialized() {
+ // Initialization is now done by RavenwoodAwareTestRunner.
+ // Should we remove it?
+ }
+
+ /**
+ * Called from {@link RavenwoodEnvironment#getRavenwoodRuntimePath()}.
+ */
+ public static String getRavenwoodRuntimePath(RavenwoodEnvironment env) {
+ return RavenwoodCommonUtils.getRavenwoodRuntimePath();
+ }
+
+ /**
+ * Called from {@link RavenwoodEnvironment#fromAddress(long)}.
+ */
+ public static <T> T fromAddress(RavenwoodEnvironment env, long address) {
+ return JvmWorkaround.getInstance().fromAddress(address);
+ }
+}
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Parcel_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Parcel_host.java
deleted file mode 100644
index 2df93cd93935..000000000000
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Parcel_host.java
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * 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.platform.test.ravenwood.nativesubstitution;
-
-import android.system.ErrnoException;
-import android.system.Os;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * Tentative, partial implementation of the Parcel native methods, using Java's
- * {@code byte[]}.
- * (We don't use a {@link ByteBuffer} because there's enough semantics differences between Parcel
- * and {@link ByteBuffer}, and it didn't work out.
- * e.g. Parcel seems to allow moving the data position to be beyond its size? Which
- * {@link ByteBuffer} wouldn't allow...)
- */
-public class Parcel_host {
- private static final String TAG = "Parcel";
-
- private Parcel_host() {
- }
-
- private static final AtomicLong sNextId = new AtomicLong(1);
-
- private static final Map<Long, Parcel_host> sInstances = new ConcurrentHashMap<>();
-
- private boolean mDeleted = false;
-
- private byte[] mBuffer;
- private int mSize;
- private int mPos;
-
- private boolean mSensitive;
- private boolean mAllowFds;
-
- // TODO Use the actual value from Parcel.java.
- private static final int OK = 0;
-
- private final Map<Integer, FileDescriptor> mFdMap = new ConcurrentHashMap<>();
-
- private static final int FD_PLACEHOLDER = 0xDEADBEEF;
- private static final int FD_PAYLOAD_SIZE = 8;
-
- private void validate() {
- if (mDeleted) {
- // TODO: Put more info
- throw new RuntimeException("Parcel already destroyed");
- }
- }
-
- private static Parcel_host getInstance(long id) {
- Parcel_host p = sInstances.get(id);
- if (p == null) {
- // TODO: Put more info
- throw new RuntimeException("Parcel doesn't exist with id=" + id);
- }
- p.validate();
- return p;
- }
-
- /** Native method substitution */
- public static long nativeCreate() {
- final long id = sNextId.getAndIncrement();
- final Parcel_host p = new Parcel_host();
- sInstances.put(id, p);
- p.init();
- return id;
- }
-
- private void init() {
- mBuffer = new byte[0];
- mSize = 0;
- mPos = 0;
- mSensitive = false;
- mAllowFds = true;
- mFdMap.clear();
- }
-
- private void updateSize() {
- if (mSize < mPos) {
- mSize = mPos;
- }
- }
-
- /** Native method substitution */
- public static void nativeDestroy(long nativePtr) {
- getInstance(nativePtr).mDeleted = true;
- sInstances.remove(nativePtr);
- }
-
- /** Native method substitution */
- public static void nativeFreeBuffer(long nativePtr) {
- getInstance(nativePtr).freeBuffer();
- }
-
- /** Native method substitution */
- private void freeBuffer() {
- init();
- }
-
- private int getCapacity() {
- return mBuffer.length;
- }
-
- private void ensureMoreCapacity(int size) {
- ensureCapacity(mPos + size);
- }
-
- private void ensureCapacity(int targetSize) {
- if (targetSize <= getCapacity()) {
- return;
- }
- var newSize = getCapacity() * 2;
- if (newSize < targetSize) {
- newSize = targetSize;
- }
- forceSetCapacity(newSize);
- }
-
- private void forceSetCapacity(int newSize) {
- var newBuf = new byte[newSize];
-
- // Copy
- System.arraycopy(mBuffer, 0, newBuf, 0, Math.min(newSize, getCapacity()));
-
- this.mBuffer = newBuf;
- }
-
- private void ensureDataAvailable(int requestSize) {
- if (mSize - mPos < requestSize) {
- throw new RuntimeException(String.format(
- "Pacel data underflow. size=%d, pos=%d, request=%d", mSize, mPos, requestSize));
- }
- }
-
- /** Native method substitution */
- public static void nativeMarkSensitive(long nativePtr) {
- getInstance(nativePtr).mSensitive = true;
- }
-
- /** Native method substitution */
- public static int nativeDataSize(long nativePtr) {
- return getInstance(nativePtr).mSize;
- }
-
- /** Native method substitution */
- public static int nativeDataAvail(long nativePtr) {
- var p = getInstance(nativePtr);
- return p.mSize - p.mPos;
- }
-
- /** Native method substitution */
- public static int nativeDataPosition(long nativePtr) {
- return getInstance(nativePtr).mPos;
- }
-
- /** Native method substitution */
- public static int nativeDataCapacity(long nativePtr) {
- return getInstance(nativePtr).mBuffer.length;
- }
-
- /** Native method substitution */
- public static void nativeSetDataSize(long nativePtr, int size) {
- var p = getInstance(nativePtr);
- p.ensureCapacity(size);
- getInstance(nativePtr).mSize = size;
- }
-
- /** Native method substitution */
- public static void nativeSetDataPosition(long nativePtr, int pos) {
- var p = getInstance(nativePtr);
- // TODO: Should this change the size or the capacity??
- p.mPos = pos;
- }
-
- /** Native method substitution */
- public static void nativeSetDataCapacity(long nativePtr, int size) {
- if (size < 0) {
- throw new IllegalArgumentException("size < 0: size=" + size);
- }
- var p = getInstance(nativePtr);
- if (p.getCapacity() < size) {
- p.forceSetCapacity(size);
- }
- }
-
- /** Native method substitution */
- public static boolean nativePushAllowFds(long nativePtr, boolean allowFds) {
- var p = getInstance(nativePtr);
- var prev = p.mAllowFds;
- p.mAllowFds = allowFds;
- return prev;
- }
-
- /** Native method substitution */
- public static void nativeRestoreAllowFds(long nativePtr, boolean lastValue) {
- getInstance(nativePtr).mAllowFds = lastValue;
- }
-
- /** Native method substitution */
- public static void nativeWriteByteArray(long nativePtr, byte[] b, int offset, int len) {
- nativeWriteBlob(nativePtr, b, offset, len);
- }
-
- /** Native method substitution */
- public static void nativeWriteBlob(long nativePtr, byte[] b, int offset, int len) {
- var p = getInstance(nativePtr);
-
- if (b == null) {
- nativeWriteInt(nativePtr, -1);
- } else {
- final var alignedSize = align4(len);
-
- nativeWriteInt(nativePtr, len);
-
- p.ensureMoreCapacity(alignedSize);
-
- System.arraycopy(b, offset, p.mBuffer, p.mPos, len);
- p.mPos += alignedSize;
- p.updateSize();
- }
- }
-
- /** Native method substitution */
- public static int nativeWriteInt(long nativePtr, int value) {
- var p = getInstance(nativePtr);
- p.ensureMoreCapacity(Integer.BYTES);
-
- p.mBuffer[p.mPos++] = (byte) ((value >> 24) & 0xff);
- p.mBuffer[p.mPos++] = (byte) ((value >> 16) & 0xff);
- p.mBuffer[p.mPos++] = (byte) ((value >> 8) & 0xff);
- p.mBuffer[p.mPos++] = (byte) ((value >> 0) & 0xff);
-
- p.updateSize();
-
- return OK;
- }
-
- /** Native method substitution */
- public static int nativeWriteLong(long nativePtr, long value) {
- nativeWriteInt(nativePtr, (int) (value >>> 32));
- nativeWriteInt(nativePtr, (int) (value));
- return OK;
- }
-
- /** Native method substitution */
- public static int nativeWriteFloat(long nativePtr, float val) {
- return nativeWriteInt(nativePtr, Float.floatToIntBits(val));
- }
-
- /** Native method substitution */
- public static int nativeWriteDouble(long nativePtr, double val) {
- return nativeWriteLong(nativePtr, Double.doubleToLongBits(val));
- }
-
- private static int align4(int val) {
- return ((val + 3) / 4) * 4;
- }
-
- /** Native method substitution */
- public static void nativeWriteString8(long nativePtr, String val) {
- if (val == null) {
- nativeWriteBlob(nativePtr, null, 0, 0);
- } else {
- var bytes = val.getBytes(StandardCharsets.UTF_8);
- nativeWriteBlob(nativePtr, bytes, 0, bytes.length);
- }
- }
-
- /** Native method substitution */
- public static void nativeWriteString16(long nativePtr, String val) {
- // Just reuse String8
- nativeWriteString8(nativePtr, val);
- }
-
- /** Native method substitution */
- public static byte[] nativeCreateByteArray(long nativePtr) {
- return nativeReadBlob(nativePtr);
- }
-
- /** Native method substitution */
- public static boolean nativeReadByteArray(long nativePtr, byte[] dest, int destLen) {
- if (dest == null) {
- return false;
- }
- var data = nativeReadBlob(nativePtr);
- if (data == null) {
- System.err.println("Percel has NULL, which is unexpected."); // TODO: Is this correct?
- return false;
- }
- // TODO: Make sure the check logic is correct.
- if (data.length != destLen) {
- System.err.println("Byte array size mismatch: expected="
- + data.length + " given=" + destLen);
- return false;
- }
- System.arraycopy(data, 0, dest, 0, data.length);
- return true;
- }
-
- /** Native method substitution */
- public static byte[] nativeReadBlob(long nativePtr) {
- var p = getInstance(nativePtr);
- if (p.mSize - p.mPos < 4) {
- // Match native impl that returns "null" when not enough data
- return null;
- }
- final var size = nativeReadInt(nativePtr);
- if (size == -1) {
- return null;
- }
- try {
- p.ensureDataAvailable(align4(size));
- } catch (Exception e) {
- System.err.println(e.toString());
- return null;
- }
-
- var bytes = new byte[size];
- System.arraycopy(p.mBuffer, p.mPos, bytes, 0, size);
-
- p.mPos += align4(size);
-
- return bytes;
- }
-
- /** Native method substitution */
- public static int nativeReadInt(long nativePtr) {
- var p = getInstance(nativePtr);
-
- if (p.mSize - p.mPos < 4) {
- // Match native impl that returns "0" when not enough data
- return 0;
- }
-
- var ret = (((p.mBuffer[p.mPos++] & 0xff) << 24)
- | ((p.mBuffer[p.mPos++] & 0xff) << 16)
- | ((p.mBuffer[p.mPos++] & 0xff) << 8)
- | ((p.mBuffer[p.mPos++] & 0xff) << 0));
-
- return ret;
- }
-
- /** Native method substitution */
- public static long nativeReadLong(long nativePtr) {
- return (((long) nativeReadInt(nativePtr)) << 32)
- | (((long) nativeReadInt(nativePtr)) & 0xffff_ffffL);
- }
-
- /** Native method substitution */
- public static float nativeReadFloat(long nativePtr) {
- return Float.intBitsToFloat(nativeReadInt(nativePtr));
- }
-
- /** Native method substitution */
- public static double nativeReadDouble(long nativePtr) {
- return Double.longBitsToDouble(nativeReadLong(nativePtr));
- }
-
- /** Native method substitution */
- public static String nativeReadString8(long nativePtr) {
- final var bytes = nativeReadBlob(nativePtr);
- if (bytes == null) {
- return null;
- }
- return new String(bytes, StandardCharsets.UTF_8);
- }
- public static String nativeReadString16(long nativePtr) {
- return nativeReadString8(nativePtr);
- }
-
- /** Native method substitution */
- public static byte[] nativeMarshall(long nativePtr) {
- var p = getInstance(nativePtr);
- return Arrays.copyOf(p.mBuffer, p.mSize);
- }
-
- /** Native method substitution */
- public static void nativeUnmarshall(
- long nativePtr, byte[] data, int offset, int length) {
- var p = getInstance(nativePtr);
- p.ensureMoreCapacity(length);
- System.arraycopy(data, offset, p.mBuffer, p.mPos, length);
- p.mPos += length;
- p.updateSize();
- }
-
- /** Native method substitution */
- public static int nativeCompareData(long thisNativePtr, long otherNativePtr) {
- var a = getInstance(thisNativePtr);
- var b = getInstance(otherNativePtr);
- if ((a.mSize == b.mSize) && Arrays.equals(a.mBuffer, b.mBuffer)) {
- return 0;
- } else {
- return -1;
- }
- }
-
- /** Native method substitution */
- public static boolean nativeCompareDataInRange(
- long ptrA, int offsetA, long ptrB, int offsetB, int length) {
- var a = getInstance(ptrA);
- var b = getInstance(ptrB);
- if (offsetA < 0 || offsetA + length > a.mSize) {
- throw new IllegalArgumentException();
- }
- if (offsetB < 0 || offsetB + length > b.mSize) {
- throw new IllegalArgumentException();
- }
- return Arrays.equals(Arrays.copyOfRange(a.mBuffer, offsetA, offsetA + length),
- Arrays.copyOfRange(b.mBuffer, offsetB, offsetB + length));
- }
-
- /** Native method substitution */
- public static void nativeAppendFrom(
- long thisNativePtr, long otherNativePtr, int srcOffset, int length) {
- var dst = getInstance(thisNativePtr);
- var src = getInstance(otherNativePtr);
-
- dst.ensureMoreCapacity(length);
-
- System.arraycopy(src.mBuffer, srcOffset, dst.mBuffer, dst.mPos, length);
- dst.mPos += length; // TODO: 4 byte align?
- dst.updateSize();
-
- // TODO: Update the other's position?
- }
-
- /** Native method substitution */
- public static boolean nativeHasBinders(long nativePtr) {
- // Assume false for now, because we don't support adding binders.
- return false;
- }
-
- /** Native method substitution */
- public static boolean nativeHasBindersInRange(
- long nativePtr, int offset, int length) {
- // Assume false for now, because we don't support writing FDs yet.
- return false;
- }
-
- /** Native method substitution */
- public static void nativeWriteFileDescriptor(long nativePtr, java.io.FileDescriptor val) {
- var p = getInstance(nativePtr);
-
- if (!p.mAllowFds) {
- // Simulate the FDS_NOT_ALLOWED case in frameworks/base/core/jni/android_util_Binder.cpp
- throw new RuntimeException("Not allowed to write file descriptors here");
- }
-
- FileDescriptor dup = null;
- try {
- dup = Os.dup(val);
- } catch (ErrnoException e) {
- throw new RuntimeException(e);
- }
- p.mFdMap.put(p.mPos, dup);
-
- // Parcel.cpp writes two int32s for a FD.
- // Make sure FD_PAYLOAD_SIZE is in sync with this code.
- nativeWriteInt(nativePtr, FD_PLACEHOLDER);
- nativeWriteInt(nativePtr, FD_PLACEHOLDER);
- }
-
- /** Native method substitution */
- public static java.io.FileDescriptor nativeReadFileDescriptor(long nativePtr) {
- var p = getInstance(nativePtr);
-
- var pos = p.mPos;
- var fd = p.mFdMap.get(pos);
-
- if (fd == null) {
- Log.w(TAG, "nativeReadFileDescriptor: Not a FD at pos #" + pos);
- return null;
- }
- nativeReadInt(nativePtr);
- return fd;
- }
-
- /** Native method substitution */
- public static boolean nativeHasFileDescriptors(long nativePtr) {
- var p = getInstance(nativePtr);
- return p.mFdMap.size() > 0;
- }
-
- /** Native method substitution */
- public static boolean nativeHasFileDescriptorsInRange(long nativePtr, int offset, int length) {
- var p = getInstance(nativePtr);
-
- // Original code: hasFileDescriptorsInRange() in frameworks/native/libs/binder/Parcel.cpp
- if (offset < 0 || length < 0) {
- throw new IllegalArgumentException("Negative value not allowed: offset=" + offset
- + " length=" + length);
- }
- long limit = (long) offset + (long) length;
- if (limit > p.mSize) {
- throw new IllegalArgumentException("Out of range: offset=" + offset
- + " length=" + length + " dataSize=" + p.mSize);
- }
-
- for (var pos : p.mFdMap.keySet()) {
- if (offset <= pos && (pos + FD_PAYLOAD_SIZE - 1) < (offset + length)) {
- return true;
- }
- }
- return false;
- }
-} \ No newline at end of file
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java
deleted file mode 100644
index b00cee02f611..000000000000
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2024 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.platform.test.ravenwood.nativesubstitution;
-
-import android.platform.test.ravenwood.RavenwoodSystemProperties;
-import android.util.Log;
-
-import com.android.internal.ravenwood.RavenwoodEnvironment;
-import com.android.ravenwood.common.RavenwoodCommonUtils;
-
-public class RavenwoodEnvironment_host {
- private static final String TAG = RavenwoodEnvironment.TAG;
-
- private static final Object sInitializeLock = new Object();
-
- // @GuardedBy("sInitializeLock")
- private static boolean sInitialized;
-
- private RavenwoodEnvironment_host() {
- }
-
- /**
- * Called from {@link RavenwoodEnvironment#ensureRavenwoodInitialized()}.
- */
- public static void ensureRavenwoodInitializedInternal() {
- synchronized (sInitializeLock) {
- if (sInitialized) {
- return;
- }
- Log.i(TAG, "Initializing Ravenwood environment");
-
- // Set the default values.
- var sysProps = RavenwoodSystemProperties.DEFAULT_VALUES;
-
- // We have a method that does it in RavenwoodRuleImpl, but we can't use that class
- // here, So just inline it.
- SystemProperties_host.initializeIfNeeded(
- sysProps.getValues(),
- sysProps.getKeyReadablePredicate(),
- sysProps.getKeyWritablePredicate());
-
- sInitialized = true;
- }
- }
-} \ No newline at end of file
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
index e198646d4e27..be8c44388435 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
@@ -15,49 +15,10 @@
*/
package com.android.platform.test.ravenwood.runtimehelper;
-import com.android.ravenwood.common.RavenwoodCommonUtils;
-
-import java.io.File;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-
/**
* Standard class loader hook.
- *
- * Currently, we use this class to load libandroid_runtime (if needed). In the future, we may
- * load other JNI or do other set up here.
*/
public class ClassLoadHook {
- /**
- * If true, we won't load `libandroid_runtime`
- *
- * <p>Looks like there's some complexity in running a host test with JNI with `atest`,
- * so we need a way to remove the dependency.
- */
- private static final boolean SKIP_LOADING_LIBANDROID = "1".equals(System.getenv(
- "RAVENWOOD_SKIP_LOADING_LIBANDROID"));
-
- public static final String CORE_NATIVE_CLASSES = "core_native_classes";
- public static final String ICU_DATA_PATH = "icu.data.path";
- public static final String KEYBOARD_PATHS = "keyboard_paths";
- public static final String GRAPHICS_NATIVE_CLASSES = "graphics_native_classes";
-
- public static final String LIBANDROID_RUNTIME_NAME = "android_runtime";
-
- /**
- * Extra strings needed to pass to register_android_graphics_classes().
- *
- * `android.graphics.Graphics` is not actually a class, so we can't use the same initialization
- * strategy than the "normal" classes. So we just hardcode it here.
- */
- public static final String GRAPHICS_EXTRA_INIT_PARAMS = ",android.graphics.Graphics";
-
- private static String sInitialDir = new File("").getAbsolutePath();
-
- static {
- log("Initialized. Current dir=" + sInitialDir);
- }
-
private ClassLoadHook() {
}
@@ -70,129 +31,12 @@ public class ClassLoadHook {
public static void onClassLoaded(Class<?> clazz) {
System.out.println("Framework class loaded: " + clazz.getCanonicalName());
- loadFrameworkNativeCode();
- }
-
- private static void log(String message) {
- System.out.println("ClassLoadHook: " + message);
- }
-
- private static void log(String fmt, Object... args) {
- log(String.format(fmt, args));
- }
-
- private static void ensurePropertyNotSet(String key) {
- if (System.getProperty(key) != null) {
- throw new RuntimeException("System property \"" + key + "\" is set unexpectedly");
- }
- }
-
- private static void setProperty(String key, String value) {
- System.setProperty(key, value);
- log("Property set: %s=\"%s\"", key, value);
- }
-
- private static void dumpSystemProperties() {
- for (var prop : System.getProperties().entrySet()) {
- log(" %s=\"%s\"", prop.getKey(), prop.getValue());
+ // Always try to initialize the environment in case classes are loaded before
+ // RavenwoodAwareTestRunner is initialized
+ try {
+ Class.forName("android.platform.test.ravenwood.RavenwoodRuntimeEnvironmentController")
+ .getMethod("globalInitOnce").invoke(null);
+ } catch (ReflectiveOperationException ignored) {
}
}
-
- private static boolean sLoadFrameworkNativeCodeCalled = false;
-
- /**
- * Load `libandroid_runtime` if needed.
- */
- private static void loadFrameworkNativeCode() {
- // This is called from class-initializers, so no synchronization is needed.
- if (sLoadFrameworkNativeCodeCalled) {
- return;
- }
- sLoadFrameworkNativeCodeCalled = true;
-
- // libandroid_runtime uses Java's system properties to decide what JNI methods to set up.
- // Set up these properties for host-side tests.
-
- if ("1".equals(System.getenv("RAVENWOOD_DUMP_PROPERTIES"))) {
- log("Java system properties:");
- dumpSystemProperties();
- }
-
- if (SKIP_LOADING_LIBANDROID) {
- log("Skip loading native runtime.");
- return;
- }
-
- // Make sure these properties are not set.
- ensurePropertyNotSet(CORE_NATIVE_CLASSES);
- ensurePropertyNotSet(ICU_DATA_PATH);
- ensurePropertyNotSet(KEYBOARD_PATHS);
- ensurePropertyNotSet(GRAPHICS_NATIVE_CLASSES);
-
- // Load the libraries, if needed.
- final var libanrdoidClasses = getClassesWithNativeMethods(sLibandroidClasses);
- final var libhwuiClasses = getClassesWithNativeMethods(sLibhwuiClasses);
- if (libanrdoidClasses.isEmpty() && libhwuiClasses.isEmpty()) {
- log("No classes require JNI methods, skip loading native runtime.");
- return;
- }
- setProperty(CORE_NATIVE_CLASSES, libanrdoidClasses);
- setProperty(GRAPHICS_NATIVE_CLASSES, libhwuiClasses + GRAPHICS_EXTRA_INIT_PARAMS);
-
- log("Loading " + LIBANDROID_RUNTIME_NAME + " for '" + libanrdoidClasses + "' and '"
- + libhwuiClasses + "'");
- RavenwoodCommonUtils.loadJniLibrary(LIBANDROID_RUNTIME_NAME);
- }
-
- /**
- * Classes with native methods that are backed by libandroid_runtime.
- *
- * See frameworks/base/core/jni/platform/host/HostRuntime.cpp
- */
- private static final Class<?>[] sLibandroidClasses = {
- android.util.Log.class,
- };
-
- /**
- * Classes with native methods that are backed by libhwui.
- *
- * See frameworks/base/libs/hwui/apex/LayoutlibLoader.cpp
- */
- private static final Class<?>[] sLibhwuiClasses = {
- android.graphics.Interpolator.class,
- android.graphics.Matrix.class,
- android.graphics.Path.class,
- android.graphics.Color.class,
- android.graphics.ColorSpace.class,
- };
-
- /**
- * @return if a given class and its nested classes, if any, have any native method or not.
- */
- private static boolean hasNativeMethod(Class<?> clazz) {
- for (var nestedClass : clazz.getNestMembers()) {
- for (var method : nestedClass.getDeclaredMethods()) {
- if (Modifier.isNative(method.getModifiers())) {
- return true;
- }
- }
- }
- return false;
- }
- /**
- * Create a list of classes as comma-separated that require JNI methods to be set up from
- * a given class list, ignoring classes with no native methods.
- */
- private static String getClassesWithNativeMethods(Class<?>[] classes) {
- final var coreNativeClassesToLoad = new ArrayList<String>();
-
- for (var clazz : classes) {
- if (hasNativeMethod(clazz)) {
- log("Class %s has native methods", clazz.getCanonicalName());
- coreNativeClassesToLoad.add(clazz.getName());
- }
- }
-
- return String.join(",", coreNativeClassesToLoad);
- }
}
diff --git a/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java b/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java
index ecaa8161ee46..c94ef31a5e5e 100644
--- a/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java
+++ b/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java
@@ -15,11 +15,15 @@
*/
package android.system;
+import com.android.ravenwood.RavenwoodRuntimeNative;
import com.android.ravenwood.common.JvmWorkaround;
-import com.android.ravenwood.common.RavenwoodRuntimeNative;
import java.io.FileDescriptor;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.AsynchronousCloseException;
/**
* OS class replacement used on Ravenwood. For now, we just implement APIs as we need them...
@@ -36,6 +40,11 @@ public final class Os {
return RavenwoodRuntimeNative.pipe2(flags);
}
+ /** Ravenwood version of the OS API. */
+ public static FileDescriptor[] pipe() throws ErrnoException {
+ return RavenwoodRuntimeNative.pipe2(0);
+ }
+
public static FileDescriptor dup(FileDescriptor fd) throws ErrnoException {
return RavenwoodRuntimeNative.dup(fd);
}
@@ -69,4 +78,23 @@ public final class Os {
public static FileDescriptor open(String path, int flags, int mode) throws ErrnoException {
return RavenwoodRuntimeNative.open(path, flags, mode);
}
+
+ /** Ravenwood version of the OS API. */
+ public static int pread(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount,
+ long offset) throws ErrnoException, InterruptedIOException {
+ var channel = new FileInputStream(fd).getChannel();
+ var buf = ByteBuffer.wrap(bytes, byteOffset, byteCount);
+ try {
+ return channel.read(buf, offset);
+ } catch (AsynchronousCloseException e) {
+ throw new InterruptedIOException(e.getMessage());
+ } catch (IOException e) {
+ // Most likely EIO
+ throw new ErrnoException("pread", OsConstants.EIO, e);
+ }
+ }
+
+ public static void setenv(String name, String value, boolean overwrite) throws ErrnoException {
+ RavenwoodRuntimeNative.setenv(name, value, overwrite);
+ }
}
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/ParcelFileDescriptor_host.java b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodJdkPatch.java
index 5a3589dae43a..96aed4b3401d 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/ParcelFileDescriptor_host.java
+++ b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodJdkPatch.java
@@ -13,19 +13,37 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package com.android.platform.test.ravenwood.nativesubstitution;
+package com.android.ravenwood;
import com.android.ravenwood.common.JvmWorkaround;
import java.io.FileDescriptor;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Class to host APIs that exist in libcore, but not in standard JRE.
+ */
+public class RavenwoodJdkPatch {
+ /**
+ * Implements FileDescriptor.getInt$()
+ */
+ public static int getInt$(FileDescriptor fd) {
+ return JvmWorkaround.getInstance().getFdInt(fd);
+ }
-public class ParcelFileDescriptor_host {
- public static void setFdInt(FileDescriptor fd, int fdInt) {
- JvmWorkaround.getInstance().setFdInt(fd, fdInt);
+ /**
+ * Implements FileDescriptor.setInt$(int)
+ */
+ public static void setInt$(FileDescriptor fd, int rawFd) {
+ JvmWorkaround.getInstance().setFdInt(fd, rawFd);
}
- public static int getFdInt(FileDescriptor fd) {
- return JvmWorkaround.getInstance().getFdInt(fd);
+ /**
+ * Implements LinkedHashMap.eldest()
+ */
+ public static <K, V> Map.Entry<K, V> eldest(LinkedHashMap<K, V> map) {
+ final var it = map.entrySet().iterator();
+ return it.hasNext() ? it.next() : null;
}
}
diff --git a/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/common/RavenwoodRuntimeNative.java b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java
index beba83391652..ad80d92686ab 100644
--- a/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/common/RavenwoodRuntimeNative.java
+++ b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java
@@ -13,11 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.ravenwood.common;
+package com.android.ravenwood;
import android.system.ErrnoException;
import android.system.StructStat;
+import com.android.ravenwood.common.JvmWorkaround;
+import com.android.ravenwood.common.RavenwoodCommonUtils;
+
import java.io.FileDescriptor;
/**
@@ -50,6 +53,9 @@ public class RavenwoodRuntimeNative {
private static native int nOpen(String path, int flags, int mode) throws ErrnoException;
+ public static native void setenv(String name, String value, boolean overwrite)
+ throws ErrnoException;
+
public static long lseek(FileDescriptor fd, long offset, int whence) throws ErrnoException {
return nLseek(JvmWorkaround.getInstance().getFdInt(fd), offset, whence);
}
diff --git a/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java b/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java
index 7d2b00d9420d..ba89f71dde8a 100644
--- a/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java
+++ b/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java
@@ -19,6 +19,8 @@ package dalvik.system;
// The original is here:
// $ANDROID_BUILD_TOP/libcore/libart/src/main/java/dalvik/system/VMRuntime.java
+import com.android.ravenwood.common.JvmWorkaround;
+
import java.lang.reflect.Array;
public class VMRuntime {
@@ -32,14 +34,22 @@ public class VMRuntime {
}
public boolean is64Bit() {
- return true;
+ return "amd64".equals(System.getProperty("os.arch"));
}
public static boolean is64BitAbi(String abi) {
- return true;
+ return abi.contains("64");
}
public Object newUnpaddedArray(Class<?> componentType, int minLength) {
return Array.newInstance(componentType, minLength);
}
+
+ public Object newNonMovableArray(Class<?> componentType, int length) {
+ return Array.newInstance(componentType, length);
+ }
+
+ public long addressOf(Object obj) {
+ return JvmWorkaround.getInstance().addressOf(obj);
+ }
}
diff --git a/ravenwood/runtime-helper-src/libcore-fake/libcore/io/IoUtils.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/io/IoUtils.java
index 65c285e06bf8..2bd1ae89c824 100644
--- a/ravenwood/runtime-helper-src/libcore-fake/libcore/io/IoUtils.java
+++ b/ravenwood/runtime-helper-src/libcore-fake/libcore/io/IoUtils.java
@@ -16,7 +16,13 @@
package libcore.io;
+import android.system.ErrnoException;
+import android.system.Os;
+
+import com.android.ravenwood.common.JvmWorkaround;
+
import java.io.File;
+import java.io.FileDescriptor;
import java.io.IOException;
import java.net.Socket;
@@ -47,6 +53,13 @@ public final class IoUtils {
}
}
+ public static void closeQuietly(FileDescriptor fd) {
+ try {
+ Os.close(fd);
+ } catch (ErrnoException ignored) {
+ }
+ }
+
public static void deleteContents(File dir) throws IOException {
File[] files = dir.listFiles();
if (files != null) {
@@ -58,4 +71,17 @@ public final class IoUtils {
}
}
}
+
+ /**
+ * FD owners currently unsupported under Ravenwood; ignored
+ */
+ public static void setFdOwner(FileDescriptor fd, Object owner) {
+ }
+
+ /**
+ * FD owners currently unsupported under Ravenwood; return FD directly
+ */
+ public static int acquireRawFd(FileDescriptor fd) {
+ return JvmWorkaround.getInstance().getFdInt(fd);
+ }
}
diff --git a/ravenwood/runtime-helper-src/libcore-fake/libcore/util/FP16.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/FP16.java
new file mode 100644
index 000000000000..478503b699a0
--- /dev/null
+++ b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/FP16.java
@@ -0,0 +1,814 @@
+/*
+ * Copyright (C) 2019 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 libcore.util;
+
+/**
+ * <p>The {@code FP16} class is a wrapper and a utility class to manipulate half-precision 16-bit
+ * <a href="https://en.wikipedia.org/wiki/Half-precision_floating-point_format">IEEE 754</a>
+ * floating point data types (also called fp16 or binary16). A half-precision float can be
+ * created from or converted to single-precision floats, and is stored in a short data type.
+ *
+ * <p>The IEEE 754 standard specifies an fp16 as having the following format:</p>
+ * <ul>
+ * <li>Sign bit: 1 bit</li>
+ * <li>Exponent width: 5 bits</li>
+ * <li>Significand: 10 bits</li>
+ * </ul>
+ *
+ * <p>The format is laid out as follows:</p>
+ * <pre>
+ * 1 11111 1111111111
+ * ^ --^-- -----^----
+ * sign | |_______ significand
+ * |
+ * -- exponent
+ * </pre>
+ *
+ * <p>Half-precision floating points can be useful to save memory and/or
+ * bandwidth at the expense of range and precision when compared to single-precision
+ * floating points (fp32).</p>
+ * <p>To help you decide whether fp16 is the right storage type for you need, please
+ * refer to the table below that shows the available precision throughout the range of
+ * possible values. The <em>precision</em> column indicates the step size between two
+ * consecutive numbers in a specific part of the range.</p>
+ *
+ * <table summary="Precision of fp16 across the range">
+ * <tr><th>Range start</th><th>Precision</th></tr>
+ * <tr><td>0</td><td>1 &frasl; 16,777,216</td></tr>
+ * <tr><td>1 &frasl; 16,384</td><td>1 &frasl; 16,777,216</td></tr>
+ * <tr><td>1 &frasl; 8,192</td><td>1 &frasl; 8,388,608</td></tr>
+ * <tr><td>1 &frasl; 4,096</td><td>1 &frasl; 4,194,304</td></tr>
+ * <tr><td>1 &frasl; 2,048</td><td>1 &frasl; 2,097,152</td></tr>
+ * <tr><td>1 &frasl; 1,024</td><td>1 &frasl; 1,048,576</td></tr>
+ * <tr><td>1 &frasl; 512</td><td>1 &frasl; 524,288</td></tr>
+ * <tr><td>1 &frasl; 256</td><td>1 &frasl; 262,144</td></tr>
+ * <tr><td>1 &frasl; 128</td><td>1 &frasl; 131,072</td></tr>
+ * <tr><td>1 &frasl; 64</td><td>1 &frasl; 65,536</td></tr>
+ * <tr><td>1 &frasl; 32</td><td>1 &frasl; 32,768</td></tr>
+ * <tr><td>1 &frasl; 16</td><td>1 &frasl; 16,384</td></tr>
+ * <tr><td>1 &frasl; 8</td><td>1 &frasl; 8,192</td></tr>
+ * <tr><td>1 &frasl; 4</td><td>1 &frasl; 4,096</td></tr>
+ * <tr><td>1 &frasl; 2</td><td>1 &frasl; 2,048</td></tr>
+ * <tr><td>1</td><td>1 &frasl; 1,024</td></tr>
+ * <tr><td>2</td><td>1 &frasl; 512</td></tr>
+ * <tr><td>4</td><td>1 &frasl; 256</td></tr>
+ * <tr><td>8</td><td>1 &frasl; 128</td></tr>
+ * <tr><td>16</td><td>1 &frasl; 64</td></tr>
+ * <tr><td>32</td><td>1 &frasl; 32</td></tr>
+ * <tr><td>64</td><td>1 &frasl; 16</td></tr>
+ * <tr><td>128</td><td>1 &frasl; 8</td></tr>
+ * <tr><td>256</td><td>1 &frasl; 4</td></tr>
+ * <tr><td>512</td><td>1 &frasl; 2</td></tr>
+ * <tr><td>1,024</td><td>1</td></tr>
+ * <tr><td>2,048</td><td>2</td></tr>
+ * <tr><td>4,096</td><td>4</td></tr>
+ * <tr><td>8,192</td><td>8</td></tr>
+ * <tr><td>16,384</td><td>16</td></tr>
+ * <tr><td>32,768</td><td>32</td></tr>
+ * </table>
+ *
+ * <p>This table shows that numbers higher than 1024 lose all fractional precision.</p>
+ *
+ * @hide
+ */
+
+public final class FP16 {
+ /**
+ * The number of bits used to represent a half-precision float value.
+ *
+ * @hide
+ */
+ public static final int SIZE = 16;
+
+ /**
+ * Epsilon is the difference between 1.0 and the next value representable
+ * by a half-precision floating-point.
+ *
+ * @hide
+ */
+ public static final short EPSILON = (short) 0x1400;
+
+ /**
+ * Maximum exponent a finite half-precision float may have.
+ *
+ * @hide
+ */
+ public static final int MAX_EXPONENT = 15;
+ /**
+ * Minimum exponent a normalized half-precision float may have.
+ *
+ * @hide
+ */
+ public static final int MIN_EXPONENT = -14;
+
+ /**
+ * Smallest negative value a half-precision float may have.
+ *
+ * @hide
+ */
+ public static final short LOWEST_VALUE = (short) 0xfbff;
+ /**
+ * Maximum positive finite value a half-precision float may have.
+ *
+ * @hide
+ */
+ public static final short MAX_VALUE = (short) 0x7bff;
+ /**
+ * Smallest positive normal value a half-precision float may have.
+ *
+ * @hide
+ */
+ public static final short MIN_NORMAL = (short) 0x0400;
+ /**
+ * Smallest positive non-zero value a half-precision float may have.
+ *
+ * @hide
+ */
+ public static final short MIN_VALUE = (short) 0x0001;
+ /**
+ * A Not-a-Number representation of a half-precision float.
+ *
+ * @hide
+ */
+ public static final short NaN = (short) 0x7e00;
+ /**
+ * Negative infinity of type half-precision float.
+ *
+ * @hide
+ */
+ public static final short NEGATIVE_INFINITY = (short) 0xfc00;
+ /**
+ * Negative 0 of type half-precision float.
+ *
+ * @hide
+ */
+ public static final short NEGATIVE_ZERO = (short) 0x8000;
+ /**
+ * Positive infinity of type half-precision float.
+ *
+ * @hide
+ */
+ public static final short POSITIVE_INFINITY = (short) 0x7c00;
+ /**
+ * Positive 0 of type half-precision float.
+ *
+ * @hide
+ */
+ public static final short POSITIVE_ZERO = (short) 0x0000;
+
+ /**
+ * The offset to shift by to obtain the sign bit.
+ *
+ * @hide
+ */
+ public static final int SIGN_SHIFT = 15;
+
+ /**
+ * The offset to shift by to obtain the exponent bits.
+ *
+ * @hide
+ */
+ public static final int EXPONENT_SHIFT = 10;
+
+ /**
+ * The bitmask to AND a number with to obtain the sign bit.
+ *
+ * @hide
+ */
+ public static final int SIGN_MASK = 0x8000;
+
+ /**
+ * The bitmask to AND a number shifted by {@link #EXPONENT_SHIFT} right, to obtain exponent bits.
+ *
+ * @hide
+ */
+ public static final int SHIFTED_EXPONENT_MASK = 0x1f;
+
+ /**
+ * The bitmask to AND a number with to obtain significand bits.
+ *
+ * @hide
+ */
+ public static final int SIGNIFICAND_MASK = 0x3ff;
+
+ /**
+ * The bitmask to AND with to obtain exponent and significand bits.
+ *
+ * @hide
+ */
+ public static final int EXPONENT_SIGNIFICAND_MASK = 0x7fff;
+
+ /**
+ * The offset of the exponent from the actual value.
+ *
+ * @hide
+ */
+ public static final int EXPONENT_BIAS = 15;
+
+ private static final int FP32_SIGN_SHIFT = 31;
+ private static final int FP32_EXPONENT_SHIFT = 23;
+ private static final int FP32_SHIFTED_EXPONENT_MASK = 0xff;
+ private static final int FP32_SIGNIFICAND_MASK = 0x7fffff;
+ private static final int FP32_EXPONENT_BIAS = 127;
+ private static final int FP32_QNAN_MASK = 0x400000;
+ private static final int FP32_DENORMAL_MAGIC = 126 << 23;
+ private static final float FP32_DENORMAL_FLOAT = Float.intBitsToFloat(FP32_DENORMAL_MAGIC);
+
+ /** Hidden constructor to prevent instantiation. */
+ private FP16() {}
+
+ /**
+ * <p>Compares the two specified half-precision float values. The following
+ * conditions apply during the comparison:</p>
+ *
+ * <ul>
+ * <li>{@link #NaN} is considered by this method to be equal to itself and greater
+ * than all other half-precision float values (including {@code #POSITIVE_INFINITY})</li>
+ * <li>{@link #POSITIVE_ZERO} is considered by this method to be greater than
+ * {@link #NEGATIVE_ZERO}.</li>
+ * </ul>
+ *
+ * @param x The first half-precision float value to compare.
+ * @param y The second half-precision float value to compare
+ *
+ * @return The value {@code 0} if {@code x} is numerically equal to {@code y}, a
+ * value less than {@code 0} if {@code x} is numerically less than {@code y},
+ * and a value greater than {@code 0} if {@code x} is numerically greater
+ * than {@code y}
+ *
+ * @hide
+ */
+ public static int compare(short x, short y) {
+ if (less(x, y)) return -1;
+ if (greater(x, y)) return 1;
+
+ // Collapse NaNs, akin to halfToIntBits(), but we want to keep
+ // (signed) short value types to preserve the ordering of -0.0
+ // and +0.0
+ short xBits = isNaN(x) ? NaN : x;
+ short yBits = isNaN(y) ? NaN : y;
+
+ return (xBits == yBits ? 0 : (xBits < yBits ? -1 : 1));
+ }
+
+ /**
+ * Returns the closest integral half-precision float value to the specified
+ * half-precision float value. Special values are handled in the
+ * following ways:
+ * <ul>
+ * <li>If the specified half-precision float is NaN, the result is NaN</li>
+ * <li>If the specified half-precision float is infinity (negative or positive),
+ * the result is infinity (with the same sign)</li>
+ * <li>If the specified half-precision float is zero (negative or positive),
+ * the result is zero (with the same sign)</li>
+ * </ul>
+ *
+ * @param h A half-precision float value
+ * @return The value of the specified half-precision float rounded to the nearest
+ * half-precision float value
+ *
+ * @hide
+ */
+ public static short rint(short h) {
+ int bits = h & 0xffff;
+ int abs = bits & EXPONENT_SIGNIFICAND_MASK;
+ int result = bits;
+
+ if (abs < 0x3c00) {
+ result &= SIGN_MASK;
+ if (abs > 0x3800){
+ result |= 0x3c00;
+ }
+ } else if (abs < 0x6400) {
+ int exp = 25 - (abs >> 10);
+ int mask = (1 << exp) - 1;
+ result += ((1 << (exp - 1)) - (~(abs >> exp) & 1));
+ result &= ~mask;
+ }
+ if (isNaN((short) result)) {
+ // if result is NaN mask with qNaN
+ // (i.e. mask the most significant mantissa bit with 1)
+ // to comply with hardware implementations (ARM64, Intel, etc).
+ result |= NaN;
+ }
+
+ return (short) result;
+ }
+
+ /**
+ * Returns the smallest half-precision float value toward negative infinity
+ * greater than or equal to the specified half-precision float value.
+ * Special values are handled in the following ways:
+ * <ul>
+ * <li>If the specified half-precision float is NaN, the result is NaN</li>
+ * <li>If the specified half-precision float is infinity (negative or positive),
+ * the result is infinity (with the same sign)</li>
+ * <li>If the specified half-precision float is zero (negative or positive),
+ * the result is zero (with the same sign)</li>
+ * </ul>
+ *
+ * @param h A half-precision float value
+ * @return The smallest half-precision float value toward negative infinity
+ * greater than or equal to the specified half-precision float value
+ *
+ * @hide
+ */
+ public static short ceil(short h) {
+ int bits = h & 0xffff;
+ int abs = bits & EXPONENT_SIGNIFICAND_MASK;
+ int result = bits;
+
+ if (abs < 0x3c00) {
+ result &= SIGN_MASK;
+ result |= 0x3c00 & -(~(bits >> 15) & (abs != 0 ? 1 : 0));
+ } else if (abs < 0x6400) {
+ abs = 25 - (abs >> 10);
+ int mask = (1 << abs) - 1;
+ result += mask & ((bits >> 15) - 1);
+ result &= ~mask;
+ }
+ if (isNaN((short) result)) {
+ // if result is NaN mask with qNaN
+ // (i.e. mask the most significant mantissa bit with 1)
+ // to comply with hardware implementations (ARM64, Intel, etc).
+ result |= NaN;
+ }
+
+ return (short) result;
+ }
+
+ /**
+ * Returns the largest half-precision float value toward positive infinity
+ * less than or equal to the specified half-precision float value.
+ * Special values are handled in the following ways:
+ * <ul>
+ * <li>If the specified half-precision float is NaN, the result is NaN</li>
+ * <li>If the specified half-precision float is infinity (negative or positive),
+ * the result is infinity (with the same sign)</li>
+ * <li>If the specified half-precision float is zero (negative or positive),
+ * the result is zero (with the same sign)</li>
+ * </ul>
+ *
+ * @param h A half-precision float value
+ * @return The largest half-precision float value toward positive infinity
+ * less than or equal to the specified half-precision float value
+ *
+ * @hide
+ */
+ public static short floor(short h) {
+ int bits = h & 0xffff;
+ int abs = bits & EXPONENT_SIGNIFICAND_MASK;
+ int result = bits;
+
+ if (abs < 0x3c00) {
+ result &= SIGN_MASK;
+ result |= 0x3c00 & (bits > 0x8000 ? 0xffff : 0x0);
+ } else if (abs < 0x6400) {
+ abs = 25 - (abs >> 10);
+ int mask = (1 << abs) - 1;
+ result += mask & -(bits >> 15);
+ result &= ~mask;
+ }
+ if (isNaN((short) result)) {
+ // if result is NaN mask with qNaN
+ // i.e. (Mask the most significant mantissa bit with 1)
+ result |= NaN;
+ }
+
+ return (short) result;
+ }
+
+ /**
+ * Returns the truncated half-precision float value of the specified
+ * half-precision float value. Special values are handled in the following ways:
+ * <ul>
+ * <li>If the specified half-precision float is NaN, the result is NaN</li>
+ * <li>If the specified half-precision float is infinity (negative or positive),
+ * the result is infinity (with the same sign)</li>
+ * <li>If the specified half-precision float is zero (negative or positive),
+ * the result is zero (with the same sign)</li>
+ * </ul>
+ *
+ * @param h A half-precision float value
+ * @return The truncated half-precision float value of the specified
+ * half-precision float value
+ *
+ * @hide
+ */
+ public static short trunc(short h) {
+ int bits = h & 0xffff;
+ int abs = bits & EXPONENT_SIGNIFICAND_MASK;
+ int result = bits;
+
+ if (abs < 0x3c00) {
+ result &= SIGN_MASK;
+ } else if (abs < 0x6400) {
+ abs = 25 - (abs >> 10);
+ int mask = (1 << abs) - 1;
+ result &= ~mask;
+ }
+
+ return (short) result;
+ }
+
+ /**
+ * Returns the smaller of two half-precision float values (the value closest
+ * to negative infinity). Special values are handled in the following ways:
+ * <ul>
+ * <li>If either value is NaN, the result is NaN</li>
+ * <li>{@link #NEGATIVE_ZERO} is smaller than {@link #POSITIVE_ZERO}</li>
+ * </ul>
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ * @return The smaller of the two specified half-precision values
+ *
+ * @hide
+ */
+ public static short min(short x, short y) {
+ if (isNaN(x)) return NaN;
+ if (isNaN(y)) return NaN;
+
+ if ((x & EXPONENT_SIGNIFICAND_MASK) == 0 && (y & EXPONENT_SIGNIFICAND_MASK) == 0) {
+ return (x & SIGN_MASK) != 0 ? x : y;
+ }
+
+ return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <
+ ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y;
+ }
+
+ /**
+ * Returns the larger of two half-precision float values (the value closest
+ * to positive infinity). Special values are handled in the following ways:
+ * <ul>
+ * <li>If either value is NaN, the result is NaN</li>
+ * <li>{@link #POSITIVE_ZERO} is greater than {@link #NEGATIVE_ZERO}</li>
+ * </ul>
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ *
+ * @return The larger of the two specified half-precision values
+ *
+ * @hide
+ */
+ public static short max(short x, short y) {
+ if (isNaN(x)) return NaN;
+ if (isNaN(y)) return NaN;
+
+ if ((x & EXPONENT_SIGNIFICAND_MASK) == 0 && (y & EXPONENT_SIGNIFICAND_MASK) == 0) {
+ return (x & SIGN_MASK) != 0 ? y : x;
+ }
+
+ return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >
+ ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y;
+ }
+
+ /**
+ * Returns true if the first half-precision float value is less (smaller
+ * toward negative infinity) than the second half-precision float value.
+ * If either of the values is NaN, the result is false.
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ *
+ * @return True if x is less than y, false otherwise
+ *
+ * @hide
+ */
+ public static boolean less(short x, short y) {
+ if (isNaN(x)) return false;
+ if (isNaN(y)) return false;
+
+ return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <
+ ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+ }
+
+ /**
+ * Returns true if the first half-precision float value is less (smaller
+ * toward negative infinity) than or equal to the second half-precision
+ * float value. If either of the values is NaN, the result is false.
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ *
+ * @return True if x is less than or equal to y, false otherwise
+ *
+ * @hide
+ */
+ public static boolean lessEquals(short x, short y) {
+ if (isNaN(x)) return false;
+ if (isNaN(y)) return false;
+
+ return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <=
+ ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+ }
+
+ /**
+ * Returns true if the first half-precision float value is greater (larger
+ * toward positive infinity) than the second half-precision float value.
+ * If either of the values is NaN, the result is false.
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ *
+ * @return True if x is greater than y, false otherwise
+ *
+ * @hide
+ */
+ public static boolean greater(short x, short y) {
+ if (isNaN(x)) return false;
+ if (isNaN(y)) return false;
+
+ return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >
+ ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+ }
+
+ /**
+ * Returns true if the first half-precision float value is greater (larger
+ * toward positive infinity) than or equal to the second half-precision float
+ * value. If either of the values is NaN, the result is false.
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ *
+ * @return True if x is greater than y, false otherwise
+ *
+ * @hide
+ */
+ public static boolean greaterEquals(short x, short y) {
+ if (isNaN(x)) return false;
+ if (isNaN(y)) return false;
+
+ return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >=
+ ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+ }
+
+ /**
+ * Returns true if the two half-precision float values are equal.
+ * If either of the values is NaN, the result is false. {@link #POSITIVE_ZERO}
+ * and {@link #NEGATIVE_ZERO} are considered equal.
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ *
+ * @return True if x is equal to y, false otherwise
+ *
+ * @hide
+ */
+ public static boolean equals(short x, short y) {
+ if (isNaN(x)) return false;
+ if (isNaN(y)) return false;
+
+ return x == y || ((x | y) & EXPONENT_SIGNIFICAND_MASK) == 0;
+ }
+
+ /**
+ * Returns true if the specified half-precision float value represents
+ * infinity, false otherwise.
+ *
+ * @param h A half-precision float value
+ * @return True if the value is positive infinity or negative infinity,
+ * false otherwise
+ *
+ * @hide
+ */
+ public static boolean isInfinite(short h) {
+ return (h & EXPONENT_SIGNIFICAND_MASK) == POSITIVE_INFINITY;
+ }
+
+ /**
+ * Returns true if the specified half-precision float value represents
+ * a Not-a-Number, false otherwise.
+ *
+ * @param h A half-precision float value
+ * @return True if the value is a NaN, false otherwise
+ *
+ * @hide
+ */
+ public static boolean isNaN(short h) {
+ return (h & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY;
+ }
+
+ /**
+ * Returns true if the specified half-precision float value is normalized
+ * (does not have a subnormal representation). If the specified value is
+ * {@link #POSITIVE_INFINITY}, {@link #NEGATIVE_INFINITY},
+ * {@link #POSITIVE_ZERO}, {@link #NEGATIVE_ZERO}, NaN or any subnormal
+ * number, this method returns false.
+ *
+ * @param h A half-precision float value
+ * @return True if the value is normalized, false otherwise
+ *
+ * @hide
+ */
+ public static boolean isNormalized(short h) {
+ return (h & POSITIVE_INFINITY) != 0 && (h & POSITIVE_INFINITY) != POSITIVE_INFINITY;
+ }
+
+ /**
+ * <p>Converts the specified half-precision float value into a
+ * single-precision float value. The following special cases are handled:</p>
+ * <ul>
+ * <li>If the input is {@link #NaN}, the returned value is {@link Float#NaN}</li>
+ * <li>If the input is {@link #POSITIVE_INFINITY} or
+ * {@link #NEGATIVE_INFINITY}, the returned value is respectively
+ * {@link Float#POSITIVE_INFINITY} or {@link Float#NEGATIVE_INFINITY}</li>
+ * <li>If the input is 0 (positive or negative), the returned value is +/-0.0f</li>
+ * <li>Otherwise, the returned value is a normalized single-precision float value</li>
+ * </ul>
+ *
+ * @param h The half-precision float value to convert to single-precision
+ * @return A normalized single-precision float value
+ *
+ * @hide
+ */
+ public static float toFloat(short h) {
+ int bits = h & 0xffff;
+ int s = bits & SIGN_MASK;
+ int e = (bits >>> EXPONENT_SHIFT) & SHIFTED_EXPONENT_MASK;
+ int m = (bits ) & SIGNIFICAND_MASK;
+
+ int outE = 0;
+ int outM = 0;
+
+ if (e == 0) { // Denormal or 0
+ if (m != 0) {
+ // Convert denorm fp16 into normalized fp32
+ float o = Float.intBitsToFloat(FP32_DENORMAL_MAGIC + m);
+ o -= FP32_DENORMAL_FLOAT;
+ return s == 0 ? o : -o;
+ }
+ } else {
+ outM = m << 13;
+ if (e == 0x1f) { // Infinite or NaN
+ outE = 0xff;
+ if (outM != 0) { // SNaNs are quieted
+ outM |= FP32_QNAN_MASK;
+ }
+ } else {
+ outE = e - EXPONENT_BIAS + FP32_EXPONENT_BIAS;
+ }
+ }
+
+ int out = (s << 16) | (outE << FP32_EXPONENT_SHIFT) | outM;
+ return Float.intBitsToFloat(out);
+ }
+
+ /**
+ * <p>Converts the specified single-precision float value into a
+ * half-precision float value. The following special cases are handled:</p>
+ * <ul>
+ * <li>If the input is NaN (see {@link Float#isNaN(float)}), the returned
+ * value is {@link #NaN}</li>
+ * <li>If the input is {@link Float#POSITIVE_INFINITY} or
+ * {@link Float#NEGATIVE_INFINITY}, the returned value is respectively
+ * {@link #POSITIVE_INFINITY} or {@link #NEGATIVE_INFINITY}</li>
+ * <li>If the input is 0 (positive or negative), the returned value is
+ * {@link #POSITIVE_ZERO} or {@link #NEGATIVE_ZERO}</li>
+ * <li>If the input is a less than {@link #MIN_VALUE}, the returned value
+ * is flushed to {@link #POSITIVE_ZERO} or {@link #NEGATIVE_ZERO}</li>
+ * <li>If the input is a less than {@link #MIN_NORMAL}, the returned value
+ * is a denorm half-precision float</li>
+ * <li>Otherwise, the returned value is rounded to the nearest
+ * representable half-precision float value</li>
+ * </ul>
+ *
+ * @param f The single-precision float value to convert to half-precision
+ * @return A half-precision float value
+ *
+ * @hide
+ */
+ public static short toHalf(float f) {
+ int bits = Float.floatToRawIntBits(f);
+ int s = (bits >>> FP32_SIGN_SHIFT );
+ int e = (bits >>> FP32_EXPONENT_SHIFT) & FP32_SHIFTED_EXPONENT_MASK;
+ int m = (bits ) & FP32_SIGNIFICAND_MASK;
+
+ int outE = 0;
+ int outM = 0;
+
+ if (e == 0xff) { // Infinite or NaN
+ outE = 0x1f;
+ outM = m != 0 ? 0x200 : 0;
+ } else {
+ e = e - FP32_EXPONENT_BIAS + EXPONENT_BIAS;
+ if (e >= 0x1f) { // Overflow
+ outE = 0x1f;
+ } else if (e <= 0) { // Underflow
+ if (e < -10) {
+ // The absolute fp32 value is less than MIN_VALUE, flush to +/-0
+ } else {
+ // The fp32 value is a normalized float less than MIN_NORMAL,
+ // we convert to a denorm fp16
+ m = m | 0x800000;
+ int shift = 14 - e;
+ outM = m >> shift;
+
+ int lowm = m & ((1 << shift) - 1);
+ int hway = 1 << (shift - 1);
+ // if above halfway or exactly halfway and outM is odd
+ if (lowm + (outM & 1) > hway){
+ // Round to nearest even
+ // Can overflow into exponent bit, which surprisingly is OK.
+ // This increment relies on the +outM in the return statement below
+ outM++;
+ }
+ }
+ } else {
+ outE = e;
+ outM = m >> 13;
+ // if above halfway or exactly halfway and outM is odd
+ if ((m & 0x1fff) + (outM & 0x1) > 0x1000) {
+ // Round to nearest even
+ // Can overflow into exponent bit, which surprisingly is OK.
+ // This increment relies on the +outM in the return statement below
+ outM++;
+ }
+ }
+ }
+ // The outM is added here as the +1 increments for outM above can
+ // cause an overflow in the exponent bit which is OK.
+ return (short) ((s << SIGN_SHIFT) | (outE << EXPONENT_SHIFT) + outM);
+ }
+
+ /**
+ * <p>Returns a hexadecimal string representation of the specified half-precision
+ * float value. If the value is a NaN, the result is <code>"NaN"</code>,
+ * otherwise the result follows this format:</p>
+ * <ul>
+ * <li>If the sign is positive, no sign character appears in the result</li>
+ * <li>If the sign is negative, the first character is <code>'-'</code></li>
+ * <li>If the value is inifinity, the string is <code>"Infinity"</code></li>
+ * <li>If the value is 0, the string is <code>"0x0.0p0"</code></li>
+ * <li>If the value has a normalized representation, the exponent and
+ * significand are represented in the string in two fields. The significand
+ * starts with <code>"0x1."</code> followed by its lowercase hexadecimal
+ * representation. Trailing zeroes are removed unless all digits are 0, then
+ * a single zero is used. The significand representation is followed by the
+ * exponent, represented by <code>"p"</code>, itself followed by a decimal
+ * string of the unbiased exponent</li>
+ * <li>If the value has a subnormal representation, the significand starts
+ * with <code>"0x0."</code> followed by its lowercase hexadecimal
+ * representation. Trailing zeroes are removed unless all digits are 0, then
+ * a single zero is used. The significand representation is followed by the
+ * exponent, represented by <code>"p-14"</code></li>
+ * </ul>
+ *
+ * @param h A half-precision float value
+ * @return A hexadecimal string representation of the specified value
+ *
+ * @hide
+ */
+ public static String toHexString(short h) {
+ StringBuilder o = new StringBuilder();
+
+ int bits = h & 0xffff;
+ int s = (bits >>> SIGN_SHIFT );
+ int e = (bits >>> EXPONENT_SHIFT) & SHIFTED_EXPONENT_MASK;
+ int m = (bits ) & SIGNIFICAND_MASK;
+
+ if (e == 0x1f) { // Infinite or NaN
+ if (m == 0) {
+ if (s != 0) o.append('-');
+ o.append("Infinity");
+ } else {
+ o.append("NaN");
+ }
+ } else {
+ if (s == 1) o.append('-');
+ if (e == 0) {
+ if (m == 0) {
+ o.append("0x0.0p0");
+ } else {
+ o.append("0x0.");
+ String significand = Integer.toHexString(m);
+ o.append(significand.replaceFirst("0{2,}$", ""));
+ o.append("p-14");
+ }
+ } else {
+ o.append("0x1.");
+ String significand = Integer.toHexString(m);
+ o.append(significand.replaceFirst("0{2,}$", ""));
+ o.append('p');
+ o.append(Integer.toString(e - EXPONENT_BIAS));
+ }
+ }
+
+ return o.toString();
+ }
+}
diff --git a/ravenwood/runtime-helper-src/libcore-fake/libcore/util/NativeAllocationRegistry.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/NativeAllocationRegistry.java
index 14b5a4f0c1e0..4e7dc5d6264f 100644
--- a/ravenwood/runtime-helper-src/libcore-fake/libcore/util/NativeAllocationRegistry.java
+++ b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/NativeAllocationRegistry.java
@@ -15,7 +15,7 @@
*/
package libcore.util;
-import com.android.ravenwood.common.RavenwoodRuntimeNative;
+import com.android.ravenwood.RavenwoodRuntimeNative;
import java.lang.ref.Cleaner;
import java.lang.ref.Reference;