Merge "Revert "libcore: Remove native calls in FileDescriptor <clinit>"" into rvc-dev am: c5bf4e3807 am: 67266859ad am: 8c34163cfa
Original change: https://googleplex-android-review.googlesource.com/c/platform/libcore/+/10604244
Change-Id: Iec4c0b87f295e8c1979e449d55d530d5e1d4a57e
diff --git a/JavaLibrary.bp b/JavaLibrary.bp
index adb5b0f..0d98122 100644
--- a/JavaLibrary.bp
+++ b/JavaLibrary.bp
@@ -109,46 +109,6 @@
],
}
-// The set of files for the core library that have been marked up with @hide
-// for the public SDK APIs. Used from frameworks/base/ to indicate the source
-// files for inclusion in the public SDK docs.
-//
-// Deprecated: Will be replaced by core-current-stubs-source.
-filegroup {
- name: "core_public_api_files",
- visibility: [
- "//frameworks/base",
- ],
- srcs: [
- ":android_icu4j_public_api_files",
- ],
-}
-
-// Contains the stubs source for the part of the Android SDK public API which
-// is provided by the core libraries.
-//
-// Currently is only a placeholder that creates an empty srcjar due to issues
-// caused by http://b/142113901.
-//
-// TODO(http://b/142113521) - Add stubs source for the core library modules.
-genrule {
- name: "core-current-stubs-source",
- visibility: [
- "//frameworks/base",
- ],
- tools: [
- "merge_zips",
- ],
- srcs: [
- ":art-module-public-api-stubs-source",
- ":conscrypt-module-public-api-stubs-source",
- ],
- out: ["core-current-stubs-source.srcjar"],
- cmd: "$(location merge_zips) $(out)" +
- " $(location :art-module-public-api-stubs-source)" +
- " $(location :conscrypt-module-public-api-stubs-source)",
-}
-
// The set of files for the ART module that contribute to one or more API
// surfaces. This includes files that are in the public API as well as those
// that are not but which have been marked up with @hide plus one or more of
@@ -223,7 +183,10 @@
installable: false,
- plugins: ["compat-changeid-annotation-processor"],
+ plugins: [
+ "compat-changeid-annotation-processor",
+ "unsupportedappusage-annotation-processor",
+ ],
}
platform_compat_config {
@@ -379,6 +342,7 @@
sdk_version: "none",
system_modules: "core-all-system-modules",
patch_module: "java.base",
+ plugins: ["unsupportedappusage-annotation-processor"],
}
//
@@ -456,6 +420,7 @@
srcs: [
":openjdk_lambda_stub_files",
],
+ include_srcs: true,
}
// Creates a jar that exists to satisfy javac when compiling source code that
@@ -486,6 +451,7 @@
visibility: [
"//art/build/sdk",
"//external/conscrypt",
+ "//external/conscrypt/apex/tests",
"//frameworks/base/location/tests/locationtests",
"//frameworks/base/core/tests/coretests",
"//frameworks/base/wifi/tests",
@@ -602,8 +568,12 @@
"xml/src/test/java/**/*.java",
],
exclude_srcs: [
+ "harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/*.java",
"luni/src/test/java/libcore/java/util/zip/Zip64Test.java",
"luni/src/test/java/libcore/java/util/zip/Zip64FileTest.java",
+ "luni/src/test/java/libcore/javax/crypto/**/*.java",
+ "luni/src/test/java/libcore/javax/net/ssl/**/*.java",
+ "luni/src/test/java/org/apache/harmony/crypto/**/*.java",
],
java_resource_dirs: [
@@ -635,6 +605,7 @@
"core-test-rules",
"core-tests-support",
"junit-params",
+ "libcore-crypto-tests",
"mockftpserver",
"mockito-target",
"mockwebserver",
@@ -655,6 +626,40 @@
test_config: "AndroidTest-core-tests.xml",
}
+java_test {
+ name: "libcore-crypto-tests",
+
+ visibility: [
+ "//art/build/sdk",
+ "//external/conscrypt/apex/tests",
+ ],
+ srcs: [
+ "harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/*.java",
+ "luni/src/test/java/libcore/javax/crypto/**/*.java",
+ "luni/src/test/java/libcore/javax/net/ssl/**/*.java",
+ "luni/src/test/java/org/apache/harmony/crypto/**/*.java",
+ ],
+ exclude_srcs: [
+ "luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/SealedObjectTest.java",
+ ],
+
+ java_resource_dirs: [
+ "luni/src/test/java",
+ "luni/src/test/resources",
+ "support/src/test/java",
+ ],
+
+ sdk_version: "none",
+ system_modules: "core-all-system-modules",
+
+ static_libs: [
+ "core-test-rules",
+ "core-tests-support",
+ "junit-params",
+ "mockito-target",
+ ],
+}
+
// Builds the core-ojtests library that contains test code from OpenJDK.
java_test {
name: "core-ojtests",
@@ -834,9 +839,13 @@
// Generates stubs for the parts of the public SDK API provided by the ART module.
//
-// Only for use by art.module.public.api.stubs target below.
+// Only for use by art.module.public.api.stubs target below and the building of the
+// public API.
droidstubs {
name: "art-module-public-api-stubs-source",
+ visibility: [
+ "//frameworks/base",
+ ],
srcs: [
":core_oj_api_files",
":core_libart_api_files",
@@ -938,11 +947,12 @@
},
}
-// Used when compiling higher-level code against core.current.stubs.
-java_system_modules {
- name: "core-current-stubs-system-modules",
- visibility: ["//visibility:public"],
- libs: [
+// Distributed with the SDK for turning into system modules to compile apps
+// against.
+java_library {
+ name: "core-current-stubs-for-system-modules",
+ visibility: ["//development/sdk"],
+ static_libs: [
"core.current.stubs",
// This one is not on device but it's needed when javac compiles code
// containing lambdas.
@@ -953,6 +963,24 @@
// See http://b/123891440.
"core-generated-annotation-stubs",
],
+ sdk_version: "none",
+ system_modules: "none",
+ dist: {
+ dest: "core-for-system-modules.jar",
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
+ },
+}
+
+// Used when compiling higher-level code against core.current.stubs.
+java_system_modules {
+ name: "core-current-stubs-system-modules",
+ visibility: ["//visibility:public"],
+ libs: [
+ "core-current-stubs-for-system-modules",
+ ],
}
// Target for validating nullability annotations for correctness and
diff --git a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
index 4a9e8631..ee20d80 100644
--- a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
@@ -128,15 +128,20 @@
: Arrays.copyOf(sharedLibraryLoaders, sharedLibraryLoaders.length);
this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted);
- if (reporter != null) {
- reportClassLoaderChain();
- }
+ reportClassLoaderChain();
}
/**
* Reports the current class loader chain to the registered {@code reporter}.
+ *
+ * @hide
*/
- private void reportClassLoaderChain() {
+ @libcore.api.CorePlatformApi
+ public void reportClassLoaderChain() {
+ if (reporter == null) {
+ return;
+ }
+
String[] classPathAndClassLoaderContexts = computeClassLoaderContextsNative();
if (classPathAndClassLoaderContexts.length == 0) {
return;
@@ -367,7 +372,7 @@
/**
* Reports the construction of a BaseDexClassLoader and provides opaque information about
* the class loader chain. For example, if the childmost ClassLoader in the chain:
- * {@quote BaseDexClassLoader { foo.dex } -> BaseDexClassLoader { base.apk }
+ * {@quote BaseDexClassLoader { foo.dex } -> BaseDexClassLoader { base.apk }
* -> BootClassLoader } was just initialized then the load of {@code "foo.dex"} would be
* reported with a classLoaderContext of {@code "PCL[];PCL[base.apk]"}.
*
diff --git a/dalvik/src/main/java/dalvik/system/CloseGuard.java b/dalvik/src/main/java/dalvik/system/CloseGuard.java
index 4607f2d..99ddf3e 100644
--- a/dalvik/src/main/java/dalvik/system/CloseGuard.java
+++ b/dalvik/src/main/java/dalvik/system/CloseGuard.java
@@ -134,6 +134,9 @@
*/
private static volatile Tracker currentTracker = null; // Disabled by default.
+ private static final String MESSAGE = "A resource was acquired at attached stack trace but never released. " +
+ "See java.io.Closeable for information on avoiding resource leaks.";
+
/**
* Returns a CloseGuard instance. {@code #open(String)} can be used to set
* up the instance to warn on failure to close.
@@ -224,6 +227,21 @@
@libcore.api.CorePlatformApi
@libcore.api.IntraCoreApi
public void open(String closer) {
+ openWithCallSite(closer, null /* callsite */);
+ }
+
+ /**
+ * Like {@link #open(String)}, but with explicit callsite string being passed in for better
+ * performance.
+ * <p>
+ * This only has better performance than {@link #open(String)} if {@link #isEnabled()} returns {@code true}, which
+ * usually shouldn't happen on release builds.
+ *
+ * @param closer Non-null name of explicit termination method. Printed by warnIfOpen.
+ * @param callsite Non-null string uniquely identifying the callsite.
+ */
+ @libcore.api.CorePlatformApi
+ public void openWithCallSite(String closer, String callsite) {
// always perform the check for valid API usage...
if (closer == null) {
throw new NullPointerException("closer == null");
@@ -233,12 +251,18 @@
closerNameOrAllocationInfo = closer;
return;
}
- String message = "Explicit termination method '" + closer + "' not called";
- Throwable stack = new Throwable(message);
- closerNameOrAllocationInfo = stack;
+ // Always record stack trace when tracker installed, which only happens in tests. Otherwise, skip expensive
+ // stack trace creation when explicit callsite is passed in for better performance.
Tracker tracker = currentTracker;
- if (tracker != null) {
- tracker.open(stack);
+ if (callsite == null || tracker != null) {
+ String message = "Explicit termination method '" + closer + "' not called";
+ Throwable stack = new Throwable(message);
+ closerNameOrAllocationInfo = stack;
+ if (tracker != null) {
+ tracker.open(stack);
+ }
+ } else {
+ closerNameOrAllocationInfo = callsite;
}
}
@@ -275,19 +299,18 @@
@libcore.api.IntraCoreApi
public void warnIfOpen() {
if (closerNameOrAllocationInfo != null) {
- if (closerNameOrAllocationInfo instanceof String) {
+ if (closerNameOrAllocationInfo instanceof Throwable) {
+ reporter.report(MESSAGE, (Throwable) closerNameOrAllocationInfo);
+ } else if (stackAndTrackingEnabled) {
+ reporter.report(MESSAGE + " Callsite: " + closerNameOrAllocationInfo);
+ } else {
System.logW("A resource failed to call "
+ (String) closerNameOrAllocationInfo + ". ");
- } else {
- String message =
- "A resource was acquired at attached stack trace but never released. ";
- message += "See java.io.Closeable for information on avoiding resource leaks.";
- Throwable stack = (Throwable) closerNameOrAllocationInfo;
- reporter.report(message, stack);
}
}
}
+
/**
* Interface to allow customization of tracking behaviour.
*
@@ -308,6 +331,9 @@
@UnsupportedAppUsage
@libcore.api.CorePlatformApi
void report(String message, Throwable allocationSite);
+
+ @libcore.api.CorePlatformApi
+ default void report(String message) {}
}
/**
@@ -320,5 +346,10 @@
@Override public void report (String message, Throwable allocationSite) {
System.logW(message, allocationSite);
}
+
+ @Override
+ public void report(String message) {
+ System.logW(message);
+ }
}
}
diff --git a/dalvik/src/main/java/dalvik/system/ZygoteHooks.java b/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
index 0339b4d..7e8fe36 100644
--- a/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
+++ b/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
@@ -21,6 +21,7 @@
import android.icu.util.ULocale;
import java.io.File;
+import java.io.FileDescriptor;
/**
* Provides hooks for the zygote to call back into the runtime to perform
@@ -58,6 +59,12 @@
for (ULocale uLocale : localesToPin) {
new DecimalFormatSymbols(uLocale);
}
+
+ // Framework's LocalLog is used during app start-up. It indirectly uses the current ICU time
+ // zone. Pre-loading the current time zone in ICU improves app startup time. b/150605074
+ // We're being explicit about the fully qualified name of the TimeZone class to avoid
+ // confusion with java.util.TimeZome.getDefault().
+ android.icu.util.TimeZone.getDefault();
}
/**
@@ -67,6 +74,11 @@
public static void onEndPreload() {
// All cache references created by ICU from this point will be soft.
CacheValue.setStrength(CacheValue.Strength.SOFT);
+
+ // Clone standard descriptors as originals closed / rebound during zygote post fork.
+ FileDescriptor.in.cloneForFork();
+ FileDescriptor.out.cloneForFork();
+ FileDescriptor.err.cloneForFork();
}
/**
diff --git a/dalvik/src/test/java/libcore/dalvik/system/CloseGuardTest.java b/dalvik/src/test/java/libcore/dalvik/system/CloseGuardTest.java
index f7f58bd..92c2946 100644
--- a/dalvik/src/test/java/libcore/dalvik/system/CloseGuardTest.java
+++ b/dalvik/src/test/java/libcore/dalvik/system/CloseGuardTest.java
@@ -64,6 +64,14 @@
}
@Test
+ public void testEnabled_OpenWithCallsiteNotClosed() throws Throwable {
+ CloseGuard.setEnabled(true);
+ ResourceOwner owner = new ResourceOwner();
+ owner.openWithCallsite("testEnabled_OpoenWIthCallsiteNotClosed");
+ assertUnreleasedResources(owner, 1);
+ }
+
+ @Test
public void testEnabled_OpenThenClosed() throws Throwable {
CloseGuard.setEnabled(true);
ResourceOwner owner = new ResourceOwner();
@@ -73,6 +81,15 @@
}
@Test
+ public void testEnabled_OpenWithCallsiteThenClosed() throws Throwable {
+ CloseGuard.setEnabled(true);
+ ResourceOwner owner = new ResourceOwner();
+ owner.openWithCallsite("testEnabled_OpenWithCallsiteThenClosed");
+ owner.close();
+ assertUnreleasedResources(owner, 0);
+ }
+
+ @Test
public void testEnabledWhenCreated_DisabledWhenOpen() throws Throwable {
CloseGuard.setEnabled(true);
ResourceOwner owner = new ResourceOwner();
@@ -111,6 +128,14 @@
}
@Test
+ public void testDisabled_OpenWithCallsiteNotClosed() throws Throwable {
+ CloseGuard.setEnabled(false);
+ ResourceOwner owner = new ResourceOwner();
+ owner.openWithCallsite("testDisabled_OpenWithCallsiteNotClosed");
+ assertUnreleasedResources(owner, 0);
+ }
+
+ @Test
public void testDisabled_OpenThenClosed() throws Throwable {
CloseGuard.setEnabled(false);
ResourceOwner owner = new ResourceOwner();
@@ -120,6 +145,15 @@
}
@Test
+ public void testDisabled_OpenWithCallsiteThenClosed() throws Throwable {
+ CloseGuard.setEnabled(false);
+ ResourceOwner owner = new ResourceOwner();
+ owner.openWithCallsite("testDisabled_OpenWithCallsiteThenClosed");
+ owner.close();
+ assertUnreleasedResources(owner, 0);
+ }
+
+ @Test
public void testDisabledWhenCreated_EnabledWhenOpen() throws Throwable {
CloseGuard.setEnabled(false);
ResourceOwner owner = new ResourceOwner();
@@ -156,6 +190,10 @@
closeGuard.open("close");
}
+ public void openWithCallsite(String callsite) {
+ closeGuard.openWithCallSite("close", callsite);
+ }
+
public void close() {
closeGuard.close();
}
diff --git a/dalvik/test-rules/src/main/java/libcore/dalvik/system/CloseGuardSupport.java b/dalvik/test-rules/src/main/java/libcore/dalvik/system/CloseGuardSupport.java
index ca007a8..e419f16 100644
--- a/dalvik/test-rules/src/main/java/libcore/dalvik/system/CloseGuardSupport.java
+++ b/dalvik/test-rules/src/main/java/libcore/dalvik/system/CloseGuardSupport.java
@@ -261,6 +261,7 @@
private final Thread callingThread = Thread.currentThread();
private final List<Throwable> unreleasedResourceAllocationSites = new ArrayList<>();
+ private final List<String> unreleasedResourceAllocationCallsites = new ArrayList<>();
@Override
public void report(String message, Throwable allocationSite) {
@@ -270,8 +271,17 @@
}
}
+ @Override
+ public void report(String message) {
+ // Only care about resources that are not reported on this thread.
+ if (callingThread == Thread.currentThread()) {
+ unreleasedResourceAllocationCallsites.add(message);
+ }
+ }
+
void assertUnreleasedResources(int expectedCount) {
- int unreleasedResourceCount = unreleasedResourceAllocationSites.size();
+ int unreleasedResourceCount = unreleasedResourceAllocationSites.size()
+ + unreleasedResourceAllocationCallsites.size();
if (unreleasedResourceCount == expectedCount) {
return;
}
@@ -282,6 +292,9 @@
for (Throwable unreleasedResourceAllocationSite : unreleasedResourceAllocationSites) {
error.addSuppressed(unreleasedResourceAllocationSite);
}
+ for (String unreleasedResourceAllocationCallsite : unreleasedResourceAllocationCallsites) {
+ error.addSuppressed(new Throwable(unreleasedResourceAllocationCallsite));
+ }
throw error;
}
}
diff --git a/expectations/virtualdeviceknownfailures.txt b/expectations/virtualdeviceknownfailures.txt
index c1fa62a..b689133 100644
--- a/expectations/virtualdeviceknownfailures.txt
+++ b/expectations/virtualdeviceknownfailures.txt
@@ -24,15 +24,7 @@
},
{
description: "multicast not supported in virtual device testing infra",
- names: ["org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_InetAddress_IPv4",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_InetAddress_IPv6",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4_nullInterface",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6_nullInterface",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_leaveGroupLjava_net_InetAddress_IPv4",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_sendLjava_net_DatagramPacketB_IPv4",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_sendLjava_net_DatagramPacketB_IPv6",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_setLoopbackModeSendReceive_IPv4",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_setLoopbackModeSendReceive_IPv6",
+ names: ["org.apache.harmony.tests.java.net.MulticastSocketTest",
"libcore.java.net.MulticastSocketTest#testGroupReceiveIPv6",
"libcore.java.nio.channels.DatagramChannelMulticastTest#test_joinAnySource_IPv4",
"libcore.java.nio.channels.DatagramChannelMulticastTest#test_joinAnySource_multicastLoopOption_IPv4"
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ScannerTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ScannerTest.java
index 4a5c803..85899f3 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ScannerTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ScannerTest.java
@@ -5694,13 +5694,15 @@
}
// http://code.google.com/p/android/issues/detail?id=57050
- public void testPerformance() throws Exception {
+ // Disable this test since it causes oom failures in follow on
+ // tests. See b/160171148 for details.
+ public void disableTestPerformance() throws Exception {
int count = 100000;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(baos));
for (int i = 0; i < count; ++i) {
- out.write(Integer.toString(123) + " ");
+ out.write("123 ");
}
out.close();
@@ -5709,7 +5711,16 @@
Scanner s = new Scanner(new BufferedReader(new InputStreamReader(bais)));
for (int i = 0; i < count; ++i) {
- if (s.nextInt() != 123) {
+ final int value;
+ try {
+ value = s.nextInt();
+ } catch (RuntimeException e) {
+ String msg = String.format(Locale.US,
+ "Failed to parse float on item %d/%d with locale %s: %s",
+ (i+1), count, s.locale(), s);
+ throw new RuntimeException(msg, e);
+ }
+ if (value != 123) {
fail();
}
}
@@ -5717,9 +5728,19 @@
bais.reset();
s = new Scanner(new BufferedReader(new InputStreamReader(bais)));
for (int i = 0; i < count; ++i) {
- if (s.nextFloat() != 123.0) {
+ final float value;
+ try {
+ value = s.nextFloat();
+ } catch (RuntimeException e) {
+ String msg = String.format(Locale.US,
+ "Failed to parse float on item %d/%d with locale %s: %s",
+ (i+1), count, s.locale(), s);
+ throw new RuntimeException(msg, e);
+ }
+ if (value != 123.0) {
fail();
}
}
+ System.gc();
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/TimeZoneTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/TimeZoneTest.java
index 0d16786..b98f230 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/TimeZoneTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/TimeZoneTest.java
@@ -232,11 +232,10 @@
// Any one of these might legitimately change its raw offset, though that's
// fairly unlikely, and the chances of more than one changing are very slim.
- assertTrue(ids.toString(), ids.contains("America/Dawson"));
assertTrue(ids.toString(), ids.contains("America/Tijuana"));
+ assertTrue(ids.toString(), ids.contains("America/Ensenada")); // Alias for America/Tijuana
assertTrue(ids.toString(), ids.contains("America/Vancouver"));
- assertTrue(ids.toString(), ids.contains("Canada/Pacific"));
- assertTrue(ids.toString(), ids.contains("Canada/Yukon"));
+ assertTrue(ids.toString(), ids.contains("Canada/Pacific")); // Alias for America/Vancouver
assertTrue(ids.toString(), ids.contains("Pacific/Pitcairn"));
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContextSpiTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContextSpiTest.java
index 45e9d40..f688b9b 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContextSpiTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContextSpiTest.java
@@ -15,9 +15,16 @@
*/
package org.apache.harmony.tests.javax.net.ssl;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContextSpi;
import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.SSLSocketFactory;
@@ -28,18 +35,20 @@
import java.security.KeyStore;
import java.security.SecureRandom;
-import java.security.Security;
-
-import junit.framework.TestCase;
import org.apache.harmony.xnet.tests.support.SSLContextSpiImpl;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
-public class SSLContextSpiTest extends TestCase {
+@RunWith(JUnit4.class)
+public class SSLContextSpiTest {
/**
* javax.net.ssl.SSLContextSpi#SSLContextSpi()
*/
- public void test_Constructor() {
+ @Test
+ public void constructor() {
try {
SSLContextSpiImpl ssl = new SSLContextSpiImpl();
assertTrue(ssl instanceof SSLContextSpi);
@@ -52,7 +61,8 @@
* javax.net.ssl.SSLContextSpi#engineCreateSSLEngine()
* Verify exception when SSLContextSpi object wasn't initialiazed.
*/
- public void test_engineCreateSSLEngine_01() {
+ @Test
+ public void engineCreateSSLEngine_01() {
SSLContextSpiImpl ssl = new SSLContextSpiImpl();
try {
SSLEngine sleng = ssl.engineCreateSSLEngine();
@@ -70,7 +80,8 @@
* javax.net.ssl.SSLContextSpi#engineCreateSSLEngine(String host, int port)
* Verify exception when SSLContextSpi object wasn't initialiazed.
*/
- public void test_engineCreateSSLEngine_02() {
+ @Test
+ public void engineCreateSSLEngine_02() {
int[] invalid_port = {Integer.MIN_VALUE, -65535, -1, 65536, Integer.MAX_VALUE};
SSLContextSpiImpl ssl = new SSLContextSpiImpl();
try {
@@ -101,7 +112,8 @@
* SSLContextSpi#engineGetSocketFactory()
* Verify exception when SSLContextSpi object wasn't initialiazed.
*/
- public void test_commonTest_01() {
+ @Test
+ public void commonTest_01() {
SSLContextSpiImpl ssl = new SSLContextSpiImpl();
try {
@@ -152,34 +164,19 @@
/**
* SSLContextSpi#engineInit(KeyManager[] km, TrustManager[] tm, SecureRandom sr)
*/
- public void test_engineInit() {
+ @Test
+ public void engineInit() throws Exception {
SSLContextSpiImpl ssl = new SSLContextSpiImpl();
- String defaultAlgorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");
+ KeyManager[] km = getKeyManagers();
+ TrustManager[] tm = getTrustManagers();
+ SecureRandom sr = getSecureRandom();
+ ssl.engineInit(km, tm, sr);
+
try {
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(defaultAlgorithm);
- char[] pass = "password".toCharArray();
- kmf.init(null, pass);
- KeyManager[] km = kmf.getKeyManagers();
- defaultAlgorithm = Security.getProperty("ssl.TrustManagerFactory.algorithm");
- TrustManagerFactory trustMF = TrustManagerFactory.getInstance(defaultAlgorithm);
- KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
- ks.load(null, null);
- trustMF.init(ks);
- TrustManager[] tm = trustMF.getTrustManagers();
- SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
- try {
- ssl.engineInit(km, tm, sr);
- } catch (KeyManagementException kme) {
- fail(kme + " was throw for engineInit method");
- }
- try {
- ssl.engineInit(km, tm, null);
- fail("KeyManagementException wasn't thrown");
- } catch (KeyManagementException kme) {
- //expected
- }
- } catch (Exception ex) {
- fail(ex + " unexpected exception");
+ ssl.engineInit(km, tm, null);
+ fail("KeyManagementException wasn't thrown");
+ } catch (KeyManagementException kme) {
+ //expected
}
}
@@ -191,39 +188,77 @@
* SSLContextSpi#engineGetServerSocketFactory()
* SSLContextSpi#engineGetSocketFactory()
*/
- public void test_commonTest_02() {
+ @Test
+ public void commonTest_02() throws Exception {
SSLContextSpiImpl ssl = new SSLContextSpiImpl();
- String defaultAlgorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");
- try {
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(defaultAlgorithm);
- char[] pass = "password".toCharArray();
- kmf.init(null, pass);
- KeyManager[] km = kmf.getKeyManagers();
- defaultAlgorithm = Security.getProperty("ssl.TrustManagerFactory.algorithm");
- TrustManagerFactory trustMF = TrustManagerFactory.getInstance(defaultAlgorithm);
- KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
- ks.load(null, null);
- trustMF.init(ks);
- TrustManager[] tm = trustMF.getTrustManagers();
- SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
- ssl.engineInit(km, tm, sr);
- } catch (Exception ex) {
- fail(ex + " unexpected exception");
- }
+ ssl.engineInit(getKeyManagers(), getTrustManagers(), getSecureRandom());
- try {
- assertNotNull("Subtest_01: Object is NULL", ssl.engineCreateSSLEngine());
- SSLEngine sleng = ssl.engineCreateSSLEngine("localhost", 1080);
- assertNotNull("Subtest_02: Object is NULL", sleng);
- assertEquals(sleng.getPeerPort(), 1080);
- assertEquals(sleng.getPeerHost(), "localhost");
- assertNull("Subtest_03: Object not NULL", ssl.engineGetClientSessionContext());
- assertNull("Subtest_04: Object not NULL", ssl.engineGetServerSessionContext());
- assertNull("Subtest_05: Object not NULL", ssl.engineGetServerSocketFactory());
- assertNull("Subtest_06: Object not NULL", ssl.engineGetSocketFactory());
- } catch (Exception e) {
- fail("Unexpected exception " + e);
+ assertNotNull("Subtest_01: Object is NULL", ssl.engineCreateSSLEngine());
+ SSLEngine sleng = ssl.engineCreateSSLEngine("localhost", 1080);
+ assertNotNull("Subtest_02: Object is NULL", sleng);
+ assertEquals(sleng.getPeerPort(), 1080);
+ assertEquals(sleng.getPeerHost(), "localhost");
+ assertNull("Subtest_03: Object not NULL", ssl.engineGetClientSessionContext());
+ assertNull("Subtest_04: Object not NULL", ssl.engineGetServerSessionContext());
+ assertNull("Subtest_05: Object not NULL", ssl.engineGetServerSocketFactory());
+ assertNull("Subtest_06: Object not NULL", ssl.engineGetSocketFactory());
+ }
+
+ private static class SpiWithSocketFactory extends SSLContextSpiImpl {
+ @Override
+ public SSLSocketFactory engineGetSocketFactory() {
+ super.engineGetSocketFactory();
+ return (SSLSocketFactory) SSLSocketFactory.getDefault();
}
}
+ /**
+ * Tests the default implementations of SSLContextSpi.engineGetDefaultSSLParameters()
+ * and SSLContextSpi.engineGetSupportedSSLParameters(). Requires a subclass which
+ * returns non-null from engineGetSocketFactory() for the base class to work.
+ *
+ * Verifies the returned SSLParameters for consistency.
+ */
+ @Test
+ public void getSslParameters() throws Exception {
+ SpiWithSocketFactory spi = new SpiWithSocketFactory();
+ spi.engineInit(getKeyManagers(), getTrustManagers(), getSecureRandom());
+
+ SSLParameters defaultParams = spi.engineGetDefaultSSLParameters();
+ assertNotNull(defaultParams);
+ String[] protocols = defaultParams.getProtocols();
+ assertNotNull(protocols);
+ assertTrue(protocols.length > 0);
+ String[] cipherSuites = defaultParams.getCipherSuites();
+ assertNotNull(cipherSuites);
+ assertTrue(cipherSuites.length > 0);
+
+ SSLParameters supportedParams = spi.engineGetSupportedSSLParameters();
+ assertNotNull(supportedParams);
+ protocols = supportedParams.getProtocols();
+ assertNotNull(protocols);
+ assertTrue(protocols.length > 0);
+ cipherSuites = supportedParams.getCipherSuites();
+ assertNotNull(cipherSuites);
+ assertTrue(cipherSuites.length > 0);
+ }
+
+ private SecureRandom getSecureRandom() throws Exception {
+ return SecureRandom.getInstance("SHA1PRNG");
+ }
+
+ private TrustManager[] getTrustManagers() throws Exception {
+ TrustManagerFactory tmf = TrustManagerFactory
+ .getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ tmf.init(ks);
+ return tmf.getTrustManagers();
+ }
+
+ private KeyManager[] getKeyManagers() throws Exception {
+ KeyManagerFactory kmf = KeyManagerFactory
+ .getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(null, "password".toCharArray());
+ return kmf.getKeyManagers();
+ }
}
diff --git a/libart/src/main/java/dalvik/system/VMRuntime.java b/libart/src/main/java/dalvik/system/VMRuntime.java
index 970dcc2..321f4e3 100644
--- a/libart/src/main/java/dalvik/system/VMRuntime.java
+++ b/libart/src/main/java/dalvik/system/VMRuntime.java
@@ -28,6 +28,7 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
+import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
/**
@@ -673,6 +674,16 @@
}
/**
+ * Prevent initialization of the caller's class if they are calling
+ * from their clinit method. This works because calling a JNI method
+ * from clinit causes the transactional runtime to abort the current
+ * transaction.
+ * @hide
+ */
+ @CriticalNative
+ public static native void doNotInitializeInAot();
+
+ /**
* Return false if the boot class path for the given instruction
* set mapped from disk storage, versus being interpretted from
* dirty pages in memory.
diff --git a/libart/src/main/java/java/lang/Daemons.java b/libart/src/main/java/java/lang/Daemons.java
index 568614f..6e05cea 100644
--- a/libart/src/main/java/java/lang/Daemons.java
+++ b/libart/src/main/java/java/lang/Daemons.java
@@ -310,7 +310,7 @@
private boolean needToWork = true; // Only accessed in synchronized methods.
- private long finalizerTimeoutMs = 0; // Lazily initialized.
+ private long finalizerTimeoutNs = 0; // Lazily initialized.
FinalizerWatchdogDaemon() {
super("FinalizerWatchdogDaemon");
@@ -370,17 +370,22 @@
}
/**
- * Sleep for the given number of milliseconds.
+ * Sleep for the given number of nanoseconds, or slightly longer.
* @return false if we were interrupted.
*/
- private boolean sleepForMillis(long durationMillis) {
- long startMillis = System.currentTimeMillis();
+ private boolean sleepForNanos(long durationNanos) {
+ // It's important to base this on nanoTime(), not currentTimeMillis(), since
+ // the former stops counting when the processor isn't running.
+ long startNanos = System.nanoTime();
while (true) {
- long elapsedMillis = System.currentTimeMillis() - startMillis;
- long sleepMillis = durationMillis - elapsedMillis;
- if (sleepMillis <= 0) {
+ long elapsedNanos = System.nanoTime() - startNanos;
+ long sleepNanos = durationNanos - elapsedNanos;
+ if (sleepNanos <= 0) {
return true;
}
+ // Ensure the nano time is always rounded up to the next whole millisecond,
+ // ensuring the delay is >= the requested delay.
+ long sleepMillis = (sleepNanos + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI;
try {
Thread.sleep(sleepMillis);
} catch (InterruptedException e) {
@@ -403,14 +408,15 @@
* null. Only called from a single thread.
*/
private Object waitForFinalization() {
- if (finalizerTimeoutMs == 0) {
- finalizerTimeoutMs = VMRuntime.getRuntime().getFinalizerTimeoutMs();
+ if (finalizerTimeoutNs == 0) {
+ finalizerTimeoutNs =
+ NANOS_PER_MILLI * VMRuntime.getRuntime().getFinalizerTimeoutMs();
// Temporary app backward compatibility. Remove eventually.
- MAX_FINALIZE_NANOS = NANOS_PER_MILLI * finalizerTimeoutMs;
+ MAX_FINALIZE_NANOS = finalizerTimeoutNs;
}
long startCount = FinalizerDaemon.INSTANCE.progressCounter.get();
// Avoid remembering object being finalized, so as not to keep it alive.
- if (!sleepForMillis(finalizerTimeoutMs)) {
+ if (!sleepForNanos(finalizerTimeoutNs)) {
// Don't report possibly spurious timeout if we are interrupted.
return null;
}
@@ -431,7 +437,7 @@
// just finished as we were timing out, in which case we may get null or a later
// one. In this last case, we are very likely to discard it below.
Object finalizing = FinalizerDaemon.INSTANCE.finalizingObject;
- sleepForMillis(500);
+ sleepForNanos(500 * NANOS_PER_MILLI);
// Recheck to make it even less likely we report the wrong finalizing object in
// the case which a very slow finalization just finished as we were timing out.
if (getNeedToWork()
diff --git a/libart/src/main/java/java/lang/DexCache.java b/libart/src/main/java/java/lang/DexCache.java
index f9e3ea3..e35a69d 100644
--- a/libart/src/main/java/java/lang/DexCache.java
+++ b/libart/src/main/java/java/lang/DexCache.java
@@ -39,6 +39,9 @@
* A dex cache holds resolved copies of strings, fields, methods, and classes from the dexfile.
*/
final class DexCache {
+ /** The classloader this dex cache is for. */
+ private ClassLoader classLoader;
+
/** The location of the associated dex file. */
private String location;
@@ -125,4 +128,3 @@
// Only created by the VM.
private DexCache() {}
}
-
diff --git a/luni/src/main/java/android/compat/Compatibility.java b/luni/src/main/java/android/compat/Compatibility.java
index e5d7cbb..9b4b1af 100644
--- a/luni/src/main/java/android/compat/Compatibility.java
+++ b/luni/src/main/java/android/compat/Compatibility.java
@@ -121,13 +121,13 @@
}
@CorePlatformApi
protected void reportChange(long changeId) {
- System.logW(String.format(
- "No Compatibility callbacks set! Reporting change %d", changeId));
+ // Do not use String.format here (b/160912695)
+ System.logW("No Compatibility callbacks set! Reporting change " + changeId);
}
@CorePlatformApi
protected boolean isChangeEnabled(long changeId) {
- System.logW(String.format(
- "No Compatibility callbacks set! Querying change %d", changeId));
+ // Do not use String.format here (b/160912695)
+ System.logW("No Compatibility callbacks set! Querying change " + changeId);
return true;
}
}
diff --git a/luni/src/main/java/libcore/icu/LocaleData.java b/luni/src/main/java/libcore/icu/LocaleData.java
index ea6fe6f..12b978de 100644
--- a/luni/src/main/java/libcore/icu/LocaleData.java
+++ b/luni/src/main/java/libcore/icu/LocaleData.java
@@ -16,12 +16,17 @@
package libcore.icu;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
+import android.compat.Compatibility;
import android.icu.impl.ICUData;
import android.icu.impl.ICUResourceBundle;
import android.icu.text.NumberingSystem;
import android.icu.util.UResourceBundle;
+import dalvik.system.VMRuntime;
+
import java.text.DateFormat;
import java.util.HashMap;
import java.util.Locale;
@@ -38,6 +43,44 @@
*/
@libcore.api.CorePlatformApi
public final class LocaleData {
+
+ /**
+ * @see #USE_REAL_ROOT_LOCALE
+ */
+ private static final Locale LOCALE_EN_US_POSIX = new Locale("en", "US", "POSIX");
+
+ // In Android Q or before, when this class tries to load {@link Locale#ROOT} data, en_US_POSIX
+ // locale data is incorrectly loaded due to a bug b/159514442 (public bug b/159047832).
+ //
+ // This class used to pass "und" string as BCP47 language tag to our jni code, which then
+ // passes the string as as ICU Locale ID to ICU4C. ICU4C 63 or older version doesn't recognize
+ // "und" as a valid locale id, and fallback the default locale. The default locale is
+ // normally selected in the Locale picker in the Settings app by the user and set via
+ // frameworks. But this class statically cached the ROOT locale data before the
+ // default locale being set by framework, and without initialization, ICU4C uses en_US_POSIX
+ // as default locale. Thus, in Q or before, en_US_POSIX data is loaded.
+ //
+ // ICU version 64.1 resolved inconsistent behavior of
+ // "root", "und" and "" (empty) Locale ID which libcore previously relied on, and they are
+ // recognized correctly as {@link Locale#ROOT} since Android R. This ChangeId gated the change,
+ // and fallback to the old behavior by checking targetSdkVersion version.
+ //
+ // The below javadoc is shown in http://developer.android.com for consumption by app developers.
+ /**
+ * Since Android 11, formatter classes, e.g. java.text.SimpleDateFormat, no longer
+ * provide English data when Locale.ROOT format is requested. Please use
+ * Locale.ENGLISH to format in English.
+ *
+ * Note that Locale.ROOT is used as language/country neutral locale or fallback locale,
+ * and does not guarantee to represent English locale.
+ *
+ * This flag is only for documentation and can't be overridden by app. Please use
+ * {@code targetSdkVersion} to enable the new behavior.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion=29 /* Android Q */)
+ public static final long USE_REAL_ROOT_LOCALE = 159047832L;
+
// A cache for the locale-specific data.
private static final HashMap<String, LocaleData> localeDataCache = new HashMap<String, LocaleData>();
static {
@@ -171,6 +214,25 @@
}
/**
+ * Normally, this utility function is used by secondary cache above {@link LocaleData},
+ * because the cache needs a correct key.
+ * @see #USE_REAL_ROOT_LOCALE
+ * @return a compatible locale for the bug b/159514442
+ */
+ public static Locale getCompatibleLocaleForBug159514442(Locale locale) {
+ if (Locale.ROOT.equals(locale)) {
+ int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
+ // Don't use Compatibility.isChangeEnabled(USE_REAL_ROOT_LOCALE) because the app compat
+ // framework lives in libcore and can depend on this class via various format methods,
+ // e.g. String.format(). See b/160912695.
+ if (targetSdkVersion <= 29 /* Android Q */) {
+ locale = LOCALE_EN_US_POSIX;
+ }
+ }
+ return locale;
+ }
+
+ /**
* Returns a shared LocaleData for the given locale.
*/
@UnsupportedAppUsage
@@ -180,6 +242,8 @@
throw new NullPointerException("locale == null");
}
+ locale = getCompatibleLocaleForBug159514442(locale);
+
final String languageTag = locale.toLanguageTag();
synchronized (localeDataCache) {
LocaleData localeData = localeDataCache.get(languageTag);
diff --git a/luni/src/test/java/libcore/java/io/FileDescriptorTest.java b/luni/src/test/java/libcore/java/io/FileDescriptorTest.java
index 3e82690..390cfd6 100644
--- a/luni/src/test/java/libcore/java/io/FileDescriptorTest.java
+++ b/luni/src/test/java/libcore/java/io/FileDescriptorTest.java
@@ -16,7 +16,10 @@
package libcore.java.io;
+import android.system.Os;
+
import java.io.File;
+import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -24,6 +27,8 @@
import java.net.ServerSocket;
import junit.framework.TestCase;
+import static org.junit.Assert.assertNotEquals;
+
public class FileDescriptorTest extends TestCase {
public void testReadOnlyFileDescriptorSync() throws Exception {
File f= File.createTempFile("FileDescriptorTest", "tmp");
@@ -40,4 +45,31 @@
assertTrue(s.getImpl().getFD$().isSocket$());
s.close();
}
+
+ public void testStaticFileDescriptors() {
+ assertTrue(FileDescriptor.in.valid());
+ assertTrue(FileDescriptor.out.valid());
+ assertTrue(FileDescriptor.err.valid());
+ }
+
+ public void testFileDescriptorCloneForFork() throws Exception {
+ FileDescriptor [] sources = { FileDescriptor.in, FileDescriptor.out, FileDescriptor.err };
+ for (FileDescriptor source : sources) {
+ // Create a new file descriptor and set it's native descriptor to each of the well
+ // known descriptors in FileDescriptor.
+ FileDescriptor target = new FileDescriptor();
+ target.setInt$(source.getInt$());
+ assertEquals(target.getInt$(), source.getInt$());
+
+ // Clone file descriptor, this creates a native file descriptor.
+ target.cloneForFork();
+ assertTrue(source.valid());
+ assertTrue(target.valid());
+ assertNotEquals(target.getInt$(), source.getInt$());
+
+ // Clean-up native resource we allocated in cloneForFork. Os.close() may throw
+ // an ErrnoException.
+ Os.close(target);
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/ArraysTest.java b/luni/src/test/java/libcore/java/util/ArraysTest.java
index b48e8ea..5a2bfe2 100644
--- a/luni/src/test/java/libcore/java/util/ArraysTest.java
+++ b/luni/src/test/java/libcore/java/util/ArraysTest.java
@@ -16,15 +16,31 @@
package libcore.java.util;
-import java.util.Arrays;
-import java.util.Random;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
-public class ArraysTest extends junit.framework.TestCase {
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ArraysTest {
+ private static final int[] TEST_ARRAY_SIZES = { 0, 1, 2, 10, 100, 1000 };
+
/**
* java.util.Arrays#setAll(int[], java.util.function.IntUnaryOperator)
*/
- public void test_setAll$I() {
+ @Test
+ public void setAll$I() {
int[] list = new int[3];
list[0] = 0;
list[1] = 1;
@@ -51,7 +67,8 @@
/**
* java.util.Arrays#parallelSetAll(int[], java.util.function.IntUnaryOperator)
*/
- public void test_parallelSetAll$I() {
+ @Test
+ public void parallelSetAll$I() {
int[] list = new int[3];
list[0] = 0;
list[1] = 1;
@@ -78,7 +95,8 @@
/**
* java.util.Arrays#setAll(long[], java.util.function.IntToLongFunction)
*/
- public void test_setAll$L() {
+ @Test
+ public void setAll$L() {
long[] list = new long[3];
list[0] = 0;
list[1] = 1;
@@ -105,7 +123,8 @@
/**
* java.util.Arrays#parallelSetAll(long[], java.util.function.IntToLongFunction)
*/
- public void test_parallelSetAll$L() {
+ @Test
+ public void parallelSetAll$L() {
long[] list = new long[3];
list[0] = 0;
list[1] = 1;
@@ -132,16 +151,17 @@
/**
* java.util.Arrays#setAll(double[], java.util.function.IntToDoubleFunction)
*/
- public void test_setAll$D() {
+ @Test
+ public void setAll$D() {
double[] list = new double[3];
list[0] = 0.0d;
list[1] = 1.0d;
list[2] = 2.0d;
Arrays.setAll(list, x -> x + 0.5);
- assertEquals(0.5d, list[0]);
- assertEquals(1.5d, list[1]);
- assertEquals(2.5d, list[2]);
+ assertEquals(0.5d, list[0], 0.0);
+ assertEquals(1.5d, list[1], 0.0);
+ assertEquals(2.5d, list[2], 0.0);
try {
Arrays.setAll(list, null);
@@ -159,16 +179,17 @@
/**
* java.util.Arrays#parallelSetAll(double[], java.util.function.IntToDoubleFunction)
*/
- public void test_parallelSetAll$D() {
+ @Test
+ public void parallelSetAll$D() {
double[] list = new double[3];
list[0] = 0.0d;
list[1] = 1.0d;
list[2] = 2.0d;
Arrays.parallelSetAll(list, x -> x + 0.5);
- assertEquals(0.5d, list[0]);
- assertEquals(1.5d, list[1]);
- assertEquals(2.5d, list[2]);
+ assertEquals(0.5d, list[0], 0.0);
+ assertEquals(1.5d, list[1], 0.0);
+ assertEquals(2.5d, list[2], 0.0);
try {
Arrays.parallelSetAll(list, null);
@@ -186,7 +207,8 @@
/**
* java.util.Array#setAll(T[], java.util.function.IntFunction<\? extends T>)
*/
- public void test_setAll$T() {
+ @Test
+ public void setAll$T() {
String[] strings = new String[3];
strings[0] = "a";
strings[0] = "b";
@@ -213,7 +235,8 @@
/**
* java.util.Array#parallelSetAll(T[], java.util.function.IntFunction<\? extends T>)
*/
- public void test_parallelSetAll$T() {
+ @Test
+ public void parallelSetAll$T() {
String[] strings = new String[3];
strings[0] = "a";
strings[0] = "b";
@@ -240,7 +263,8 @@
/**
* java.util.Array#parallelPrefix(int[], java.util.function.IntBinaryOperator)
*/
- public void test_parallelPrefix$I() {
+ @Test
+ public void parallelPrefix$I() {
// Get an arbitrary array of ints.
Random rand = new Random(0);
int[] list = new int[1000];
@@ -256,7 +280,7 @@
}
Arrays.parallelPrefix(list, (x, y) -> x + y);
- assertTrue(Arrays.equals(seqResult, list));
+ assertArrayEquals(seqResult, list);
try {
Arrays.parallelPrefix(list, null);
@@ -274,7 +298,8 @@
/**
* java.util.Array#parallelPrefix(int[], int, int, java.util.function.IntBinaryOperator)
*/
- public void test_parallelPrefix$III() {
+ @Test
+ public void parallelPrefix$III() {
// Get an arbitrary array of ints.
Random rand = new Random(0);
int[] list = new int[1000];
@@ -291,7 +316,7 @@
}
Arrays.parallelPrefix(list, begin, end, (x, y) -> x + y);
- assertTrue(Arrays.equals(seqResult, list));
+ assertArrayEquals(seqResult, list);
try {
Arrays.parallelPrefix(list, begin, end, null);
@@ -315,7 +340,8 @@
/**
* java.util.Array#parallelPrefix(long[], java.util.function.LongBinaryOperator)
*/
- public void test_parallelPrefix$L() {
+ @Test
+ public void parallelPrefix$L() {
// Get an arbitrary array of ints.
Random rand = new Random(0);
long[] list = new long[1000];
@@ -331,7 +357,7 @@
}
Arrays.parallelPrefix(list, (x, y) -> x + y);
- assertTrue(Arrays.equals(seqResult, list));
+ assertArrayEquals(seqResult, list);
try {
Arrays.parallelPrefix(list, null);
@@ -349,7 +375,8 @@
/**
* java.util.Array#parallelPrefix(long[], int, int, java.util.function.LongBinaryOperator)
*/
- public void test_parallelPrefix$LII() {
+ @Test
+ public void parallelPrefix$LII() {
// Get an arbitrary array of ints.
Random rand = new Random(0);
long[] list = new long[1000];
@@ -366,7 +393,7 @@
}
Arrays.parallelPrefix(list, begin, end, (x, y) -> x + y);
- assertTrue(Arrays.equals(seqResult, list));
+ assertArrayEquals(seqResult, list);
try {
Arrays.parallelPrefix(list, begin, end, null);
@@ -390,7 +417,8 @@
/**
* java.util.Array#parallelPrefix(double[], java.util.function.DoubleBinaryOperator)
*/
- public void test_parallelPrefix$D() {
+ @Test
+ public void parallelPrefix$D() {
// Get an arbitrary array of ints.
Random rand = new Random(0);
double[] list = new double[1000];
@@ -410,7 +438,7 @@
// Parallel double arithmetic contains error, reduce to integer for comparison.
int[] listInInt = Arrays.stream(list).mapToInt(x -> (int) x).toArray();
int[] seqResultInInt = Arrays.stream(seqResult).mapToInt(x -> (int) x).toArray();
- assertTrue(Arrays.equals(seqResultInInt, listInInt));
+ assertArrayEquals(seqResultInInt, listInInt);
try {
Arrays.parallelPrefix(list, null);
@@ -428,7 +456,8 @@
/**
* java.util.Array#parallelPrefix(double[], int, int, java.util.function.DoubleBinaryOperator)
*/
- public void test_parallelPrefix$DII() {
+ @Test
+ public void parallelPrefix$DII() {
// Get an arbitrary array of ints.
Random rand = new Random(0);
double[] list = new double[1000];
@@ -449,7 +478,7 @@
// Parallel double arithmetic contains error, reduce to integer for comparison.
int[] listInInt = Arrays.stream(list).mapToInt(x -> (int) x).toArray();
int[] seqResultInInt = Arrays.stream(seqResult).mapToInt(x -> (int) x).toArray();
- assertTrue(Arrays.equals(seqResultInInt, listInInt));
+ assertArrayEquals(seqResultInInt, listInInt);
try {
Arrays.parallelPrefix(list, begin, end, null);
@@ -473,7 +502,8 @@
/**
* java.util.Array#parallelPrefix(T[], java.util.function.BinaryOperator<T>)
*/
- public void test_parallelPrefix$T() {
+ @Test
+ public void parallelPrefix$T() {
String[] strings = new String[3];
strings[0] = "a";
strings[1] = "b";
@@ -500,7 +530,8 @@
/**
* java.util.Array#parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>)
*/
- public void test_parallelPrefix$TII() {
+ @Test
+ public void parallelPrefix$TII() {
String[] strings = new String[5];
strings[0] = "a";
strings[1] = "b";
@@ -536,9 +567,389 @@
}
// http://b/74236526
- public void test_deepEquals_nestedArraysOfDifferentTypesButEqualValues() {
+ @Test
+ public void deepEquals_nestedArraysOfDifferentTypesButEqualValues() {
assertTrue(Arrays.deepEquals(
new Object[] { new Object[] { "Hello", "world" } },
new Object[] { new String[] { "Hello", "world" } }));
}
+
+ @Test
+ public void streamInt() {
+ for (int size : TEST_ARRAY_SIZES) {
+ int[] sourceArray = intTestArray(size);
+
+ // Stream, map, accumulate
+ int sum = Arrays.stream(sourceArray)
+ .map(i -> i + i)
+ .sum();
+ assertEquals(size * (size - 1), sum);
+
+ // Stream, collect as array again
+ int[] destArray = Arrays.stream(sourceArray)
+ .toArray();
+ assertArrayEquals(sourceArray, destArray);
+ assertNotSame(sourceArray, destArray);
+
+ // Stream, box, collect as list
+ List<Integer> destList = Arrays.stream(sourceArray)
+ .boxed()
+ .collect(Collectors.toList());
+
+ assertEquals(size, destList.size());
+ for (int i = 0; i < size; i++) {
+ assertEquals((int) destList.get(i), i);
+ }
+ }
+ }
+
+ @Test
+ public void streamIntStartEnd() {
+ final int size = 10;
+ int[] sourceArray = intTestArray(size);
+ for (int start = 0; start < size - 1; start++) {
+ for (int end = start; end < size; end++) {
+ int[] destArray = Arrays.stream(sourceArray, start, end)
+ .toArray();
+ int len = end - start;
+ assertEquals(len, destArray.length);
+ if (len > 0) {
+ assertEquals(start, destArray[0]);
+ assertEquals(end - 1, destArray[len - 1]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void streamIntStartEnd_Exceptions() {
+ int[] sourceArray = intTestArray(10);
+ try {
+ int unused = Arrays.stream(sourceArray, -1, 9)
+ .sum();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ try {
+ int unused = Arrays.stream(sourceArray, 0, 11)
+ .sum();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ try {
+ int unused = Arrays.stream(sourceArray, 11, 11)
+ .sum();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ try {
+ int unused = Arrays.stream(sourceArray, 0, -1)
+ .sum();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ try {
+ int unused = Arrays.stream(sourceArray, 4, 3)
+ .sum();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ }
+
+ @Test
+ public void streamLong() {
+ for (int size : TEST_ARRAY_SIZES) {
+ long[] sourceArray = longTestArray(size);
+
+ // Stream, map, accumulate
+ long sum = Arrays.stream(sourceArray)
+ .map(i -> i + i)
+ .sum();
+ assertEquals(size * (size - 1), sum);
+
+ // Stream, collect as array again
+ long[] destArray = Arrays.stream(sourceArray)
+ .toArray();
+ assertArrayEquals(sourceArray, destArray);
+ assertNotSame(sourceArray, destArray);
+
+ // Stream, box, collect as list
+ List<Long> destList = Arrays.stream(sourceArray)
+ .boxed()
+ .collect(Collectors.toList());
+
+ assertEquals(size, destList.size());
+ for (int i = 0; i < size; i++) {
+ assertEquals((long) destList.get(i), i);
+ }
+ }
+ }
+
+ @Test
+ public void streamLongStartEnd() {
+ final int size = 10;
+ long[] sourceArray = longTestArray(size);
+ for (int start = 0; start < size - 1; start++) {
+ for (int end = start; end < size; end++) {
+ long[] destArray = Arrays.stream(sourceArray, start, end)
+ .toArray();
+ int len = end - start;
+ assertEquals(len, destArray.length);
+ if (len > 0) {
+ assertEquals(start, destArray[0]);
+ assertEquals(end - 1, destArray[len - 1]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void streamLongStartEnd_Exceptions() {
+ long[] sourceArray = longTestArray(10);
+ try {
+ long unused = Arrays.stream(sourceArray, -1, 9)
+ .sum();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ try {
+ long unused = Arrays.stream(sourceArray, 0, 11)
+ .sum();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ try {
+ long unused = Arrays.stream(sourceArray, 11, 11)
+ .sum();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ try {
+ long unused = Arrays.stream(sourceArray, 0, -1)
+ .sum();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ try {
+ long unused = Arrays.stream(sourceArray, 4, 3)
+ .sum();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ }
+
+ @Test
+ public void streamDouble() {
+ for (int size : TEST_ARRAY_SIZES) {
+ double[] sourceArray = doubleTestArray(size);
+
+ // Stream, map, accumulate
+ double sum = Arrays.stream(sourceArray)
+ .map(i -> i + i)
+ .sum();
+ assertEquals(size * (size - 1), sum, 0.001);
+
+ // Stream, collect as array again
+ double[] destArray = Arrays.stream(sourceArray)
+ .toArray();
+ assertArrayEquals(sourceArray, destArray, 0.001);
+ assertNotSame(sourceArray, destArray);
+
+ // Stream, box, collect as list
+ List<Double> destList = Arrays.stream(sourceArray)
+ .boxed()
+ .collect(Collectors.toList());
+
+ assertEquals(size, destList.size());
+ for (int i = 0; i < size; i++) {
+ assertEquals(destList.get(i), i, 0.001);
+ }
+ }
+ }
+
+ @Test
+ public void streamDoubleStartEnd() {
+ final int size = 10;
+ double[] sourceArray = doubleTestArray(size);
+ for (int start = 0; start < size - 1; start++) {
+ for (int end = start; end < size; end++) {
+ double[] destArray = Arrays.stream(sourceArray, start, end)
+ .toArray();
+ int len = end - start;
+ assertEquals(len, destArray.length);
+ if (len > 0) {
+ assertEquals(start, destArray[0], 0.0);
+ assertEquals(end - 1, destArray[len - 1], 0.0);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void streamDoubleStartEnd_Exceptions() {
+ double[] sourceArray = doubleTestArray(10);
+ try {
+ double unused = Arrays.stream(sourceArray, -1, 9)
+ .sum();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ try {
+ double unused = Arrays.stream(sourceArray, 0, 11)
+ .sum();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ try {
+ double unused = Arrays.stream(sourceArray, 11, 11)
+ .sum();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ try {
+ double unused = Arrays.stream(sourceArray, 0, -1)
+ .sum();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ try {
+ double unused = Arrays.stream(sourceArray, 4, 3)
+ .sum();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ }
+
+ @Test
+ public void streamObject() {
+ for (int size : TEST_ARRAY_SIZES) {
+ String[] sourceArray = stringTestArray(size);
+
+ // Stream, map, accumulate
+ int sum = Arrays.stream(sourceArray)
+ .mapToInt(i -> Integer.parseInt(i) * 2)
+ .sum();
+ assertEquals(size * (size - 1), sum);
+
+ // Stream, collect as array again
+ String[] destArray = Arrays.stream(sourceArray)
+ .toArray(String[]::new);
+ assertArrayEquals(sourceArray, destArray);
+ assertNotSame(sourceArray, destArray);
+
+ // Stream, collect as list
+ List<String> destList = Arrays.stream(sourceArray)
+ .collect(Collectors.toList());
+
+ assertEquals(size, destList.size());
+ for (int i = 0; i < size; i++) {
+ assertSame(destList.get(i), sourceArray[i]);
+ }
+ }
+ }
+
+ @Test
+ public void streamObjectStartEnd() {
+ final int size = 10;
+ String[] sourceArray = stringTestArray(size);
+ for (int start = 0; start < size - 1; start++) {
+ for (int end = start; end < size; end++) {
+ String[] destArray = Arrays.stream(sourceArray, start, end)
+ .toArray(String[]::new);
+ int len = end - start;
+ assertEquals(len, destArray.length);
+ if (len > 0) {
+ assertSame(sourceArray[start], destArray[0]);
+ assertSame(sourceArray[end - 1], destArray[len - 1]);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void streamObjectStartEnd_Exceptions() {
+ String[] sourceArray = stringTestArray(10);
+ try {
+ long unused = Arrays.stream(sourceArray, -1, 9)
+ .count();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ try {
+ long unused = Arrays.stream(sourceArray, 0, 11)
+ .count();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ try {
+ long unused = Arrays.stream(sourceArray, 11, 11)
+ .count();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ try {
+ long unused = Arrays.stream(sourceArray, 0, -1)
+ .count();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ try {
+ long unused = Arrays.stream(sourceArray, 4, 3)
+ .count();
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Expected
+ }
+ }
+
+ private int[] intTestArray(int size) {
+ int[] array = new int[size];
+ for (int i = 0; i < size; i++) {
+ array[i] = i;
+ }
+ return array;
+ }
+
+ private long[] longTestArray(int size) {
+ long[] array = new long[size];
+ for (int i = 0; i < size; i++) {
+ array[i] = i;
+ }
+ return array;
+ }
+
+ private double[] doubleTestArray(int size) {
+ double[] array = new double[size];
+ for (int i = 0; i < size; i++) {
+ array[i] = i;
+ }
+ return array;
+ }
+
+ private String[] stringTestArray(int size) {
+ String[] array = new String[size];
+ for (int i = 0; i < size; i++) {
+ array[i] = String.valueOf(i);
+ }
+ return array;
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/stream/StreamTest.java b/luni/src/test/java/libcore/java/util/stream/StreamTest.java
new file mode 100644
index 0000000..5f8f254
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/stream/StreamTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 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.java.util.stream;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+
+import java.util.stream.Stream;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Streams tests required for Mainline coverage.
+ *
+ * TODO(b/153297830): Use existing CtsLibcoreOjTestCases for coverage instead.
+ */
+
+@RunWith(JUnit4.class)
+public class StreamTest {
+ private static final int[] TEST_ARRAY_SIZES = { 0, 1, 2, 10, 100, 1000 };
+
+ /**
+ * Stream<T>.of() has two overloads, Stream.of(T t) and Stream.of(T... values)
+ *
+ * The first builds a Stream<T> whose functionality is tested in CtsLibcoreOjTestCases, so we
+ * just check the contents are as expected
+ *
+ * The second is a thin wrapper around Arrays.Stream(), which is tested in ArraysTest,
+ * so again we just check the contents are as expected.
+ *
+ */
+ @Test
+ public void streamOfSingleObject() {
+ String object = "string";
+ String[] array = Stream.of(object).toArray(String[]::new);
+ assertEquals(1, array.length);
+ assertSame(object, array[0]);
+ }
+
+ @Test
+ public void streamOfObjects() {
+ for (int size : TEST_ARRAY_SIZES) {
+ String[] sourceArray = stringTestArray(size);
+
+ // Stream.of(T[] t) is equivalent to Stream.of(T... t)
+ String[] destArray = Stream.of(sourceArray)
+ .toArray(String[]::new);
+ assertNotSame(sourceArray, destArray);
+ assertArrayEquals(sourceArray, destArray);
+ }
+ }
+
+ private String[] stringTestArray(int size) {
+ String[] array = new String[size];
+ for (int i = 0; i < size; i++) {
+ array[i] = String.valueOf(i);
+ }
+ return array;
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/zip/ZipInputStreamTest.java b/luni/src/test/java/libcore/java/util/zip/ZipInputStreamTest.java
index 8485874..8a33f6f 100644
--- a/luni/src/test/java/libcore/java/util/zip/ZipInputStreamTest.java
+++ b/luni/src/test/java/libcore/java/util/zip/ZipInputStreamTest.java
@@ -143,6 +143,19 @@
zis.close();
}
+ private static final byte[] ZIP_WITH_DATA_DESCRIPTOR = new byte[] {
+(byte) 80, 75, 3, 4, 10, 0, 8, 0, 0, 0, -51, 90, -121, 80, -20, 62, -84, -103, 2, 0, 0, 0, 2, 0, 0, 0, 8, 0, 28, 0, 116, 101, 115, 116, 46, 116, 120, 116, 85, 84, 9, 0, 3, 97, 84, -116, 94, 102, 84, -116, 94, 117, 120, 11, 0, 1, 4, -119, 66, 0, 0, 4, 83, 95, 1, 0, 72, 10, 80, 75, 7, 8, -20, 62, -84, -103, 2, 0, 0, 0, 2, 0, 0, 0, 80, 75, 1, 2, 30, 3, 10, 0, 0, 0, 0, 0, -51, 90, -121, 80, -20, 62, -84, -103, 2, 0, 0, 0, 2, 0, 0, 0, 8, 0, 24, 0, 0, 0, 0, 0, 1, 0, 0, 0, -92, -127, 0, 0, 0, 0, 116, 101, 115, 116, 46, 116, 120, 116, 85, 84, 5, 0, 3, 97, 84, -116, 94, 117, 120, 11, 0, 1, 4, -119, 66, 0, 0, 4, 83, 95, 1, 0, 80, 75, 5, 6, 0, 0, 0, 0, 1, 0, 1, 0, 78, 0, 0, 0, 84, 0, 0, 0, 0, 0 };
+
+ public void testDataDescriptorOnStoredEntry() throws Exception {
+ ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(
+ ZIP_WITH_DATA_DESCRIPTOR));
+
+ ZipEntry entry = zis.getNextEntry();
+ assertEquals("test.txt", entry.getName());
+
+ zis.close();
+ }
+
private static byte[] zip(String[] names, byte[] bytes) throws IOException {
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
ZipOutputStream zippedOut = new ZipOutputStream(bytesOut);
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLParametersTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLParametersTest.java
index 620c022..3b3cfe4 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLParametersTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLParametersTest.java
@@ -16,13 +16,21 @@
package libcore.javax.net.ssl;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
import java.util.Arrays;
import javax.net.ssl.SSLParameters;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
-public class SSLParametersTest extends TestCase {
+@RunWith(JUnit4.class)
+public class SSLParametersTest {
- public void test_applicationProtocols() {
+ @Test
+ public void applicationProtocols() {
SSLParameters params = new SSLParameters();
try {
params.setApplicationProtocols(null);
@@ -61,4 +69,14 @@
assertTrue(Arrays.equals(new String[] {"h2"}, params.getApplicationProtocols()));
}
+ @Test
+ public void getSetUseCipherSuitesOrder() {
+ SSLParameters params = new SSLParameters();
+ // Default should be false
+ assertFalse(params.getUseCipherSuitesOrder());
+ params.setUseCipherSuitesOrder(true);
+ assertTrue(params.getUseCipherSuitesOrder());
+ params.setUseCipherSuitesOrder(false);
+ assertFalse(params.getUseCipherSuitesOrder());
+ }
}
diff --git a/luni/src/test/java/libcore/libcore/icu/LocaleDataTest.java b/luni/src/test/java/libcore/libcore/icu/LocaleDataTest.java
index 607397d..eace233 100644
--- a/luni/src/test/java/libcore/libcore/icu/LocaleDataTest.java
+++ b/luni/src/test/java/libcore/libcore/icu/LocaleDataTest.java
@@ -16,10 +16,37 @@
package libcore.libcore.icu;
-import java.util.Locale;
-import libcore.icu.LocaleData;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
-public class LocaleDataTest extends junit.framework.TestCase {
+import android.icu.text.DateTimePatternGenerator;
+
+import java.text.DateFormatSymbols;
+import java.text.DecimalFormatSymbols;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import libcore.icu.LocaleData;
+import libcore.junit.util.SwitchTargetSdkVersionRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class LocaleDataTest {
+
+ @Rule
+ public TestRule switchTargetSdkVersionRule = SwitchTargetSdkVersionRule.getInstance();
+
+ @Test
public void testAll() throws Exception {
// Test that we can get the locale data for all known locales.
for (Locale l : Locale.getAvailableLocales()) {
@@ -29,6 +56,7 @@
}
}
+ @Test
public void test_en_US() throws Exception {
LocaleData l = LocaleData.get(Locale.US);
assertEquals("AM", l.amPm[0]);
@@ -57,6 +85,7 @@
assertEquals("Tomorrow", l.tomorrow);
}
+ @Test
public void test_de_DE() throws Exception {
LocaleData l = LocaleData.get(new Locale("de", "DE"));
@@ -65,6 +94,7 @@
assertEquals("Morgen", l.tomorrow);
}
+ @Test
public void test_cs_CZ() throws Exception {
LocaleData l = LocaleData.get(new Locale("cs", "CZ"));
@@ -77,6 +107,7 @@
assertEquals("1", l.tinyStandAloneMonthNames[0]);
}
+ @Test
public void test_ko_KR() throws Exception {
LocaleData l = LocaleData.get(new Locale("ko", "KR"));
@@ -86,6 +117,7 @@
assertEquals("내일", l.tomorrow);
}
+ @Test
public void test_ru_RU() throws Exception {
LocaleData l = LocaleData.get(new Locale("ru", "RU"));
@@ -100,6 +132,7 @@
}
// http://code.google.com/p/android/issues/detail?id=38844
+ @Test
public void testDecimalFormatSymbols_es() throws Exception {
LocaleData es = LocaleData.get(new Locale("es"));
assertEquals(',', es.decimalSeparator);
@@ -123,6 +156,7 @@
}
// http://b/7924970
+ @Test
public void testTimeFormat12And24() throws Exception {
LocaleData en_US = LocaleData.get(Locale.US);
assertEquals("h:mm a", en_US.timeFormat_hm);
@@ -134,6 +168,7 @@
}
// http://b/26397197
+ @Test
public void testPatternWithOverride() throws Exception {
LocaleData haw = LocaleData.get(new Locale("haw"));
assertFalse(haw.shortDateFormat.isEmpty());
@@ -143,7 +178,111 @@
* Check that LocaleData.get() does not throw when the input locale is invalid.
* http://b/129070579
*/
+ @Test
public void testInvalidLocale() {
LocaleData.get(new Locale("invalidLocale"));
}
+
+ // Test for b/159514442 when targetSdkVersion == current
+ @Test
+ public void test_rootLocale_icu4jConsistency() {
+ assertRootDataEqualsToTargetLocaleData(Locale.ROOT);
+ }
+
+ // Test for b/159514442
+ @Test
+ @SwitchTargetSdkVersionRule.TargetSdkVersion(30)
+ public void test_rootLocale_useRealRootLocaleData() {
+ assertRootDataEqualsToTargetLocaleData(Locale.ROOT);
+
+ // Regression test as in b/159514442.
+ SimpleDateFormat df = new SimpleDateFormat("MMM", Locale.ROOT);
+ df.setTimeZone(TimeZone.getTimeZone("GMT"));
+ assertEquals("M07", df.format(new Date(1594255915217L)));
+ }
+
+ // Test for b/159514442
+ @Test
+ @SwitchTargetSdkVersionRule.TargetSdkVersion(29)
+ public void test_rootLocale_notUseRealRootLocaleData() {
+ Locale LOCALE_EN_US_POSIX = new Locale("en", "US", "POSIX");
+ assertRootDataEqualsToTargetLocaleData(LOCALE_EN_US_POSIX);
+
+ // Regression test as in b/159514442.
+ SimpleDateFormat df = new SimpleDateFormat("MMM", Locale.ROOT);
+ df.setTimeZone(TimeZone.getTimeZone("GMT"));
+ assertEquals("Jul", df.format(new Date(1594255915217L)));
+ }
+
+ private static void assertRootDataEqualsToTargetLocaleData(Locale targetLocale) {
+ LocaleData localeData = LocaleData.get(Locale.ROOT);
+ Calendar calendar = Calendar.getInstance(Locale.ROOT);
+ android.icu.util.Calendar icuCalendar = android.icu.util.Calendar.getInstance(targetLocale);
+ DateFormatSymbols dateFormatSymbols = DateFormatSymbols.getInstance(Locale.ROOT);
+ android.icu.text.DateFormatSymbols icuDateFormatSymbols =
+ android.icu.text.DateFormatSymbols.getInstance(targetLocale);
+ DecimalFormatSymbols decimalFormatSymbols = DecimalFormatSymbols.getInstance(Locale.ROOT);
+ android.icu.text.DecimalFormatSymbols icuDecimalFormatSymbols =
+ android.icu.text.DecimalFormatSymbols.getInstance(targetLocale);
+ DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(Locale.ROOT);
+
+ assertEquals(localeData.firstDayOfWeek, (Integer) icuCalendar.getFirstDayOfWeek());
+ assertEquals(localeData.minimalDaysInFirstWeek,
+ (Integer) icuCalendar.getMinimalDaysInFirstWeek());
+
+ assertArrayEquals(localeData.amPm, icuDateFormatSymbols.getAmPmStrings());
+ assertArrayEquals(localeData.eras, icuDateFormatSymbols.getEras());
+ assertArrayEquals(localeData.longMonthNames, icuDateFormatSymbols.getMonths(
+ android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.WIDE));
+ assertArrayEquals(localeData.tinyMonthNames, icuDateFormatSymbols.getMonths(
+ android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.NARROW));
+ assertArrayEquals(localeData.shortMonthNames, icuDateFormatSymbols.getMonths(
+ android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.ABBREVIATED));
+ assertArrayEquals(localeData.longStandAloneMonthNames, icuDateFormatSymbols.getMonths(
+ android.icu.text.DateFormatSymbols.STANDALONE, android.icu.text.DateFormatSymbols.WIDE));
+ assertArrayEquals(localeData.tinyStandAloneMonthNames, icuDateFormatSymbols.getMonths(
+ android.icu.text.DateFormatSymbols.STANDALONE, android.icu.text.DateFormatSymbols.NARROW));
+ assertArrayEquals(localeData.shortStandAloneMonthNames, icuDateFormatSymbols.getMonths(
+ android.icu.text.DateFormatSymbols.STANDALONE,
+ android.icu.text.DateFormatSymbols.ABBREVIATED));
+ assertArrayEquals(localeData.longWeekdayNames, icuDateFormatSymbols.getWeekdays(
+ android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.WIDE));
+ assertArrayEquals(localeData.tinyWeekdayNames, icuDateFormatSymbols.getWeekdays(
+ android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.NARROW));
+ assertArrayEquals(localeData.shortWeekdayNames, icuDateFormatSymbols.getWeekdays(
+ android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.ABBREVIATED));
+ assertArrayEquals(localeData.longStandAloneWeekdayNames, icuDateFormatSymbols.getWeekdays(
+ android.icu.text.DateFormatSymbols.STANDALONE, android.icu.text.DateFormatSymbols.WIDE));
+ assertArrayEquals(localeData.tinyStandAloneWeekdayNames, icuDateFormatSymbols.getWeekdays(
+ android.icu.text.DateFormatSymbols.STANDALONE, android.icu.text.DateFormatSymbols.NARROW));
+ assertArrayEquals(localeData.shortStandAloneWeekdayNames, icuDateFormatSymbols.getWeekdays(
+ android.icu.text.DateFormatSymbols.STANDALONE,
+ android.icu.text.DateFormatSymbols.ABBREVIATED));
+
+ // ICU DecimalFormatSymbols has data slightly different from LocaleData, but infinity is known
+ // to be the same, but caused the bug b/68318492 in old Android version.
+ assertEquals(localeData.infinity, icuDecimalFormatSymbols.getInfinity());
+ assertEquals(decimalFormatSymbols.getInfinity(), icuDecimalFormatSymbols.getInfinity());
+
+ assertEquals(localeData.timeFormat_Hm, dtpg.getBestPattern("Hm"));
+ assertEquals(localeData.timeFormat_hm, dtpg.getBestPattern("hm"));
+ assertEquals(localeData.timeFormat_Hms, dtpg.getBestPattern("Hms"));
+ assertEquals(localeData.timeFormat_hms, dtpg.getBestPattern("hms"));
+
+ // Explicitly test Calendar and DateFormatSymbols here because they are known to
+ // cache some part of LocaleData.
+ assertEquals(calendar.getFirstDayOfWeek(), icuCalendar.getFirstDayOfWeek());
+ assertEquals(calendar.getMinimalDaysInFirstWeek(), icuCalendar.getMinimalDaysInFirstWeek());
+ assertArrayEquals(dateFormatSymbols.getAmPmStrings(), icuDateFormatSymbols.getAmPmStrings());
+ assertArrayEquals(dateFormatSymbols.getEras(), icuDateFormatSymbols.getEras());
+
+ assertArrayEquals(dateFormatSymbols.getMonths(), icuDateFormatSymbols.getMonths(
+ android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.WIDE));
+ assertArrayEquals(dateFormatSymbols.getShortMonths(), icuDateFormatSymbols.getMonths(
+ android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.ABBREVIATED));
+ assertArrayEquals(dateFormatSymbols.getWeekdays(), icuDateFormatSymbols.getWeekdays(
+ android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.WIDE));
+ assertArrayEquals(dateFormatSymbols.getShortWeekdays(), icuDateFormatSymbols.getWeekdays(
+ android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.ABBREVIATED));
+ }
}
diff --git a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/KeyAgreementThread.java b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/KeyAgreementThread.java
index 480ea7f..33e9c21 100644
--- a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/KeyAgreementThread.java
+++ b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/KeyAgreementThread.java
@@ -15,7 +15,6 @@
*/
package org.apache.harmony.crypto.tests.javax.crypto.func;
-import com.android.org.bouncycastle.util.Arrays;
import java.security.AlgorithmParameterGenerator;
import java.security.AlgorithmParameters;
import java.security.KeyFactory;
@@ -25,6 +24,7 @@
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
import javax.crypto.KeyAgreement;
import javax.crypto.spec.DHParameterSpec;
@@ -80,7 +80,7 @@
byte[] sk1 = kag1.getSecretKey(algName, bArray2);
byte[] sk2 = kag2.getSecretKey(algName, bArray1);
- if (Arrays.areEqual(sk1, sk2) == false) {
+ if (!Arrays.equals(sk1, sk2)) {
throw new Exception ("Generated keys are not the same");
}
}
diff --git a/mmodules/core_platform_api/api/platform/current-api.txt b/mmodules/core_platform_api/api/platform/current-api.txt
index 74d536f..15a0a48 100644
--- a/mmodules/core_platform_api/api/platform/current-api.txt
+++ b/mmodules/core_platform_api/api/platform/current-api.txt
@@ -531,6 +531,7 @@
method public void addDexPath(String);
method public void addNativePath(java.util.Collection<java.lang.String>);
method public String getLdLibraryPath();
+ method public void reportClassLoaderChain();
method public static void setReporter(dalvik.system.BaseDexClassLoader.Reporter);
}
@@ -563,6 +564,7 @@
method public static dalvik.system.CloseGuard get();
method public static dalvik.system.CloseGuard.Reporter getReporter();
method public void open(String);
+ method public void openWithCallSite(String, String);
method public static void setEnabled(boolean);
method public static void setReporter(dalvik.system.CloseGuard.Reporter);
method public void warnIfOpen();
@@ -570,6 +572,7 @@
public static interface CloseGuard.Reporter {
method public void report(String, Throwable);
+ method public default void report(String);
}
public interface DalvikLogHandler {
diff --git a/ojluni/src/main/java/java/io/FileDescriptor.java b/ojluni/src/main/java/java/io/FileDescriptor.java
index ed3ebfe..98db443 100644
--- a/ojluni/src/main/java/java/io/FileDescriptor.java
+++ b/ojluni/src/main/java/java/io/FileDescriptor.java
@@ -82,8 +82,7 @@
*
* @see java.lang.System#in
*/
- // Android-changed: Duplicates of FDs needed for RuntimeInit#redirectLogStreams
- public static final FileDescriptor in = dupFd(0);
+ public static final FileDescriptor in = new FileDescriptor(0);
/**
* A handle to the standard output stream. Usually, this file
@@ -91,8 +90,7 @@
* known as <code>System.out</code>.
* @see java.lang.System#out
*/
- // Android-changed: Duplicates of FDs needed for RuntimeInit#redirectLogStreams
- public static final FileDescriptor out = dupFd(1);
+ public static final FileDescriptor out = new FileDescriptor(1);
/**
* A handle to the standard error stream. Usually, this file
@@ -101,8 +99,7 @@
*
* @see java.lang.System#err
*/
- // Android-changed: Duplicates of FDs needed for RuntimeInit#redirectLogStreams
- public static final FileDescriptor err = dupFd(2);
+ public static final FileDescriptor err = new FileDescriptor(2);
/**
* Tests if this file descriptor object is valid.
@@ -169,6 +166,26 @@
this.descriptor = fd;
}
+ // BEGIN Android-added: Method to clone standard file descriptors.
+ // Required as a consequence of RuntimeInit#redirectLogStreams. Cloning is used in
+ // ZygoteHooks.onEndPreload().
+ /**
+ * Clones the current native file descriptor and uses this for this FileDescriptor instance.
+ *
+ * This method does not close the current native file descriptor.
+ *
+ * @hide internal use only
+ */
+ public void cloneForFork() {
+ try {
+ int newDescriptor = Os.fcntlInt(this, F_DUPFD_CLOEXEC, 0);
+ this.descriptor = newDescriptor;
+ } catch (ErrnoException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ // END Android-added: Method to clone standard file descriptors.
+
// BEGIN Android-added: Methods to enable ownership enforcement of Unix file descriptors.
/**
* Returns the owner ID of this FileDescriptor. It's highly unlikely you should be calling this.
@@ -214,15 +231,6 @@
return isSocket(descriptor);
}
- // Android-added: Needed for RuntimeInit#redirectLogStreams.
- private static FileDescriptor dupFd(int fd) {
- try {
- return new FileDescriptor(Os.fcntlInt(new FileDescriptor(fd), F_DUPFD_CLOEXEC, 0));
- } catch (ErrnoException e) {
- throw new RuntimeException(e);
- }
- }
-
private static native boolean isSocket(int descriptor);
// Set up JavaIOFileDescriptorAccess in SharedSecrets
static {
diff --git a/ojluni/src/main/java/java/io/FileInputStream.java b/ojluni/src/main/java/java/io/FileInputStream.java
index 74ee3aa..38230bb 100755
--- a/ojluni/src/main/java/java/io/FileInputStream.java
+++ b/ojluni/src/main/java/java/io/FileInputStream.java
@@ -154,9 +154,11 @@
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
- // Android-changed: Open files through common bridge code.
+ // BEGIN Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+ // http://b/112107427
// fd = new FileDescriptor();
fd = IoBridge.open(name, O_RDONLY);
+ // END Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
// Android-changed: Tracking mechanism for FileDescriptor sharing.
// fd.attach(this);
@@ -164,7 +166,7 @@
path = name;
- // Android-removed: Open files through common bridge code.
+ // Android-removed: Open files using IoBridge to share BlockGuard & StrictMode logic.
// open(name);
// Android-added: File descriptor ownership tracking.
@@ -222,20 +224,25 @@
this.isFdOwner = isFdOwner;
}
+ // BEGIN Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+ // http://b/112107427
+ /*
/**
* Opens the specified file for reading.
* @param name the name of the file
- */
+ *
private native void open0(String name) throws FileNotFoundException;
// wrap native call to allow instrumentation
/**
* Opens the specified file for reading.
* @param name the name of the file
- */
+ *
private void open(String name) throws FileNotFoundException {
open0(name);
}
+ */
+ // END Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
/**
* Reads a byte of data from this input stream. This method blocks
diff --git a/ojluni/src/main/java/java/io/FileOutputStream.java b/ojluni/src/main/java/java/io/FileOutputStream.java
index 95ad1be..d0d0d40 100755
--- a/ojluni/src/main/java/java/io/FileOutputStream.java
+++ b/ojluni/src/main/java/java/io/FileOutputStream.java
@@ -229,11 +229,12 @@
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
- // BEGIN Android-changed: Open files through common bridge code.
+ // BEGIN Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+ // http://b/111268862
// this.fd = new FileDescriptor();
int flags = O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC);
this.fd = IoBridge.open(name, flags);
- // END Android-changed: Open files through common bridge code.
+ // END Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
// Android-changed: Tracking mechanism for FileDescriptor sharing.
// fd.attach(this);
@@ -242,7 +243,7 @@
this.append = append;
this.path = name;
- // Android-removed: Open files through common bridge code.
+ // Android-removed: Open files using IoBridge to share BlockGuard & StrictMode logic.
// open(name, append);
// Android-added: File descriptor ownership tracking.
@@ -300,11 +301,14 @@
this.isFdOwner = isFdOwner;
}
+ // BEGIN Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+ // http://b/112107427
+ /*
/**
* Opens a file, with the specified name, for overwriting or appending.
* @param name name of file to be opened
* @param append whether the file is to be opened in append mode
- */
+ *
private native void open0(String name, boolean append)
throws FileNotFoundException;
@@ -313,11 +317,13 @@
* Opens a file, with the specified name, for overwriting or appending.
* @param name name of file to be opened
* @param append whether the file is to be opened in append mode
- */
+ *
private void open(String name, boolean append)
throws FileNotFoundException {
open0(name, append);
}
+ */
+ // END Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
// Android-removed: write(int, boolean), use IoBridge instead.
/*
diff --git a/ojluni/src/main/java/java/lang/System.java b/ojluni/src/main/java/java/lang/System.java
index 63651a0..352d9ec 100644
--- a/ojluni/src/main/java/java/lang/System.java
+++ b/ojluni/src/main/java/java/lang/System.java
@@ -26,6 +26,7 @@
package java.lang;
import com.android.icu.util.Icu4cMetadata;
+import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
import android.system.ErrnoException;
import android.system.StructPasswd;
@@ -294,6 +295,7 @@
* the current time and midnight, January 1, 1970 UTC.
* @see java.util.Date
*/
+ @CriticalNative
public static native long currentTimeMillis();
/**
@@ -340,6 +342,7 @@
* high-resolution time source, in nanoseconds
* @since 1.5
*/
+ @CriticalNative
public static native long nanoTime();
/**
diff --git a/ojluni/src/main/java/java/text/DateFormatSymbols.java b/ojluni/src/main/java/java/text/DateFormatSymbols.java
index 97dc528..5216928 100644
--- a/ojluni/src/main/java/java/text/DateFormatSymbols.java
+++ b/ojluni/src/main/java/java/text/DateFormatSymbols.java
@@ -421,25 +421,27 @@
// BEGIN Android-changed: Replace getProviderInstance() with getCachedInstance().
// Android removed support for DateFormatSymbolsProviders, but still caches DFS.
+ // App compat change for b/159514442.
/**
* Returns a cached DateFormatSymbols if it's found in the
* cache. Otherwise, this method returns a newly cached instance
* for the given locale.
*/
private static DateFormatSymbols getCachedInstance(Locale locale) {
- SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
+ Locale cacheKey = LocaleData.getCompatibleLocaleForBug159514442(locale);
+ SoftReference<DateFormatSymbols> ref = cachedInstances.get(cacheKey);
DateFormatSymbols dfs;
if (ref == null || (dfs = ref.get()) == null) {
dfs = new DateFormatSymbols(locale);
ref = new SoftReference<>(dfs);
- SoftReference<DateFormatSymbols> x = cachedInstances.putIfAbsent(locale, ref);
+ SoftReference<DateFormatSymbols> x = cachedInstances.putIfAbsent(cacheKey, ref);
if (x != null) {
DateFormatSymbols y = x.get();
if (y != null) {
dfs = y;
} else {
// Replace the empty SoftReference with ref.
- cachedInstances.put(locale, ref);
+ cachedInstances.put(cacheKey, ref);
}
}
}
@@ -818,7 +820,9 @@
* appropriate LocaleData object. Note: zoneStrings isn't initialized in this method.
*/
private void initializeData(Locale locale) {
- SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
+ // Android-changed: App compat change for b/159514442.
+ Locale cacheKey = LocaleData.getCompatibleLocaleForBug159514442(locale);
+ SoftReference<DateFormatSymbols> ref = cachedInstances.get(cacheKey);
DateFormatSymbols dfs;
// Android-changed: invert cache presence check to simplify code flow.
if (ref != null && (dfs = ref.get()) != null) {
diff --git a/ojluni/src/main/java/java/util/Calendar.java b/ojluni/src/main/java/java/util/Calendar.java
index 3a0343b..7093533 100644
--- a/ojluni/src/main/java/java/util/Calendar.java
+++ b/ojluni/src/main/java/java/util/Calendar.java
@@ -3376,6 +3376,7 @@
*/
private void setWeekCountData(Locale desiredLocale)
{
+ desiredLocale = LocaleData.getCompatibleLocaleForBug159514442(desiredLocale);
/* try to get the Locale data from the cache */
int[] data = cachedLocaleData.get(desiredLocale);
if (data == null) { /* cache miss */
diff --git a/ojluni/src/main/java/java/util/zip/ZipInputStream.java b/ojluni/src/main/java/java/util/zip/ZipInputStream.java
index 0413f47..aaebb49 100644
--- a/ojluni/src/main/java/java/util/zip/ZipInputStream.java
+++ b/ojluni/src/main/java/java/util/zip/ZipInputStream.java
@@ -323,11 +323,16 @@
e.method = get16(tmpbuf, LOCHOW);
e.xdostime = get32(tmpbuf, LOCTIM);
if ((flag & 8) == 8) {
- /* "Data Descriptor" present */
- if (e.method != DEFLATED) {
- throw new ZipException(
- "only DEFLATED entries can have EXT descriptor");
- }
+ // Android-Changed: Remove the requirement that only DEFLATED entries
+ // can have data descriptors. This is not required by the ZIP spec and
+ // is inconsistent with the behaviour of ZipFile and versions of Android
+ // prior to Android N.
+ //
+ // /* "Data Descriptor" present */
+ // if (e.method != DEFLATED) {
+ // throw new ZipException(
+ // "only DEFLATED entries can have EXT descriptor");
+ // }
} else {
e.crc = get32(tmpbuf, LOCCRC);
e.csize = get32(tmpbuf, LOCSIZ);
diff --git a/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java b/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java
index 49ad55c..c680c9c 100644
--- a/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java
+++ b/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java
@@ -237,6 +237,18 @@
if (index == -1)
throw new IOException("Network interface cannot be identified");
Net.setInterface6(fd, index);
+ // BEGIN Android-added: Apply IP_MULTICAST_IF to dual-stack sockets.
+ // On dual-stack sockets, IP_MULTICAST_IF sets inet_sk(sk)->mc_index and
+ // inet_sk(sk)->mc_addr, which are specific to IPv4, and IPV6_MULTICAST_IF sets
+ // inet6_sk(sk)->mcast_oif, which are specific to IPv6. For IPv4 multicast
+ // traffic to work over an interface that is not the default, we need to
+ // configure both. http://b/144222142
+ Inet4Address target = Net.anyInet4Address(interf);
+ if (target != null) {
+ int targetAddress = Net.inet4AsInt(target);
+ Net.setInterface4(fd, targetAddress);
+ }
+ // END Android-added: Apply IP_MULTICAST_IF to dual-stack sockets.
} else {
// need IPv4 address to identify interface
Inet4Address target = Net.anyInet4Address(interf);
diff --git a/ojluni/src/main/java/sun/nio/fs/UnixChannelFactory.java b/ojluni/src/main/java/sun/nio/fs/UnixChannelFactory.java
index c6f074e..9491fd9 100644
--- a/ojluni/src/main/java/sun/nio/fs/UnixChannelFactory.java
+++ b/ojluni/src/main/java/sun/nio/fs/UnixChannelFactory.java
@@ -47,6 +47,13 @@
private static final JavaIOFileDescriptorAccess fdAccess =
SharedSecrets.getJavaIOFileDescriptorAccess();
+ static {
+ // b/151107960. This class is on the preloaded-classes-blacklist.
+ // It would be instantiated during AOT now without this magic
+ // function call and consequently fail 'atest PreloadCheck'.
+ dalvik.system.VMRuntime.doNotInitializeInAot();
+ }
+
protected UnixChannelFactory() {
}
diff --git a/ojluni/src/main/native/Android.bp b/ojluni/src/main/native/Android.bp
index 7aa8dda..45a5c98 100644
--- a/ojluni/src/main/native/Android.bp
+++ b/ojluni/src/main/native/Android.bp
@@ -37,7 +37,6 @@
"SocketChannelImpl.c",
"FileChannelImpl.c",
"FileDispatcherImpl.c",
- "FileOutputStream_md.c",
"FileInputStream.c",
"FileSystemPreferences.c",
"EPoll.c",
diff --git a/ojluni/src/main/native/FileInputStream.c b/ojluni/src/main/native/FileInputStream.c
index 58664a1..650cb6c 100644
--- a/ojluni/src/main/native/FileInputStream.c
+++ b/ojluni/src/main/native/FileInputStream.c
@@ -62,10 +62,15 @@
fis_fd = (*env)->GetFieldID(env, clazz, "fd", "Ljava/io/FileDescriptor;");
}
+// BEGIN Android-removed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+// http://b/112107427
+/*
JNIEXPORT void JNICALL
FileInputStream_open0(JNIEnv *env, jobject this, jstring path) {
fileOpen(env, this, path, fis_fd, O_RDONLY);
}
+*/
+// END Android-removed: Open files using IoBridge to share BlockGuard & StrictMode logic.
JNIEXPORT jlong JNICALL
FileInputStream_skip0(JNIEnv *env, jobject this, jlong toSkip) {
@@ -141,7 +146,6 @@
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(FileInputStream, open0, "(Ljava/lang/String;)V"),
NATIVE_METHOD(FileInputStream, skip0, "(J)J"),
NATIVE_METHOD(FileInputStream, available0, "()I"),
};
diff --git a/ojluni/src/main/native/FileOutputStream_md.c b/ojluni/src/main/native/FileOutputStream_md.c
deleted file mode 100644
index 73218d4..0000000
--- a/ojluni/src/main/native/FileOutputStream_md.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include "jni.h"
-#include "jni_util.h"
-#include "jvm.h"
-
-#include "io_util.h"
-#include "io_util_md.h"
-
-#include <fcntl.h>
-#include <nativehelper/JNIHelp.h>
-
-#define NATIVE_METHOD(className, functionName, signature) \
-{ #functionName, signature, (void*)(className ## _ ## functionName) }
-
-/*******************************************************************/
-/* BEGIN JNI ********* BEGIN JNI *********** BEGIN JNI ************/
-/*******************************************************************/
-
-jfieldID fos_fd; /* id for jobject 'fd' in java.io.FileOutputStream */
-
-/**************************************************************
- * Output stream
- */
-static void FileOutputStream_initIDs(JNIEnv *env) {
- jclass clazz = (*env)->FindClass(env, "java/io/FileOutputStream");
- fos_fd = (*env)->GetFieldID(env, clazz, "fd", "Ljava/io/FileDescriptor;");
-}
-
-
-JNIEXPORT void JNICALL
-FileOutputStream_open0(JNIEnv *env, jobject this,
- jstring path, jboolean append) {
- fileOpen(env, this, path, fos_fd,
- O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC));
-}
-
-static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(FileOutputStream, open0, "(Ljava/lang/String;Z)V"),
-};
-
-void register_java_io_FileOutputStream(JNIEnv* env) {
- jniRegisterNativeMethods(env, "java/io/FileOutputStream", gMethods, NELEM(gMethods));
- FileOutputStream_initIDs(env);
-}
diff --git a/ojluni/src/main/native/OnLoad.cpp b/ojluni/src/main/native/OnLoad.cpp
index ab13939..f0b8566 100644
--- a/ojluni/src/main/native/OnLoad.cpp
+++ b/ojluni/src/main/native/OnLoad.cpp
@@ -35,7 +35,6 @@
extern "C" void register_sun_nio_ch_SocketChannelImpl(JNIEnv* env);
extern "C" void register_sun_nio_ch_FileChannelImpl(JNIEnv* env);
extern "C" void register_sun_nio_ch_FileDispatcherImpl(JNIEnv* env);
-extern "C" void register_java_io_FileOutputStream(JNIEnv* env);
extern "C" void register_java_io_FileInputStream(JNIEnv* env);
extern "C" void register_java_util_prefs_FileSystemPreferences(JNIEnv* env);
extern "C" void register_sun_nio_ch_NativeThread(JNIEnv* env);
@@ -104,7 +103,6 @@
register_sun_nio_ch_SocketChannelImpl(env);
register_sun_nio_ch_FileChannelImpl(env);
register_sun_nio_ch_FileDispatcherImpl(env);
- register_java_io_FileOutputStream(env);
register_java_io_FileInputStream(env);
register_java_util_prefs_FileSystemPreferences(env);
register_sun_nio_ch_NativeThread(env);
diff --git a/ojluni/src/main/native/System.c b/ojluni/src/main/native/System.c
index 6cfee92..39332ce 100644
--- a/ojluni/src/main/native/System.c
+++ b/ojluni/src/main/native/System.c
@@ -38,13 +38,12 @@
#include "openssl/opensslv.h"
#include "zlib.h"
#include <nativehelper/JNIHelp.h>
+#include <nativehelper/jni_macros.h>
+
#if defined(__ANDROID__)
void android_get_LD_LIBRARY_PATH(char*, size_t);
#endif
-#define NATIVE_METHOD(className, functionName, signature) \
-{ #functionName, signature, (void*)(className ## _ ## functionName) }
-
#define PUTPROP(props, key, val) \
if (1) { \
jstring jkey = (*env)->NewStringUTF(env, key); \
@@ -252,13 +251,13 @@
}
}
-static jlong System_nanoTime(JNIEnv* env, jclass unused) {
+static jlong System_nanoTime() {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return now.tv_sec * 1000000000LL + now.tv_nsec;
}
-static jlong System_currentTimeMillis(JNIEnv* env, jclass unused) {
+static jlong System_currentTimeMillis() {
return JVM_CurrentTimeMillis(NULL, NULL);
}
@@ -269,8 +268,8 @@
NATIVE_METHOD(System, setIn0, "(Ljava/io/InputStream;)V"),
NATIVE_METHOD(System, specialProperties, "()[Ljava/lang/String;"),
NATIVE_METHOD(System, log, "(CLjava/lang/String;Ljava/lang/Throwable;)V"),
- NATIVE_METHOD(System, currentTimeMillis, "()J"),
- NATIVE_METHOD(System, nanoTime, "()J"),
+ CRITICAL_NATIVE_METHOD(System, currentTimeMillis, "()J"),
+ CRITICAL_NATIVE_METHOD(System, nanoTime, "()J"),
};
void register_java_lang_System(JNIEnv* env) {
diff --git a/support/src/test/java/org/apache/harmony/xnet/tests/support/MySSLContextSpi.java b/support/src/test/java/org/apache/harmony/xnet/tests/support/MySSLContextSpi.java
index 54e2a03..94ca6a9 100644
--- a/support/src/test/java/org/apache/harmony/xnet/tests/support/MySSLContextSpi.java
+++ b/support/src/test/java/org/apache/harmony/xnet/tests/support/MySSLContextSpi.java
@@ -77,14 +77,14 @@
return null;
}
- protected SSLParameters engineGetDefaultSSLParameters() {
+ public SSLParameters engineGetDefaultSSLParameters() {
engineGetSocketFactory();
- return null;
+ return super.engineGetDefaultSSLParameters();
}
- protected SSLParameters engineGetSupportedSSLParameters() {
+ public SSLParameters engineGetSupportedSSLParameters() {
engineGetSocketFactory();
- return null;
+ return super.engineGetSupportedSSLParameters();
}
/*