Merge "Test case DecimalFormat failure with leading 0." into nyc-dev
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index b75bc5b..c07c5ee 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -204,6 +204,7 @@
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
LOCAL_JAVA_LIBRARIES := core-oj core-libart core-junit bouncycastle
+LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-bcpkix bouncycastle-ocsp
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_MODULE := core-tests-support
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/JavaLibrary.mk
@@ -319,6 +320,7 @@
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
LOCAL_JAVA_LIBRARIES := core-oj-hostdex core-libart-hostdex core-junit-hostdex bouncycastle-hostdex
+ LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-bcpkix-hostdex bouncycastle-ocsp-hostdex
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := core-tests-support-hostdex
diff --git a/dalvik/src/main/java/dalvik/system/DexFile.java b/dalvik/src/main/java/dalvik/system/DexFile.java
index 1d33339..c30972b 100644
--- a/dalvik/src/main/java/dalvik/system/DexFile.java
+++ b/dalvik/src/main/java/dalvik/system/DexFile.java
@@ -452,6 +452,15 @@
public native static boolean isProfileGuidedCompilerFilter(String filter);
/**
+ * Returns the version of the compiler filter that is not based on profiles.
+ * If the input is not a valid filter, or the filter is already not based on
+ * profiles, this returns the input.
+ *
+ * @hide
+ */
+ public native static String getNonProfileGuidedCompilerFilter(String filter);
+
+ /**
* Returns the VM's opinion of what kind of dexopt is needed to make the
* apk/jar file up to date, where {@code targetMode} is used to indicate what
* type of compilation the caller considers up-to-date, and {@code newProfile}
diff --git a/dex/src/main/java/com/android/dex/DexFormat.java b/dex/src/main/java/com/android/dex/DexFormat.java
index 9319bc2..c598eee 100644
--- a/dex/src/main/java/com/android/dex/DexFormat.java
+++ b/dex/src/main/java/com/android/dex/DexFormat.java
@@ -27,7 +27,7 @@
* API level to target in order to produce the most modern file
* format
*/
- public static final int API_CURRENT = 14;
+ public static final int API_CURRENT = 24;
/** API level to target in order to suppress extended opcode usage */
public static final int API_NO_EXTENDED_OPCODES = 13;
@@ -44,8 +44,14 @@
/** common suffix for all dex file "magic numbers" */
public static final String MAGIC_SUFFIX = "\0";
- /** dex file version number for the current format variant */
- public static final String VERSION_CURRENT = "036";
+ /**
+ * Dex file version number for dalvik.
+ * <p>
+ * Note: Dex version 36 was loadable in some versions of Dalvik but was never fully supported or
+ * completed and is not considered a valid dex file format.
+ * </p>
+ */
+ public static final String VERSION_CURRENT = "037";
/** dex file version number for API level 13 and earlier */
public static final String VERSION_FOR_API_13 = "035";
@@ -88,7 +94,7 @@
if (version.equals(VERSION_CURRENT)) {
return API_CURRENT;
} else if (version.equals(VERSION_FOR_API_13)) {
- return 13;
+ return API_NO_EXTENDED_OPCODES;
}
return -1;
@@ -108,4 +114,9 @@
return MAGIC_PREFIX + version + MAGIC_SUFFIX;
}
+
+ public static boolean isSupportedDexMagic(byte[] magic) {
+ int api = magicToApi(magic);
+ return api == API_NO_EXTENDED_OPCODES || api == API_CURRENT;
+ }
}
diff --git a/dex/src/main/java/com/android/dex/TableOfContents.java b/dex/src/main/java/com/android/dex/TableOfContents.java
index d1b87ac..583f195 100644
--- a/dex/src/main/java/com/android/dex/TableOfContents.java
+++ b/dex/src/main/java/com/android/dex/TableOfContents.java
@@ -53,6 +53,7 @@
debugInfos, annotations, encodedArrays, annotationsDirectories
};
+ public int apiLevel;
public int checksum;
public byte[] signature;
public int fileSize;
@@ -73,12 +74,12 @@
private void readHeader(Dex.Section headerIn) throws UnsupportedEncodingException {
byte[] magic = headerIn.readByteArray(8);
- int apiTarget = DexFormat.magicToApi(magic);
- if (apiTarget != DexFormat.API_NO_EXTENDED_OPCODES) {
+ if (!DexFormat.isSupportedDexMagic(magic)) {
throw new DexException("Unexpected magic: " + Arrays.toString(magic));
}
+ apiLevel = DexFormat.magicToApi(magic);
checksum = headerIn.readInt();
signature = headerIn.readByteArray(20);
fileSize = headerIn.readInt();
@@ -163,8 +164,8 @@
throw new IllegalArgumentException("No such map item: " + type);
}
- public void writeHeader(Dex.Section out) throws IOException {
- out.write(DexFormat.apiToMagic(DexFormat.API_NO_EXTENDED_OPCODES).getBytes("UTF-8"));
+ public void writeHeader(Dex.Section out, int api) throws IOException {
+ out.write(DexFormat.apiToMagic(api).getBytes("UTF-8"));
out.writeInt(checksum);
out.write(signature);
out.writeInt(fileSize);
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/DatagramChannelTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/DatagramChannelTest.java
index 12aaae0..6bfe85e 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/DatagramChannelTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/DatagramChannelTest.java
@@ -17,6 +17,8 @@
package org.apache.harmony.tests.java.nio.channels;
+import android.system.ErrnoException;
+import android.system.OsConstants;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
@@ -33,8 +35,10 @@
import java.nio.channels.UnresolvedAddressException;
import java.nio.channels.UnsupportedAddressTypeException;
import java.nio.channels.spi.SelectorProvider;
+import java.util.concurrent.atomic.AtomicReference;
import junit.framework.TestCase;
import libcore.io.IoUtils;
+import libcore.io.Libcore;
/**
* Test for DatagramChannel
@@ -2518,4 +2522,40 @@
dc.socket().getLocalSocketAddress();
}
+
+ // b/27294715
+ public void test_concurrentShutdown() throws Exception {
+ DatagramChannel dc = DatagramChannel.open();
+ dc.configureBlocking(true);
+ dc.bind(new InetSocketAddress(Inet6Address.LOOPBACK, 0));
+ // Set 4s timeout
+ dc.socket().setSoTimeout(4000);
+
+ final AtomicReference<Exception> killerThreadException = new AtomicReference<Exception>(null);
+ final Thread killer = new Thread(new Runnable() {
+ public void run() {
+ try {
+ Thread.sleep(2000);
+ try {
+ Libcore.os.shutdown(dc.socket().getFileDescriptor$(), OsConstants.SHUT_RDWR);
+ } catch (ErrnoException expected) {
+ if (OsConstants.ENOTCONN != expected.errno) {
+ killerThreadException.set(expected);
+ }
+ }
+ } catch (Exception ex) {
+ killerThreadException.set(ex);
+ }
+ }
+ });
+ killer.start();
+
+ ByteBuffer dst = ByteBuffer.allocate(CAPACITY_NORMAL);
+ assertEquals(null, dc.receive(dst));
+ assertEquals(0, dst.position());
+ dc.close();
+
+ killer.join();
+ assertNull(killerThreadException.get());
+ }
}
diff --git a/luni/src/main/native/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp
index 27fa0d7..3fa4dee 100644
--- a/luni/src/main/native/libcore_io_Posix.cpp
+++ b/luni/src/main/native/libcore_io_Posix.cpp
@@ -376,8 +376,8 @@
const struct sockaddr_nl* nl_addr = reinterpret_cast<const struct sockaddr_nl*>(&ss);
static jmethodID ctor = env->GetMethodID(JniConstants::netlinkSocketAddressClass,
"<init>", "(II)V");
- return env->NewObject(JniConstants::netlinkSocketAddressClass, ctor,
- static_cast<jint>(nl_addr->nl_pid),
+ return env->NewObject(JniConstants::netlinkSocketAddressClass, ctor,
+ static_cast<jint>(nl_addr->nl_pid),
static_cast<jint>(nl_addr->nl_groups));
} else if (ss.ss_family == AF_PACKET) {
const struct sockaddr_ll* sll = reinterpret_cast<const struct sockaddr_ll*>(&ss);
@@ -1516,10 +1516,9 @@
sockaddr* from = (javaInetSocketAddress != NULL) ? reinterpret_cast<sockaddr*>(&ss) : NULL;
socklen_t* fromLength = (javaInetSocketAddress != NULL) ? &sl : 0;
jint recvCount = NET_FAILURE_RETRY(env, ssize_t, recvfrom, javaFd, bytes.get() + byteOffset, byteCount, flags, from, fromLength);
- if (recvCount == -1) {
- return recvCount;
+ if (recvCount > 0) {
+ fillInetSocketAddress(env, javaInetSocketAddress, ss);
}
- fillInetSocketAddress(env, javaInetSocketAddress, ss);
return recvCount;
}
diff --git a/luni/src/test/java/libcore/io/OsTest.java b/luni/src/test/java/libcore/io/OsTest.java
index 552c2a1..49a592d 100644
--- a/luni/src/test/java/libcore/io/OsTest.java
+++ b/luni/src/test/java/libcore/io/OsTest.java
@@ -34,10 +34,12 @@
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
+import java.net.SocketOptions;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Locale;
+import java.util.concurrent.atomic.AtomicReference;
import junit.framework.TestCase;
import static android.system.OsConstants.*;
@@ -457,6 +459,42 @@
}
}
+ // b/27294715
+ public void test_recvfrom_concurrentShutdown() throws Exception {
+ final FileDescriptor serverFd = Libcore.os.socket(AF_INET, SOCK_DGRAM, 0);
+ Libcore.os.bind(serverFd, InetAddress.getByName("127.0.0.1"), 0);
+ // Set 4s timeout
+ IoBridge.setSocketOption(serverFd, SocketOptions.SO_TIMEOUT, new Integer(4000));
+
+ final AtomicReference<Exception> killerThreadException = new AtomicReference<Exception>(null);
+ final Thread killer = new Thread(new Runnable() {
+ public void run() {
+ try {
+ Thread.sleep(2000);
+ try {
+ Libcore.os.shutdown(serverFd, SHUT_RDWR);
+ } catch (ErrnoException expected) {
+ if (OsConstants.ENOTCONN != expected.errno) {
+ killerThreadException.set(expected);
+ }
+ }
+ } catch (Exception ex) {
+ killerThreadException.set(ex);
+ }
+ }
+ });
+ killer.start();
+
+ ByteBuffer buffer = ByteBuffer.allocate(16);
+ InetSocketAddress srcAddress = new InetSocketAddress();
+ int received = Libcore.os.recvfrom(serverFd, buffer, 0, srcAddress);
+ assertTrue(received == 0);
+ Libcore.os.close(serverFd);
+
+ killer.join();
+ assertNull(killerThreadException.get());
+ }
+
public void test_xattr() throws Exception {
final String NAME_TEST = "user.meow";
diff --git a/luni/src/test/java/libcore/java/lang/BooleanTest.java b/luni/src/test/java/libcore/java/lang/BooleanTest.java
index 1ee5421..b1f536f 100644
--- a/luni/src/test/java/libcore/java/lang/BooleanTest.java
+++ b/luni/src/test/java/libcore/java/lang/BooleanTest.java
@@ -33,4 +33,9 @@
assertTrue(Boolean.compare(false, true) < 0);
assertTrue(Boolean.compare(true, false) > 0);
}
+
+ public void testStaticHashCode() {
+ assertEquals(Boolean.TRUE.hashCode(), Boolean.hashCode(true));
+ assertEquals(Boolean.FALSE.hashCode(), Boolean.hashCode(false));
+ }
}
diff --git a/luni/src/test/java/libcore/java/lang/ByteTest.java b/luni/src/test/java/libcore/java/lang/ByteTest.java
index 761a7f9..75d09b0 100644
--- a/luni/src/test/java/libcore/java/lang/ByteTest.java
+++ b/luni/src/test/java/libcore/java/lang/ByteTest.java
@@ -31,4 +31,12 @@
assertTrue(Byte.compare(min, zero) < 0);
assertTrue(Byte.compare(min, max) < 0);
}
+
+ public void testStaticHashCode() {
+ assertEquals(new Byte((byte) 567).hashCode(), Byte.hashCode((byte) 567));
+ }
+
+ public void testBYTES() {
+ assertEquals(1, Byte.BYTES);
+ }
}
diff --git a/luni/src/test/java/libcore/java/lang/CharacterTest.java b/luni/src/test/java/libcore/java/lang/CharacterTest.java
index 8c6f06f..ecf06d1 100644
--- a/luni/src/test/java/libcore/java/lang/CharacterTest.java
+++ b/luni/src/test/java/libcore/java/lang/CharacterTest.java
@@ -289,4 +289,12 @@
assertEquals(Character.DIRECTIONALITY_UNDEFINED, Character.getDirectionality(0x2068));
assertEquals(Character.DIRECTIONALITY_UNDEFINED, Character.getDirectionality(0x2069));
}
+
+ public void testStaticHashCode() {
+ assertEquals(new Character('A').hashCode(), Character.hashCode('A'));
+ }
+
+ public void testBYTES() {
+ assertEquals(2, Character.BYTES);
+ }
}
diff --git a/luni/src/test/java/libcore/java/lang/DoubleTest.java b/luni/src/test/java/libcore/java/lang/DoubleTest.java
index 6fc6c5e..3d2b2c8 100644
--- a/luni/src/test/java/libcore/java/lang/DoubleTest.java
+++ b/luni/src/test/java/libcore/java/lang/DoubleTest.java
@@ -164,4 +164,8 @@
double b = 578.0;
assertEquals(a + b, Double.sum(a, b));
}
+
+ public void testBYTES() {
+ assertEquals(8, Double.BYTES);
+ }
}
diff --git a/luni/src/test/java/libcore/java/lang/FloatTest.java b/luni/src/test/java/libcore/java/lang/FloatTest.java
index c25bd5c..b989cf4 100644
--- a/luni/src/test/java/libcore/java/lang/FloatTest.java
+++ b/luni/src/test/java/libcore/java/lang/FloatTest.java
@@ -137,4 +137,30 @@
assertEquals(1.1754944e-38f, Float.parseFloat("11754942807573644E-54"));
assertEquals(1.1754944e-38f, Float.parseFloat("11754942807573645E-54"));
}
+
+ public void testStaticHashCode() {
+ assertEquals(Float.valueOf(567.0f).hashCode(), Float.hashCode(567.0f));
+ }
+
+ public void testMax() {
+ float a = 567.0f;
+ float b = 578.0f;
+ assertEquals(Math.max(a, b), Float.max(a, b));
+ }
+
+ public void testMin() {
+ float a = 567.0f;
+ float b = 578.0f;
+ assertEquals(Math.min(a, b), Float.min(a, b));
+ }
+
+ public void testSum() {
+ float a = 567.0f;
+ float b = 578.0f;
+ assertEquals(a + b, Float.sum(a, b));
+ }
+
+ public void testBYTES() {
+ assertEquals(4, Float.BYTES);
+ }
}
diff --git a/luni/src/test/java/libcore/java/lang/IntegerTest.java b/luni/src/test/java/libcore/java/lang/IntegerTest.java
index 44028fe..64449a4 100644
--- a/luni/src/test/java/libcore/java/lang/IntegerTest.java
+++ b/luni/src/test/java/libcore/java/lang/IntegerTest.java
@@ -153,4 +153,8 @@
int b = 578;
assertEquals(a + b, Integer.sum(a, b));
}
+
+ public void testBYTES() {
+ assertEquals(4, Integer.BYTES);
+ }
}
diff --git a/luni/src/test/java/libcore/java/lang/LongTest.java b/luni/src/test/java/libcore/java/lang/LongTest.java
index 4e68933..adf6303 100644
--- a/luni/src/test/java/libcore/java/lang/LongTest.java
+++ b/luni/src/test/java/libcore/java/lang/LongTest.java
@@ -159,4 +159,8 @@
long b = 578L;
assertEquals(a + b, Long.sum(a, b));
}
+
+ public void testBYTES() {
+ assertEquals(8, Long.BYTES);
+ }
}
diff --git a/luni/src/test/java/libcore/java/lang/ShortTest.java b/luni/src/test/java/libcore/java/lang/ShortTest.java
index ab987bd..9a1d5a5 100644
--- a/luni/src/test/java/libcore/java/lang/ShortTest.java
+++ b/luni/src/test/java/libcore/java/lang/ShortTest.java
@@ -31,4 +31,12 @@
assertTrue(Short.compare(min, zero) < 0);
assertTrue(Short.compare(min, max) < 0);
}
+
+ public void testStaticHashCode() {
+ assertEquals(Short.valueOf((short) 567).hashCode(), Short.hashCode((short) 567));
+ }
+
+ public void testBYTES() {
+ assertEquals(2, Short.BYTES);
+ }
}
diff --git a/luni/src/test/java/libcore/java/net/URLTest.java b/luni/src/test/java/libcore/java/net/URLTest.java
index 2717d14..789e3e9 100644
--- a/luni/src/test/java/libcore/java/net/URLTest.java
+++ b/luni/src/test/java/libcore/java/net/URLTest.java
@@ -750,4 +750,11 @@
BlockGuard.setThreadPolicy(oldPolicy);
}
}
+
+ // http://27444667
+ public void testEmptyQueryAndAnchor() throws Exception {
+ assertEquals("/some/path", new URL("http://foobar.com/some/path?").getFile());
+ assertEquals("/some/path", new URL("http://foobar.com/some/path#").getFile());
+ assertEquals("/some/path", new URL("http://foobar.com/some/path?#").getFile());
+ }
}
diff --git a/luni/src/test/java/libcore/java/nio/channels/DatagramChannelTest.java b/luni/src/test/java/libcore/java/nio/channels/DatagramChannelTest.java
index 609a990..5169e9b 100644
--- a/luni/src/test/java/libcore/java/nio/channels/DatagramChannelTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/DatagramChannelTest.java
@@ -17,6 +17,7 @@
package libcore.java.nio.channels;
import java.io.IOException;
+import java.net.BindException;
import java.net.DatagramSocket;
import java.net.Inet4Address;
import java.net.Inet6Address;
@@ -25,10 +26,9 @@
import java.net.NetworkInterface;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
+import java.nio.channels.AlreadyBoundException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.DatagramChannel;
-import java.nio.channels.SocketChannel;
-import java.nio.channels.UnresolvedAddressException;
import java.util.Enumeration;
import java.util.Set;
@@ -181,6 +181,49 @@
assertNotNull(socket.getFileDescriptor$());
}
+ public void test_bind() throws IOException {
+ InetSocketAddress socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK, 0);
+ DatagramChannel channel = DatagramChannel.open();
+ channel.bind(socketAddress);
+ assertEquals(socketAddress.getAddress(),
+ ((InetSocketAddress)(channel.getLocalAddress())).getAddress());
+ assertTrue(((InetSocketAddress)(channel.getLocalAddress())).getPort() > 0);
+
+ try {
+ channel.bind(socketAddress);
+ fail();
+ } catch (AlreadyBoundException expected) {
+ }
+
+ socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK,
+ ((InetSocketAddress)(channel.getLocalAddress())).getPort());
+ try {
+ DatagramChannel.open().bind(socketAddress);
+ fail();
+ } catch (BindException expected) {}
+
+ channel.close();
+ socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK, 0);
+ try {
+ channel.bind(socketAddress);
+ } catch (ClosedChannelException expected) {}
+ }
+
+ public void test_getRemoteAddress() throws IOException {
+ InetSocketAddress socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK, 0);
+ DatagramChannel clientChannel = DatagramChannel.open();
+ DatagramChannel serverChannel = DatagramChannel.open();
+ serverChannel.bind(socketAddress);
+
+ assertNull(clientChannel.getRemoteAddress());
+
+ clientChannel.connect(serverChannel.getLocalAddress());
+ assertEquals(socketAddress.getAddress(),
+ ((InetSocketAddress)(clientChannel.getRemoteAddress())).getAddress());
+ assertEquals(((InetSocketAddress)(serverChannel.getLocalAddress())).getPort(),
+ ((InetSocketAddress)(clientChannel.getRemoteAddress())).getPort());
+ }
+
private static InetAddress getNonLoopbackNetworkInterfaceAddress(boolean ipv4) throws IOException {
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
while (networkInterfaces.hasMoreElements()) {
diff --git a/luni/src/test/java/libcore/java/nio/channels/ServerSocketChannelTest.java b/luni/src/test/java/libcore/java/nio/channels/ServerSocketChannelTest.java
index 1178b70..380b404 100644
--- a/luni/src/test/java/libcore/java/nio/channels/ServerSocketChannelTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/ServerSocketChannelTest.java
@@ -22,10 +22,13 @@
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.SocketException;
+import java.net.StandardSocketOptions;
+import java.nio.channels.AlreadyBoundException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.UnresolvedAddressException;
+import java.nio.channels.UnsupportedAddressTypeException;
import java.util.Enumeration;
import java.util.Set;
@@ -136,6 +139,58 @@
ssc.close();
}
+ public void test_bind$SocketAddress() throws IOException {
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ ssc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
+ assertEquals(InetAddress.getLoopbackAddress(),
+ ((InetSocketAddress)(ssc.getLocalAddress())).getAddress());
+ assertTrue(((InetSocketAddress)(ssc.getLocalAddress())).getPort() > 0);
+
+ try {
+ ssc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(),
+ ((InetSocketAddress)(ssc.getLocalAddress())).getPort()));
+ fail();
+ } catch (AlreadyBoundException expected) {
+ }
+
+ try {
+ ServerSocketChannel ssc1 = ServerSocketChannel.open();
+ ssc1.bind(new InetSocketAddress("1.1.1.1.1.1.1", 0));
+ fail();
+ } catch (UnresolvedAddressException expected) {
+ }
+
+ ssc.close();
+ try {
+ ssc.bind(new InetSocketAddress("1.1.1.1.1.1.1", 0));
+ fail();
+ } catch (ClosedChannelException expected) {
+ }
+ }
+
+ public void test_setOption() throws Exception {
+ ServerSocketChannel sc = ServerSocketChannel.open();
+ sc.setOption(StandardSocketOptions.SO_REUSEADDR, true);
+
+ // Assert that we can read back the option from the channel...
+ assertTrue(sc.getOption(StandardSocketOptions.SO_REUSEADDR));
+
+ sc.setOption(StandardSocketOptions.SO_REUSEADDR, false);
+
+ // Assert that we can read back the option from the channel...
+ assertEquals(false, (boolean)sc.getOption(StandardSocketOptions.SO_REUSEADDR));
+
+ sc.setOption(StandardSocketOptions.SO_RCVBUF, 1120);
+ assertEquals((Integer)1120, sc.getOption(StandardSocketOptions.SO_RCVBUF));
+
+ sc.close();
+ try {
+ sc.setOption(StandardSocketOptions.SO_RCVBUF, 2000);
+ fail();
+ } catch (ClosedChannelException expected) {
+ }
+ }
+
private static boolean canConnect(InetSocketAddress address) {
try {
SocketChannel socketChannel = SocketChannel.open(address);
diff --git a/luni/src/test/java/libcore/java/nio/channels/SocketChannelTest.java b/luni/src/test/java/libcore/java/nio/channels/SocketChannelTest.java
index d31b222..72609ee 100644
--- a/luni/src/test/java/libcore/java/nio/channels/SocketChannelTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/SocketChannelTest.java
@@ -20,278 +20,378 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
+import java.net.BindException;
import java.net.ConnectException;
-import java.net.Socket;
-import java.net.SocketImpl;
+import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketImpl;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
+import java.nio.channels.AlreadyBoundException;
import java.nio.channels.ClosedChannelException;
-import java.nio.channels.SocketChannel;
-import java.nio.channels.Selector;
+import java.nio.channels.NotYetConnectedException;
import java.nio.channels.SelectionKey;
-import java.nio.channels.UnresolvedAddressException;
-import java.util.Set;
-
-import static android.system.OsConstants.*;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
public class SocketChannelTest extends junit.framework.TestCase {
- public void test_read_intoReadOnlyByteArrays() throws Exception {
- ByteBuffer readOnly = ByteBuffer.allocate(1).asReadOnlyBuffer();
- ServerSocket ss = new ServerSocket(0);
- ss.setReuseAddress(true);
- SocketChannel sc = SocketChannel.open(ss.getLocalSocketAddress());
- try {
- sc.read(readOnly);
- fail();
- } catch (IllegalArgumentException expected) {
- }
- try {
- sc.read(new ByteBuffer[] { readOnly });
- fail();
- } catch (IllegalArgumentException expected) {
- }
- try {
- sc.read(new ByteBuffer[] { readOnly }, 0, 1);
- fail();
- } catch (IllegalArgumentException expected) {
- }
- }
-
- // https://code.google.com/p/android/issues/detail?id=56684
- public void test_56684() throws Exception {
- SocketChannel sc = SocketChannel.open();
- sc.configureBlocking(false);
-
- Selector selector = Selector.open();
- SelectionKey selectionKey = sc.register(selector, SelectionKey.OP_CONNECT);
-
- try {
- // This test originally mocked the connect syscall to return ENETUNREACH.
- // This is not easily doable in openJdk libcore, but a connect to broadcast
- // address (255.255.255.255) for a TCP connection produces ENETUNREACH
- // Kernel code that does it is at
- // http://lxr.free-electrons.com/source/net/ipv4/tcp_ipv4.c?v=3.18#L182
- sc.connect(new InetSocketAddress(InetAddress.getByAddress(new byte[] {
- (byte) 255, (byte) 255, (byte)255, (byte)255 }), 0));
- fail();
- } catch (ConnectException ex) {
+ public void test_read_intoReadOnlyByteArrays() throws Exception {
+ ByteBuffer readOnly = ByteBuffer.allocate(1).asReadOnlyBuffer();
+ ServerSocket ss = new ServerSocket(0);
+ ss.setReuseAddress(true);
+ SocketChannel sc = SocketChannel.open(ss.getLocalSocketAddress());
+ try {
+ sc.read(readOnly);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ sc.read(new ByteBuffer[] { readOnly });
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ sc.read(new ByteBuffer[] { readOnly }, 0, 1);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
}
- try {
- sc.finishConnect();
- fail();
- } catch (ClosedChannelException expected) {
- }
- }
+ // https://code.google.com/p/android/issues/detail?id=56684
+ public void test_56684() throws Exception {
+ SocketChannel sc = SocketChannel.open();
+ sc.configureBlocking(false);
- /** Checks that closing a Socket's output stream also closes the Socket and SocketChannel. */
- public void test_channelSocketOutputStreamClosureState() throws Exception {
- ServerSocket ss = new ServerSocket(0);
+ Selector selector = Selector.open();
+ SelectionKey selectionKey = sc.register(selector, SelectionKey.OP_CONNECT);
- SocketChannel sc = SocketChannel.open(ss.getLocalSocketAddress());
- sc.configureBlocking(true);
+ try {
+ // This test originally mocked the connect syscall to return ENETUNREACH.
+ // This is not easily doable in openJdk libcore, but a connect to broadcast
+ // address (255.255.255.255) for a TCP connection produces ENETUNREACH
+ // Kernel code that does it is at
+ // http://lxr.free-electrons.com/source/net/ipv4/tcp_ipv4.c?v=3.18#L182
+ sc.connect(new InetSocketAddress(InetAddress.getByAddress(new byte[] {
+ (byte) 255, (byte) 255, (byte) 255, (byte) 255 }), 0));
+ fail();
+ } catch (ConnectException ex) {
+ }
- Socket scSocket = sc.socket();
- OutputStream os = scSocket.getOutputStream();
-
- assertTrue(sc.isOpen());
- assertFalse(scSocket.isClosed());
-
- os.close();
-
- assertFalse(sc.isOpen());
- assertTrue(scSocket.isClosed());
-
- ss.close();
- }
-
- /** Checks that closing a Socket's input stream also closes the Socket and SocketChannel. */
- public void test_channelSocketInputStreamClosureState() throws Exception {
- ServerSocket ss = new ServerSocket(0);
-
- SocketChannel sc = SocketChannel.open(ss.getLocalSocketAddress());
- sc.configureBlocking(true);
-
- Socket scSocket = sc.socket();
- InputStream is = scSocket.getInputStream();
-
- assertTrue(sc.isOpen());
- assertFalse(scSocket.isClosed());
-
- is.close();
-
- assertFalse(sc.isOpen());
- assertTrue(scSocket.isClosed());
-
- ss.close();
- }
-
- /** Checks the state of the SocketChannel and associated Socket after open() */
- public void test_open_initialState() throws Exception {
- SocketChannel sc = SocketChannel.open();
- try {
- assertNull(sc.socket().getLocalSocketAddress());
-
- Socket socket = sc.socket();
- assertFalse(socket.isBound());
- assertFalse(socket.isClosed());
- assertFalse(socket.isConnected());
- assertEquals(-1, socket.getLocalPort());
- assertTrue(socket.getLocalAddress().isAnyLocalAddress());
- assertNull(socket.getLocalSocketAddress());
- assertNull(socket.getInetAddress());
- assertEquals(0, socket.getPort());
- assertNull(socket.getRemoteSocketAddress());
- assertFalse(socket.getReuseAddress());
-
- assertSame(sc, socket.getChannel());
- } finally {
- sc.close();
- }
- }
-
- public void test_bind_unresolvedAddress() throws IOException {
- SocketChannel sc = SocketChannel.open();
- try {
- sc.socket().bind(new InetSocketAddress("unresolvedname", 31415));
- fail();
- } catch (IOException expected) {
+ try {
+ sc.finishConnect();
+ fail();
+ } catch (ClosedChannelException expected) {
+ }
}
- assertNull(sc.socket().getLocalSocketAddress());
- assertTrue(sc.isOpen());
- assertFalse(sc.isConnected());
+ /** Checks that closing a Socket's output stream also closes the Socket and SocketChannel. */
+ public void test_channelSocketOutputStreamClosureState() throws Exception {
+ ServerSocket ss = new ServerSocket(0);
- sc.close();
- }
+ SocketChannel sc = SocketChannel.open(ss.getLocalSocketAddress());
+ sc.configureBlocking(true);
- /** Checks that the SocketChannel and associated Socket agree on the socket state. */
- public void test_bind_socketStateSync() throws IOException {
- SocketChannel sc = SocketChannel.open();
- assertNull(sc.socket().getLocalSocketAddress());
+ Socket scSocket = sc.socket();
+ OutputStream os = scSocket.getOutputStream();
- Socket socket = sc.socket();
- assertNull(socket.getLocalSocketAddress());
- assertFalse(socket.isBound());
+ assertTrue(sc.isOpen());
+ assertFalse(scSocket.isClosed());
- InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0);
- sc.socket().bind(bindAddr);
+ os.close();
- InetSocketAddress actualAddr = (InetSocketAddress) sc.socket().getLocalSocketAddress();
- assertEquals(actualAddr, socket.getLocalSocketAddress());
- assertEquals(bindAddr.getHostName(), actualAddr.getHostName());
- assertTrue(socket.isBound());
- assertFalse(socket.isConnected());
- assertFalse(socket.isClosed());
+ assertFalse(sc.isOpen());
+ assertTrue(scSocket.isClosed());
- sc.close();
+ ss.close();
+ }
- assertFalse(sc.isOpen());
- assertTrue(socket.isClosed());
- }
+ /** Checks that closing a Socket's input stream also closes the Socket and SocketChannel. */
+ public void test_channelSocketInputStreamClosureState() throws Exception {
+ ServerSocket ss = new ServerSocket(0);
- /**
- * Checks that the SocketChannel and associated Socket agree on the socket state, even if
- * the Socket object is requested/created after bind().
- */
- public void test_bind_socketObjectCreationAfterBind() throws IOException {
- SocketChannel sc = SocketChannel.open();
- assertNull(sc.socket().getLocalSocketAddress());
+ SocketChannel sc = SocketChannel.open(ss.getLocalSocketAddress());
+ sc.configureBlocking(true);
- InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0);
- sc.socket().bind(bindAddr);
+ Socket scSocket = sc.socket();
+ InputStream is = scSocket.getInputStream();
- // Socket object creation after bind().
- Socket socket = sc.socket();
- InetSocketAddress actualAddr = (InetSocketAddress) sc.socket().getLocalSocketAddress();
- assertEquals(actualAddr, socket.getLocalSocketAddress());
- assertEquals(bindAddr.getHostName(), actualAddr.getHostName());
- assertTrue(socket.isBound());
- assertFalse(socket.isConnected());
- assertFalse(socket.isClosed());
+ assertTrue(sc.isOpen());
+ assertFalse(scSocket.isClosed());
- sc.close();
+ is.close();
- assertFalse(sc.isOpen());
- assertTrue(socket.isClosed());
- }
+ assertFalse(sc.isOpen());
+ assertTrue(scSocket.isClosed());
- /**
- * Tests connect() and object state for a blocking SocketChannel. Blocking mode is the default.
- */
- public void test_connect_blocking() throws Exception {
- ServerSocket ss = new ServerSocket(0);
+ ss.close();
+ }
- SocketChannel sc = SocketChannel.open();
- assertTrue(sc.isBlocking());
+ /** Checks the state of the SocketChannel and associated Socket after open() */
+ public void test_open_initialState() throws Exception {
+ SocketChannel sc = SocketChannel.open();
+ try {
+ assertNull(sc.socket().getLocalSocketAddress());
- assertTrue(sc.connect(ss.getLocalSocketAddress()));
+ Socket socket = sc.socket();
+ assertFalse(socket.isBound());
+ assertFalse(socket.isClosed());
+ assertFalse(socket.isConnected());
+ assertEquals(-1, socket.getLocalPort());
+ assertTrue(socket.getLocalAddress().isAnyLocalAddress());
+ assertNull(socket.getLocalSocketAddress());
+ assertNull(socket.getInetAddress());
+ assertEquals(0, socket.getPort());
+ assertNull(socket.getRemoteSocketAddress());
+ assertFalse(socket.getReuseAddress());
- assertTrue(sc.socket().isBound());
- assertTrue(sc.isConnected());
- assertTrue(sc.socket().isConnected());
- assertFalse(sc.socket().isClosed());
- assertTrue(sc.isBlocking());
+ assertSame(sc, socket.getChannel());
+ } finally {
+ sc.close();
+ }
+ }
- ss.close();
- sc.close();
- }
+ public void test_bind_unresolvedAddress() throws IOException {
+ SocketChannel sc = SocketChannel.open();
+ try {
+ sc.socket().bind(new InetSocketAddress("unresolvedname", 31415));
+ fail();
+ } catch (IOException expected) {
+ }
- /** Tests connect() and object state for a non-blocking SocketChannel. */
- public void test_connect_nonBlocking() throws Exception {
- ServerSocket ss = new ServerSocket(0);
-
- SocketChannel sc = SocketChannel.open();
- assertTrue(sc.isBlocking());
- sc.configureBlocking(false);
- assertFalse(sc.isBlocking());
-
- if (!sc.connect(ss.getLocalSocketAddress())) {
- do {
- assertTrue(sc.socket().isBound());
+ assertNull(sc.socket().getLocalSocketAddress());
+ assertTrue(sc.isOpen());
assertFalse(sc.isConnected());
- assertFalse(sc.socket().isConnected());
+
+ sc.close();
+ }
+
+ /** Checks that the SocketChannel and associated Socket agree on the socket state. */
+ public void test_bind_socketStateSync() throws IOException {
+ SocketChannel sc = SocketChannel.open();
+ assertNull(sc.socket().getLocalSocketAddress());
+
+ Socket socket = sc.socket();
+ assertNull(socket.getLocalSocketAddress());
+ assertFalse(socket.isBound());
+
+ InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0);
+ sc.socket().bind(bindAddr);
+
+ InetSocketAddress actualAddr = (InetSocketAddress) sc.socket().getLocalSocketAddress();
+ assertEquals(actualAddr, socket.getLocalSocketAddress());
+ assertEquals(bindAddr.getHostName(), actualAddr.getHostName());
+ assertTrue(socket.isBound());
+ assertFalse(socket.isConnected());
+ assertFalse(socket.isClosed());
+
+ sc.close();
+
+ assertFalse(sc.isOpen());
+ assertTrue(socket.isClosed());
+ }
+
+ /**
+ * Checks that the SocketChannel and associated Socket agree on the socket state, even if
+ * the Socket object is requested/created after bind().
+ */
+ public void test_bind_socketObjectCreationAfterBind() throws IOException {
+ SocketChannel sc = SocketChannel.open();
+ assertNull(sc.socket().getLocalSocketAddress());
+
+ InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0);
+ sc.socket().bind(bindAddr);
+
+ // Socket object creation after bind().
+ Socket socket = sc.socket();
+ InetSocketAddress actualAddr = (InetSocketAddress) sc.socket().getLocalSocketAddress();
+ assertEquals(actualAddr, socket.getLocalSocketAddress());
+ assertEquals(bindAddr.getHostName(), actualAddr.getHostName());
+ assertTrue(socket.isBound());
+ assertFalse(socket.isConnected());
+ assertFalse(socket.isClosed());
+
+ sc.close();
+
+ assertFalse(sc.isOpen());
+ assertTrue(socket.isClosed());
+ }
+
+ /**
+ * Tests connect() and object state for a blocking SocketChannel. Blocking mode is the default.
+ */
+ public void test_connect_blocking() throws Exception {
+ ServerSocket ss = new ServerSocket(0);
+
+ SocketChannel sc = SocketChannel.open();
+ assertTrue(sc.isBlocking());
+
+ assertTrue(sc.connect(ss.getLocalSocketAddress()));
+
+ assertTrue(sc.socket().isBound());
+ assertTrue(sc.isConnected());
+ assertTrue(sc.socket().isConnected());
assertFalse(sc.socket().isClosed());
- } while (!sc.finishConnect());
+ assertTrue(sc.isBlocking());
+
+ ss.close();
+ sc.close();
}
- assertTrue(sc.socket().isBound());
- assertTrue(sc.isConnected());
- assertTrue(sc.socket().isConnected());
- assertFalse(sc.socket().isClosed());
- assertFalse(sc.isBlocking());
- ss.close();
- sc.close();
- }
+ /** Tests connect() and object state for a non-blocking SocketChannel. */
+ public void test_connect_nonBlocking() throws Exception {
+ ServerSocket ss = new ServerSocket(0);
- public void test_Socket_impl_notNull() throws Exception {
- SocketChannel sc = SocketChannel.open();
- Socket socket = sc.socket();
- Field f_impl = Socket.class.getDeclaredField("impl");
- f_impl.setAccessible(true);
- Object implFieldValue = f_impl.get(socket);
- assertNotNull(implFieldValue);
- assertTrue(implFieldValue instanceof SocketImpl);
- }
+ SocketChannel sc = SocketChannel.open();
+ assertTrue(sc.isBlocking());
+ sc.configureBlocking(false);
+ assertFalse(sc.isBlocking());
- public void test_setOption() throws Exception {
- SocketChannel sc = SocketChannel.open();
- sc.setOption(StandardSocketOptions.SO_LINGER, 1000);
+ if (!sc.connect(ss.getLocalSocketAddress())) {
+ do {
+ assertTrue(sc.socket().isBound());
+ assertFalse(sc.isConnected());
+ assertFalse(sc.socket().isConnected());
+ assertFalse(sc.socket().isClosed());
+ } while (!sc.finishConnect());
+ }
+ assertTrue(sc.socket().isBound());
+ assertTrue(sc.isConnected());
+ assertTrue(sc.socket().isConnected());
+ assertFalse(sc.socket().isClosed());
+ assertFalse(sc.isBlocking());
- // Assert that we can read back the option from the channel...
- assertEquals(1000, (int) sc.<Integer>getOption(StandardSocketOptions.SO_LINGER));
- // ... and its socket adaptor.
- assertEquals(1000, sc.socket().getSoLinger());
-
- sc.close();
- try {
- sc.setOption(StandardSocketOptions.SO_LINGER, 2000);
- fail();
- } catch (ClosedChannelException expected) {
+ ss.close();
+ sc.close();
}
- }
+
+ public void test_Socket_impl_notNull() throws Exception {
+ SocketChannel sc = SocketChannel.open();
+ Socket socket = sc.socket();
+ Field f_impl = Socket.class.getDeclaredField("impl");
+ f_impl.setAccessible(true);
+ Object implFieldValue = f_impl.get(socket);
+ assertNotNull(implFieldValue);
+ assertTrue(implFieldValue instanceof SocketImpl);
+ }
+
+ public void test_setOption() throws Exception {
+ SocketChannel sc = SocketChannel.open();
+ sc.setOption(StandardSocketOptions.SO_LINGER, 1000);
+
+ // Assert that we can read back the option from the channel...
+ assertEquals(1000, (int) sc.<Integer>getOption(StandardSocketOptions.SO_LINGER));
+ // ... and its socket adaptor.
+ assertEquals(1000, sc.socket().getSoLinger());
+
+ sc.close();
+ try {
+ sc.setOption(StandardSocketOptions.SO_LINGER, 2000);
+ fail();
+ } catch (ClosedChannelException expected) {
+ }
+ }
+
+ public void test_bind() throws IOException {
+ InetSocketAddress socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK, 0);
+ SocketChannel sc = SocketChannel.open();
+ sc.bind(socketAddress);
+ assertEquals(socketAddress.getAddress(),
+ ((InetSocketAddress) (sc.getLocalAddress())).getAddress());
+ assertTrue(((InetSocketAddress) (sc.getLocalAddress())).getPort() > 0);
+
+ try {
+ sc.bind(socketAddress);
+ fail();
+ } catch (AlreadyBoundException expected) {
+ }
+
+ socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK,
+ ((InetSocketAddress) (sc.getLocalAddress())).getPort());
+ try {
+ SocketChannel.open().bind(socketAddress);
+ fail();
+ } catch (BindException expected) {
+ }
+
+ sc.close();
+ socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK, 0);
+ try {
+ sc.bind(socketAddress);
+ } catch (ClosedChannelException expected) {
+ }
+ }
+
+ public void test_getRemoteAddress() throws IOException {
+ SocketChannel sc = SocketChannel.open();
+ ServerSocket ss = new ServerSocket(0);
+
+ assertNull(sc.getRemoteAddress());
+
+ sc.connect(ss.getLocalSocketAddress());
+ assertEquals(sc.getRemoteAddress(), ss.getLocalSocketAddress());
+ }
+
+ public void test_shutdownInput() throws IOException {
+ SocketChannel channel1 = SocketChannel.open();
+ ServerSocket server1 = new ServerSocket(0);
+ InetSocketAddress localAddr1 = new InetSocketAddress("127.0.0.1", server1.getLocalPort());
+
+ // initialize write content
+ byte[] writeContent = new byte[10];
+ for (int i = 0; i < writeContent.length; i++) {
+ writeContent[i] = (byte) i;
+ }
+
+ // establish connection
+ channel1.connect(localAddr1);
+ Socket acceptedSocket = server1.accept();
+ // use OutputStream.write to write bytes data.
+ OutputStream out = acceptedSocket.getOutputStream();
+ out.write(writeContent);
+ // use close to guarantee all data is sent
+ acceptedSocket.close();
+
+ channel1.configureBlocking(false);
+ ByteBuffer readContent = ByteBuffer.allocate(10 + 1);
+ channel1.shutdownInput();
+ assertEquals(-1, channel1.read(readContent));
+ }
+
+ public void test_shutdownOutput() throws IOException {
+ SocketChannel channel1 = SocketChannel.open();
+ ServerSocket server1 = new ServerSocket(0);
+ InetSocketAddress localAddr1 = new InetSocketAddress("127.0.0.1", server1.getLocalPort());
+
+ // initialize write content
+ ByteBuffer writeContent = ByteBuffer.allocate(10);
+ for (int i = 0; i < 10; i++) {
+ writeContent.put((byte) i);
+ }
+ writeContent.flip();
+
+ try {
+ channel1.shutdownOutput();
+ fail();
+ } catch (NotYetConnectedException expected) {}
+
+ // establish connection
+ channel1.connect(localAddr1);
+ channel1.shutdownOutput();
+
+ try {
+ channel1.write(writeContent);
+ fail();
+ } catch (ClosedChannelException expected) {}
+
+ channel1.close();
+
+ try {
+ channel1.shutdownOutput();
+ fail();
+ } catch(ClosedChannelException expected) {}
+ }
}
diff --git a/luni/src/test/java/libcore/java/security/ProviderTest.java b/luni/src/test/java/libcore/java/security/ProviderTest.java
index d3ccae1..7d9e633 100644
--- a/luni/src/test/java/libcore/java/security/ProviderTest.java
+++ b/luni/src/test/java/libcore/java/security/ProviderTest.java
@@ -38,6 +38,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -45,6 +46,7 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.crypto.Cipher;
+import javax.crypto.EncryptedPrivateKeyInfo;
import javax.crypto.NoSuchPaddingException;
import junit.framework.TestCase;
import libcore.javax.crypto.MockKey;
@@ -550,6 +552,58 @@
}
}
+ @SuppressWarnings("serial")
+ public void testProviderService_AliasDoesNotEraseCanonical_Success()
+ throws Exception {
+ // Make sure we start with a "known good" alias for this OID.
+ {
+ EncryptedPrivateKeyInfo epki1 = new EncryptedPrivateKeyInfo("OID.1.2.840.113549.1.1.5",
+ new byte[1]);
+ assertEquals("SHA1WITHRSA", epki1.getAlgName().toUpperCase(Locale.US));
+ }
+
+ Provider provider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("Signature.FOO", MockSpi.class.getName());
+ put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", "FOO");
+ }
+ };
+
+ Security.addProvider(provider);
+ try {
+ // This triggers a re-indexing of the algorithm id data:
+ try {
+ new EncryptedPrivateKeyInfo("nonexistent", new byte[1]);
+ fail("Should not find 'nonexistent' algorithm");
+ } catch (NoSuchAlgorithmException expected) {
+ }
+
+ EncryptedPrivateKeyInfo epki2 = new EncryptedPrivateKeyInfo("OID.1.2.840.113549.1.1.5", new byte[1]);
+ assertEquals("SHA1WITHRSA", epki2.getAlgName().toUpperCase(Locale.US));
+ } finally {
+ Security.removeProvider(provider.getName());
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public void testProviderService_CanFindNewOID_Success()
+ throws Exception {
+ Provider provider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("Signature.NEWALG", MockSpi.class.getName());
+ put("Alg.Alias.Signature.OID.1.2.9999.9999.9999", "NEWALG");
+ }
+ };
+
+ Security.addProvider(provider);
+ try {
+ EncryptedPrivateKeyInfo epki2 = new EncryptedPrivateKeyInfo("OID.1.2.9999.9999.9999", new byte[1]);
+ assertEquals("NEWALG", epki2.getAlgName().toUpperCase(Locale.US));
+ } finally {
+ Security.removeProvider(provider.getName());
+ }
+ }
+
public void testProvider_removeProvider_Success() throws Exception {
MockProvider provider = new MockProvider("MockProvider");
assertNull(Security.getProvider(provider.getName()));
diff --git a/luni/src/test/java/libcore/java/security/cert/PKIXRevocationCheckerTest.java b/luni/src/test/java/libcore/java/security/cert/PKIXRevocationCheckerTest.java
new file mode 100644
index 0000000..4b10030
--- /dev/null
+++ b/luni/src/test/java/libcore/java/security/cert/PKIXRevocationCheckerTest.java
@@ -0,0 +1,109 @@
+package libcore.java.security.cert;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.security.KeyStore.PrivateKeyEntry;
+import java.security.cert.CertPathBuilder;
+import java.security.cert.CertPathChecker;
+import java.security.cert.Extension;
+import java.security.cert.PKIXRevocationChecker;
+import java.security.cert.PKIXRevocationChecker.Option;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+
+import junit.framework.TestCase;
+import libcore.java.security.TestKeyStore;
+
+public class PKIXRevocationCheckerTest extends TestCase {
+ PKIXRevocationChecker checker;
+
+ PrivateKeyEntry entity;
+
+ PrivateKeyEntry issuer;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX");
+ CertPathChecker rc = cpb.getRevocationChecker();
+ assertNotNull(rc);
+ assertTrue(rc instanceof PKIXRevocationChecker);
+ checker = (PKIXRevocationChecker) rc;
+
+ TestKeyStore server = TestKeyStore.getServer();
+ TestKeyStore intermediate = TestKeyStore.getIntermediateCa();
+
+ entity = server.getPrivateKey("RSA", "RSA");
+ issuer = intermediate.getPrivateKey("RSA", "RSA");
+ }
+
+ public void test_Initializes() throws Exception {
+ assertEquals(0, checker.getOcspResponses().size());
+ assertEquals(0, checker.getOcspExtensions().size());
+ assertEquals(0, checker.getOptions().size());
+ assertEquals(0, checker.getSoftFailExceptions().size());
+ assertNull(checker.getSupportedExtensions());
+ assertNull(checker.getOcspResponderCert());
+ assertNull(checker.getOcspResponder());
+ }
+
+ public void test_CanSetOCSPResponse() throws Exception {
+ byte[] goodOCSPResponse = TestKeyStore.getOCSPResponseForGood(entity, issuer);
+
+ Map<X509Certificate, byte[]> ocspResponses = Collections
+ .singletonMap((X509Certificate) entity.getCertificate(), goodOCSPResponse);
+ checker.setOcspResponses(ocspResponses);
+
+ Map<X509Certificate, byte[]> returnedResponses = checker.getOcspResponses();
+ assertEquals(1, returnedResponses.size());
+ byte[] returnedResponse = returnedResponses.get(entity.getCertificate());
+ assertNotNull(returnedResponse);
+ assertEquals(Arrays.toString(goodOCSPResponse), Arrays.toString(returnedResponse));
+ }
+
+ public void test_getOcspResponder() throws Exception {
+ URI url = new URI("http://localhost/");
+ checker.setOcspResponder(url);
+ assertEquals(url, checker.getOcspResponder());
+ }
+
+ public void test_getOcspResponderCert() throws Exception {
+ checker.setOcspResponderCert((X509Certificate) issuer.getCertificate());
+ assertEquals((X509Certificate) issuer.getCertificate(), checker.getOcspResponderCert());
+ }
+
+ public void test_getOptions() throws Exception {
+ checker.setOptions(Collections.singleton(Option.SOFT_FAIL));
+ assertEquals(Collections.singleton(Option.SOFT_FAIL), checker.getOptions());
+ }
+
+ public void test_getOcspExtensions() throws Exception {
+ checker.setOcspExtensions(Collections.singletonList(new Extension() {
+ @Override
+ public boolean isCritical() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte[] getValue() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getId() {
+ return "TestExtension";
+ }
+
+ @Override
+ public void encode(OutputStream out) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ }));
+ assertEquals(1, checker.getOcspExtensions().size());
+ assertEquals("TestExtension", checker.getOcspExtensions().get(0).getId());
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/LinkedHashMapTest.java b/luni/src/test/java/libcore/java/util/LinkedHashMapTest.java
index c7de1f6..e82e66d 100644
--- a/luni/src/test/java/libcore/java/util/LinkedHashMapTest.java
+++ b/luni/src/test/java/libcore/java/util/LinkedHashMapTest.java
@@ -18,6 +18,8 @@
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
public class LinkedHashMapTest extends junit.framework.TestCase {
@@ -205,4 +207,31 @@
assertEquals("key1", newest.getKey());
assertEquals("value3", newest.getValue());
}
+
+ // http://b/27929722
+ // This tests the behaviour is consistent with earlier Android releases.
+ // This behaviour is NOT consistent with the RI. Future Android releases
+ // might change this.
+ public void test_removeEldestEntry() {
+ final AtomicBoolean removeEldestEntryReturnValue = new AtomicBoolean(false);
+ final AtomicInteger removeEldestEntryCallCount = new AtomicInteger(0);
+ LinkedHashMap<String, String> m = new LinkedHashMap<String, String>() {
+ @Override
+ protected boolean removeEldestEntry(Entry eldest) {
+ removeEldestEntryCallCount.incrementAndGet();
+ return removeEldestEntryReturnValue.get();
+ }
+ };
+
+ m.put("foo", "bar");
+ assertEquals(0, removeEldestEntryCallCount.get());
+ m.put("baz", "quux");
+ assertEquals(1, removeEldestEntryCallCount.get());
+
+ removeEldestEntryReturnValue.set(true);
+ m.put("foob", "faab");
+ assertEquals(2, removeEldestEntryCallCount.get());
+ assertEquals(2, m.size());
+ assertFalse(m.containsKey("foo"));
+ }
}
diff --git a/luni/src/test/java/tests/security/cert/CertPathValidatorExceptionTest.java b/luni/src/test/java/tests/security/cert/CertPathValidatorExceptionTest.java
index 1eac1f7..1f45443 100644
--- a/luni/src/test/java/tests/security/cert/CertPathValidatorExceptionTest.java
+++ b/luni/src/test/java/tests/security/cert/CertPathValidatorExceptionTest.java
@@ -24,9 +24,14 @@
import junit.framework.TestCase;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.doReturn;
+
import java.security.cert.CertPath;
import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertPathValidatorException.BasicReason;
import java.security.cert.Certificate;
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
@@ -431,6 +436,27 @@
}
}
+ public void testCertPathValidatorException_constructsCorrectlyWithReason() throws Exception {
+ Throwable cause = mock(Throwable.class);
+ CertPath certPath = mock(CertPath.class);
+
+ Certificate cert1 = mock(Certificate.class);
+ Certificate cert2 = mock(Certificate.class);
+ List<Certificate> certList = new ArrayList<Certificate>();
+ certList.add(cert1);
+ certList.add(cert2);
+ doReturn(certList).when(certPath).getCertificates();
+
+ CertPathValidatorException exception = new CertPathValidatorException("Test exception",
+ cause, certPath, 1, BasicReason.REVOKED);
+
+ assertEquals("Test exception", exception.getMessage());
+ assertEquals(cause, exception.getCause());
+ assertEquals(certPath, exception.getCertPath());
+ assertEquals(1, exception.getIndex());
+ assertEquals(BasicReason.REVOKED, exception.getReason());
+ }
+
class myCertPath extends CertPath {
private static final long serialVersionUID = 5871603047244722511L;
diff --git a/luni/src/test/java/tests/security/cert/CertPathValidatorSpiTest.java b/luni/src/test/java/tests/security/cert/CertPathValidatorSpiTest.java
deleted file mode 100644
index f69a3e5..0000000
--- a/luni/src/test/java/tests/security/cert/CertPathValidatorSpiTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
- */
-
-/**
-* @author Vera Y. Petrashkova
-* @version $Revision$
-*/
-
-package tests.security.cert;
-
-import junit.framework.TestCase;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.cert.CertPath;
-import java.security.cert.CertPathParameters;
-import java.security.cert.CertPathValidatorException;
-import java.security.cert.CertPathValidatorResult;
-import java.security.cert.CertPathValidatorSpi;
-
-import org.apache.harmony.security.tests.support.cert.MyCertPathValidatorSpi;
-/**
- * Tests for <code>CertPathValidatorSpi</code> class constructors and methods.
- *
- */
-public class CertPathValidatorSpiTest extends TestCase {
-
- /**
- * Test for <code>CertPathValidatorSpi</code> constructor Assertion:
- * constructs CertPathValidatorSpi
- */
- public void testCertPathValidatorSpi01() throws CertPathValidatorException,
- InvalidAlgorithmParameterException {
- CertPathValidatorSpi certPathValid = new MyCertPathValidatorSpi();
- CertPathParameters params = null;
- CertPath certPath = null;
- CertPathValidatorResult cpvResult = certPathValid.engineValidate(
- certPath, params);
- assertNull("Not null CertPathValidatorResult", cpvResult);
- try {
- certPathValid.engineValidate(certPath, params);
- fail("CertPathValidatorException must be thrown");
- } catch (CertPathValidatorException e) {
- }
- try {
- certPathValid.engineValidate(certPath, params);
- fail("InvalidAlgorithmParameterException must be thrown");
- } catch (InvalidAlgorithmParameterException e) {
- }
- }
-}
diff --git a/luni/src/test/java/tests/security/cert/CertificateRevocationExceptionTest.java b/luni/src/test/java/tests/security/cert/CertificateRevocationExceptionTest.java
index c3894f8..3951da6 100644
--- a/luni/src/test/java/tests/security/cert/CertificateRevocationExceptionTest.java
+++ b/luni/src/test/java/tests/security/cert/CertificateRevocationExceptionTest.java
@@ -130,6 +130,10 @@
assertTrue(firstDate.compareTo(exception.getInvalidityDate()) > 0);
}
+ public void testGetAuthorityName() throws Exception {
+ CertificateRevokedException exception = getTestException();
+ assertEquals(new X500Principal("CN=test1"), exception.getAuthorityName());
+ }
/**
* serialization/deserialization compatibility.
@@ -160,6 +164,8 @@
assertEquals(expected.getRevocationDate(), actual.getRevocationDate());
assertNotSame(expected.getRevocationDate(), actual.getRevocationDate());
assertEquals(expected.getRevocationReason(), expected.getRevocationReason());
+ assertEquals(expected.getAuthorityName(), actual.getAuthorityName());
+ assertNotSame(expected.getAuthorityName(), actual.getAuthorityName());
assertEquals(expected.getExtensions().size(), actual.getExtensions().size());
assertEquals(expected.getExtensions().keySet(), actual.getExtensions().keySet());
diff --git a/ojluni/src/main/java/java/lang/Boolean.java b/ojluni/src/main/java/java/lang/Boolean.java
index 64d732e..cac469b 100755
--- a/ojluni/src/main/java/java/lang/Boolean.java
+++ b/ojluni/src/main/java/java/lang/Boolean.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, 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
@@ -201,6 +201,18 @@
}
/**
+ * Returns a hash code for a {@code boolean} value; compatible with
+ * {@code Boolean.hashCode()}.
+ *
+ * @param value the value to hash
+ * @return a hash code value for a {@code boolean} value.
+ * @since 1.8
+ */
+ public static int hashCode(boolean value) {
+ return value ? 1231 : 1237;
+ }
+
+ /**
* Returns {@code true} if and only if the argument is not
* {@code null} and is a {@code Boolean} object that
* represents the same {@code boolean} value as this object.
diff --git a/ojluni/src/main/java/java/lang/Byte.java b/ojluni/src/main/java/java/lang/Byte.java
index a753b4b..47ad37e 100755
--- a/ojluni/src/main/java/java/lang/Byte.java
+++ b/ojluni/src/main/java/java/lang/Byte.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, 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
@@ -385,6 +385,18 @@
* @return a hash code value for this {@code Byte}
*/
public int hashCode() {
+ return Byte.hashCode(value);
+ }
+
+ /**
+ * Returns a hash code for a {@code byte} value; compatible with
+ * {@code Byte.hashCode()}.
+ *
+ * @param value the value to hash
+ * @return a hash code value for a {@code byte} value.
+ * @since 1.8
+ */
+ public static int hashCode(byte value) {
return (int)value;
}
@@ -448,6 +460,14 @@
*/
public static final int SIZE = 8;
+ /**
+ * The number of bytes used to represent a {@code byte} value in two's
+ * complement binary form.
+ *
+ * @since 1.8
+ */
+ public static final int BYTES = SIZE / Byte.SIZE;
+
/** use serialVersionUID from JDK 1.1. for interoperability */
private static final long serialVersionUID = -7183698231559129828L;
diff --git a/ojluni/src/main/java/java/lang/Character.java b/ojluni/src/main/java/java/lang/Character.java
index b7f2c2a..bb69d91 100755
--- a/ojluni/src/main/java/java/lang/Character.java
+++ b/ojluni/src/main/java/java/lang/Character.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, 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
@@ -4433,6 +4433,19 @@
* @return a hash code value for this {@code Character}
*/
public int hashCode() {
+ return Character.hashCode(value);
+ }
+
+ /**
+ * Returns a hash code for a {@code char} value; compatible with
+ * {@code Character.hashCode()}.
+ *
+ * @since 1.8
+ *
+ * @param value The {@code char} for which to return a hash code.
+ * @return a hash code value for a {@code char} value.
+ */
+ public static int hashCode(char value) {
return (int)value;
}
@@ -7101,6 +7114,14 @@
public static final int SIZE = 16;
/**
+ * The number of bytes used to represent a {@code char} value in unsigned
+ * binary form.
+ *
+ * @since 1.8
+ */
+ public static final int BYTES = SIZE / Byte.SIZE;
+
+ /**
* Returns the value obtained by reversing the order of the bytes in the
* specified <tt>char</tt> value.
*
diff --git a/ojluni/src/main/java/java/lang/Double.java b/ojluni/src/main/java/java/lang/Double.java
index 50712c4..59f8088 100755
--- a/ojluni/src/main/java/java/lang/Double.java
+++ b/ojluni/src/main/java/java/lang/Double.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, 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
diff --git a/ojluni/src/main/java/java/lang/Float.java b/ojluni/src/main/java/java/lang/Float.java
index 3b513c9..d75953e 100755
--- a/ojluni/src/main/java/java/lang/Float.java
+++ b/ojluni/src/main/java/java/lang/Float.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, 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
@@ -122,6 +122,13 @@
public static final int SIZE = 32;
/**
+ * The number of bytes used to represent a {@code float} value.
+ *
+ * @since 1.8
+ */
+ public static final int BYTES = SIZE / Byte.SIZE;
+
+ /**
* The {@code Class} instance representing the primitive type
* {@code float}.
*
@@ -648,6 +655,18 @@
}
/**
+ * Returns a hash code for a {@code float} value; compatible with
+ * {@code Float.hashCode()}.
+ *
+ * @param value the value to hash
+ * @return a hash code value for a {@code float} value.
+ * @since 1.8
+ */
+ public static int hashCode(float value) {
+ return floatToIntBits(value);
+ }
+
+ /**
* Compares this object against the specified object. The result
* is {@code true} if and only if the argument is not
@@ -901,6 +920,48 @@
1)); // (0.0, -0.0) or (NaN, !NaN)
}
+ /**
+ * Adds two {@code float} values together as per the + operator.
+ *
+ * @param a the first operand
+ * @param b the second operand
+ * @return the sum of {@code a} and {@code b}
+ * @jls 4.2.4 Floating-Point Operations
+ * @see java.util.function.BinaryOperator
+ * @since 1.8
+ */
+ public static float sum(float a, float b) {
+ return a + b;
+ }
+
+ /**
+ * Returns the greater of two {@code float} values
+ * as if by calling {@link Math#max(float, float) Math.max}.
+ *
+ * @param a the first operand
+ * @param b the second operand
+ * @return the greater of {@code a} and {@code b}
+ * @see java.util.function.BinaryOperator
+ * @since 1.8
+ */
+ public static float max(float a, float b) {
+ return Math.max(a, b);
+ }
+
+ /**
+ * Returns the smaller of two {@code float} values
+ * as if by calling {@link Math#min(float, float) Math.min}.
+ *
+ * @param a the first operand
+ * @param b the second operand
+ * @return the smaller of {@code a} and {@code b}
+ * @see java.util.function.BinaryOperator
+ * @since 1.8
+ */
+ public static float min(float a, float b) {
+ return Math.min(a, b);
+ }
+
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -2671257302660747028L;
}
diff --git a/ojluni/src/main/java/java/lang/Integer.java b/ojluni/src/main/java/java/lang/Integer.java
index 2b573e7..fe36907 100755
--- a/ojluni/src/main/java/java/lang/Integer.java
+++ b/ojluni/src/main/java/java/lang/Integer.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, 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
diff --git a/ojluni/src/main/java/java/lang/Long.java b/ojluni/src/main/java/java/lang/Long.java
index c40be4a..bf123c0 100755
--- a/ojluni/src/main/java/java/lang/Long.java
+++ b/ojluni/src/main/java/java/lang/Long.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1994, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, 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
@@ -997,6 +997,14 @@
public static final int SIZE = 64;
/**
+ * The number of bytes used to represent a {@code long} value in two's
+ * complement binary form.
+ *
+ * @since 1.8
+ */
+ public static final int BYTES = SIZE / Byte.SIZE;
+
+ /**
* Returns a {@code long} value with at most a single one-bit, in the
* position of the highest-order ("leftmost") one-bit in the specified
* {@code long} value. Returns zero if the specified value has no
diff --git a/ojluni/src/main/java/java/lang/Short.java b/ojluni/src/main/java/java/lang/Short.java
index 8b002c5..c701d81 100755
--- a/ojluni/src/main/java/java/lang/Short.java
+++ b/ojluni/src/main/java/java/lang/Short.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, 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
@@ -390,6 +390,18 @@
* @return a hash code value for this {@code Short}
*/
public int hashCode() {
+ return Short.hashCode(value);
+ }
+
+ /**
+ * Returns a hash code for a {@code short} value; compatible with
+ * {@code Short.hashCode()}.
+ *
+ * @param value the value to hash
+ * @return a hash code value for a {@code short} value.
+ * @since 1.8
+ */
+ public static int hashCode(short value) {
return (int)value;
}
@@ -453,6 +465,14 @@
public static final int SIZE = 16;
/**
+ * The number of bytes used to represent a {@code short} value in two's
+ * complement binary form.
+ *
+ * @since 1.8
+ */
+ public static final int BYTES = SIZE / Byte.SIZE;
+
+ /**
* Returns the value obtained by reversing the order of the bytes in the
* two's complement representation of the specified {@code short} value.
*
diff --git a/ojluni/src/main/java/java/net/URL.java b/ojluni/src/main/java/java/net/URL.java
index b585e2b..70825a0 100755
--- a/ojluni/src/main/java/java/net/URL.java
+++ b/ojluni/src/main/java/java/net/URL.java
@@ -708,7 +708,7 @@
this.protocol = protocol;
this.host = host;
this.port = port;
- this.file = query == null ? path : path + "?" + query;
+ this.file = (query == null || query.isEmpty()) ? path : path + "?" + query;
this.userInfo = userInfo;
this.path = path;
this.ref = ref;
diff --git a/ojluni/src/main/java/java/net/URLStreamHandler.java b/ojluni/src/main/java/java/net/URLStreamHandler.java
index e64b9b8..e177363 100755
--- a/ojluni/src/main/java/java/net/URLStreamHandler.java
+++ b/ojluni/src/main/java/java/net/URLStreamHandler.java
@@ -337,6 +337,10 @@
// Remove trailing .
if (path.endsWith("/."))
path = path.substring(0, path.length() -1);
+
+ // Remove trailing ?
+ if (path.endsWith("?"))
+ path = path.substring(0, path.length() -1);
}
setURL(u, protocol, host, port, authority, userInfo, path, query, ref);
diff --git a/ojluni/src/main/java/java/nio/channels/ServerSocketChannel.java b/ojluni/src/main/java/java/nio/channels/ServerSocketChannel.java
index 127fb5b..63ed42f 100755
--- a/ojluni/src/main/java/java/nio/channels/ServerSocketChannel.java
+++ b/ojluni/src/main/java/java/nio/channels/ServerSocketChannel.java
@@ -138,7 +138,7 @@
* @return This channel
*
* @throws AlreadyBoundException {@inheritDoc}
- * @throws UnsupportedAddressTypeException {@inheritDoc}
+ * @throws UnresolvedAddressException
* @throws ClosedChannelException {@inheritDoc}
* @throws IOException {@inheritDoc}
* @throws SecurityException
diff --git a/ojluni/src/main/java/java/security/Permission.java b/ojluni/src/main/java/java/security/Permission.java
index 1d8e7f5..9f04ac4 100755
--- a/ojluni/src/main/java/java/security/Permission.java
+++ b/ojluni/src/main/java/java/security/Permission.java
@@ -41,5 +41,5 @@
public abstract String getActions();
- public PermissionCollection newPermissionCollection() { return null; }
+ public PermissionCollection newPermissionCollection() { return new Permissions(); }
}
diff --git a/ojluni/src/main/java/java/util/LinkedHashMap.java b/ojluni/src/main/java/java/util/LinkedHashMap.java
index 81b8a7a..7853d46 100755
--- a/ojluni/src/main/java/java/util/LinkedHashMap.java
+++ b/ojluni/src/main/java/java/util/LinkedHashMap.java
@@ -440,13 +440,27 @@
* removes the eldest entry if appropriate.
*/
void addEntry(int hash, K key, V value, int bucketIndex) {
- super.addEntry(hash, key, value, bucketIndex);
+ // Previous Android releases called removeEldestEntry() before actually
+ // inserting a value but after increasing the size.
+ // The RI is documented to call it afterwards.
+ // **** THIS CHANGE WILL BE REVERTED IN A FUTURE ANDROID RELEASE ****
// Remove eldest entry if instructed
LinkedHashMapEntry<K,V> eldest = header.after;
- if (removeEldestEntry(eldest)) {
- removeEntryForKey(eldest.key);
+ if (eldest != header) {
+ boolean removeEldest;
+ size++;
+ try {
+ removeEldest = removeEldestEntry(eldest);
+ } finally {
+ size--;
+ }
+ if (removeEldest) {
+ removeEntryForKey(eldest.key);
+ }
}
+
+ super.addEntry(hash, key, value, bucketIndex);
}
/**
@@ -473,7 +487,12 @@
size++;
}
- /**
+ // Intentionally make this not JavaDoc, as the we don't conform to
+ // the behaviour documented here (we call removeEldestEntry before
+ // inserting the new value to be consistent with previous Android
+ // releases).
+ // **** THIS CHANGE WILL BE REVERTED IN A FUTURE ANDROID RELEASE ****
+ /*
* Returns <tt>true</tt> if this map should remove its eldest entry.
* This method is invoked by <tt>put</tt> and <tt>putAll</tt> after
* inserting a new entry into the map. It provides the implementor
diff --git a/ojluni/src/main/java/sun/security/x509/AlgorithmId.java b/ojluni/src/main/java/sun/security/x509/AlgorithmId.java
index 620a13d..f2de8ab 100755
--- a/ojluni/src/main/java/sun/security/x509/AlgorithmId.java
+++ b/ojluni/src/main/java/sun/security/x509/AlgorithmId.java
@@ -250,6 +250,13 @@
// ignore
}
}
+
+ // Try to update the name <-> OID mapping table.
+ synchronized (oidTable) {
+ reinitializeMappingTableLocked();
+ algName = nameTable.get(algid);
+ }
+
return (algName == null) ? algid.toString() : algName;
}
@@ -547,58 +554,73 @@
// See if any of the installed providers supply a mapping from
// the given algorithm name to an OID string
- String oidString;
synchronized (oidTable) {
- // Android-changed: Update the table only if the OID changed. Also synchronize
- // on oidTable for thread safety.
- int currentVersion = Security.getVersion();
- if (initOidTableVersion != currentVersion) {
- Provider[] provs = Security.getProviders();
- for (int i=0; i<provs.length; i++) {
- for (Enumeration<Object> enum_ = provs[i].keys();
- enum_.hasMoreElements(); ) {
- String alias = (String)enum_.nextElement();
- String upperCaseAlias = alias.toUpperCase(Locale.ENGLISH);
- int index;
- if (upperCaseAlias.startsWith("ALG.ALIAS")) {
- if ((index=upperCaseAlias.indexOf("OID.", 0)) != -1) {
- index += "OID.".length();
- if (index == alias.length()) {
- // invalid alias entry
- break;
- }
- oidString = alias.substring(index);
- String stdAlgName = provs[i].getProperty(alias);
- if (stdAlgName != null) {
- stdAlgName = stdAlgName.toUpperCase(Locale.ENGLISH);
- }
- if (stdAlgName != null &&
- oidTable.get(stdAlgName) == null) {
- ObjectIdentifier oid =
- new ObjectIdentifier(oidString);
- oidTable.put(stdAlgName, oid);
- nameTable.put(oid, stdAlgName);
- }
- } else {
- // Android-changed: If the alias isn't specified with an explicit
- // "OID." in the name, we still attempt to parse it as one.
- final int sep = alias.indexOf('.', "ALG.ALIAS.".length());
- String suffix = alias.substring(sep + 1);
+ reinitializeMappingTableLocked();
+ return oidTable.get(name.toUpperCase(Locale.ENGLISH));
+ }
+ }
+
+ private static void reinitializeMappingTableLocked() {
+ // Android-changed: Update the table only if the OID changed. Also synchronize
+ // on oidTable for thread safety.
+ int currentVersion = Security.getVersion();
+ if (initOidTableVersion != currentVersion) {
+ Provider[] provs = Security.getProviders();
+ for (int i=0; i<provs.length; i++) {
+ for (Enumeration<Object> enum_ = provs[i].keys();
+ enum_.hasMoreElements(); ) {
+ String alias = (String)enum_.nextElement();
+ String upperCaseAlias = alias.toUpperCase(Locale.ENGLISH);
+ int index;
+ if (upperCaseAlias.startsWith("ALG.ALIAS")) {
+ if ((index=upperCaseAlias.indexOf("OID.", 0)) != -1) {
+ index += "OID.".length();
+ if (index == alias.length()) {
+ // invalid alias entry
+ break;
+ }
+ String oidString = alias.substring(index);
+ String stdAlgName = provs[i].getProperty(alias);
+ if (stdAlgName != null) {
+ stdAlgName = stdAlgName.toUpperCase(Locale.ENGLISH);
ObjectIdentifier oid = null;
try {
- oid = new ObjectIdentifier(suffix);
+ oid = new ObjectIdentifier(oidString);
} catch (IOException e) {
// Not an OID.
}
if (oid != null) {
- String stdAlgName = provs[i].getProperty(alias);
- if (stdAlgName != null) {
- stdAlgName = stdAlgName.toUpperCase(Locale.ENGLISH);
- }
- if (stdAlgName != null && oidTable.get(stdAlgName) == null) {
+ if (!oidTable.containsKey(stdAlgName)) {
oidTable.put(stdAlgName, oid);
+ }
+ if (!nameTable.containsKey(oid)) {
+ nameTable.put(oid, stdAlgName);
+ }
+ }
+ }
+ } else {
+ // Android-changed: If the alias isn't specified with an explicit
+ // "OID." in the name, we still attempt to parse it as one.
+ final int sep = alias.indexOf('.', "ALG.ALIAS.".length());
+ String suffix = alias.substring(sep + 1);
+
+ ObjectIdentifier oid = null;
+ try {
+ oid = new ObjectIdentifier(suffix);
+ } catch (IOException e) {
+ // Not an OID.
+ }
+
+ if (oid != null) {
+ String stdAlgName = provs[i].getProperty(alias);
+ if (stdAlgName != null) {
+ stdAlgName = stdAlgName.toUpperCase(Locale.ENGLISH);
+ if (!oidTable.containsKey(stdAlgName)) {
+ oidTable.put(stdAlgName, oid);
+ }
+ if (!nameTable.containsKey(oid)) {
nameTable.put(oid, stdAlgName);
}
}
@@ -606,11 +628,9 @@
}
}
}
-
- initOidTableVersion = currentVersion;
}
- return oidTable.get(name.toUpperCase(Locale.ENGLISH));
+ initOidTableVersion = currentVersion;
}
}
diff --git a/ojluni/src/main/native/DatagramChannelImpl.c b/ojluni/src/main/native/DatagramChannelImpl.c
index 473a98d..471c62b 100644
--- a/ojluni/src/main/native/DatagramChannelImpl.c
+++ b/ojluni/src/main/native/DatagramChannelImpl.c
@@ -169,6 +169,15 @@
}
} while (retry == JNI_TRUE);
+ // Peer (or other thread) has performed an orderly shutdown, sockaddr will be
+ // invalid.
+ if (n == 0) {
+ // zero the sender field, so receive() returns null and not
+ // random garbage
+ (*env)->SetObjectField(env, this, dci_senderID, NULL);
+ return n;
+ }
+
/*
* If the source address and port match the cached address
* and port in DatagramChannelImpl then we don't need to
diff --git a/ojluni/src/main/native/Inet4AddressImpl.c b/ojluni/src/main/native/Inet4AddressImpl.c
index c424337..2856576 100755
--- a/ojluni/src/main/native/Inet4AddressImpl.c
+++ b/ojluni/src/main/native/Inet4AddressImpl.c
@@ -99,6 +99,7 @@
if (netif != NULL) {
if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
NET_ThrowNew(env, errno, "Can't bind socket");
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -137,6 +138,7 @@
*/
#endif /*__linux__ */
NET_ThrowNew(env, errno, "Can't send ICMP packet");
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -158,11 +160,13 @@
if (icmplen >= 8 && icmp->icmp_type == ICMP_ECHOREPLY
&& (ntohs(icmp->icmp_id) == pid)) {
if ((him->sin_addr.s_addr == sa_recv.sin_addr.s_addr)) {
+ untagSocket(env, fd);
close(fd);
return JNI_TRUE;
}
if (him->sin_addr.s_addr == 0) {
+ untagSocket(env, fd);
close(fd);
return JNI_TRUE;
}
@@ -172,6 +176,7 @@
} while (tmout2 > 0);
timeout -= 1000;
} while (timeout >0);
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -240,6 +245,7 @@
/*
* It didn't fail, so we can use ICMP_ECHO requests.
*/
+ tagSocket(env, fd);
return ping4(env, fd, &him, timeout, netif, ttl);
}
@@ -255,6 +261,8 @@
NET_ThrowNew(env, errno, "Can't create socket");
return JNI_FALSE;
}
+ tagSocket(env, fd);
+
if (ttl > 0) {
setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
}
@@ -265,6 +273,7 @@
if (netif != NULL) {
if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
NET_ThrowNew(env, errno, "Can't bind socket");
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -284,6 +293,7 @@
* we were able to reach the host!
*/
if (connect_rv == 0 || errno == ECONNREFUSED) {
+ untagSocket(env, fd);
close(fd);
return JNI_TRUE;
} else {
@@ -302,6 +312,7 @@
* When that happens, don't throw an exception, just return false.
*/
#endif /* __linux__ */
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -309,6 +320,7 @@
if (errno != EINPROGRESS) {
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
"connect failed");
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -322,10 +334,12 @@
connect_rv = errno;
}
if (connect_rv == 0 || connect_rv == ECONNREFUSED) {
+ untagSocket(env, fd);
close(fd);
return JNI_TRUE;
}
}
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
diff --git a/ojluni/src/main/native/Inet6AddressImpl.c b/ojluni/src/main/native/Inet6AddressImpl.c
index 27f03ce..ec766c9 100755
--- a/ojluni/src/main/native/Inet6AddressImpl.c
+++ b/ojluni/src/main/native/Inet6AddressImpl.c
@@ -180,6 +180,7 @@
if (netif != NULL) {
if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) {
NET_ThrowNew(env, errno, "Can't bind socket");
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -209,6 +210,7 @@
*/
#endif /*__linux__ */
NET_ThrowNew(env, errno, "Can't send ICMP packet");
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -230,10 +232,12 @@
if (n >= 8 && icmp6->icmp6_type == ICMP6_ECHO_REPLY &&
(ntohs(icmp6->icmp6_id) == pid)) {
if (NET_IsEqual(caddr, recv_caddr)) {
+ untagSocket(env, fd);
close(fd);
return JNI_TRUE;
}
if (NET_IsZeroAddr(caddr)) {
+ untagSocket(env, fd);
close(fd);
return JNI_TRUE;
}
@@ -242,6 +246,7 @@
} while (tmout2 > 0);
timeout -= 1000;
} while (timeout > 0);
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -322,6 +327,7 @@
fd = JVM_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
if (fd != -1) { /* Good to go, let's do a ping */
+ tagSocket(env, fd);
return ping6(env, fd, &him6, timeout, netif, ttl);
}
@@ -335,6 +341,8 @@
NET_ThrowNew(env, errno, "Can't create socket");
return JNI_FALSE;
}
+ tagSocket(env, fd);
+
if (ttl > 0) {
setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
}
@@ -345,6 +353,7 @@
if (netif != NULL) {
if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) {
NET_ThrowNew(env, errno, "Can't bind socket");
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -360,6 +369,7 @@
* we were able to reach the host!
*/
if (connect_rv == 0 || errno == ECONNREFUSED) {
+ untagSocket(env, fd);
close(fd);
return JNI_TRUE;
} else {
@@ -378,6 +388,7 @@
* When that happens, don't throw an exception, just return false.
*/
#endif /* __linux__ */
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -385,6 +396,7 @@
if (errno != EINPROGRESS) {
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
"connect failed");
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
@@ -399,10 +411,12 @@
connect_rv = errno;
}
if (connect_rv == 0 || ECONNREFUSED) {
+ untagSocket(env, fd);
close(fd);
return JNI_TRUE;
}
}
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
diff --git a/ojluni/src/main/native/Net.c b/ojluni/src/main/native/Net.c
index 3bdbf4d..e7cd5d7 100644
--- a/ojluni/src/main/native/Net.c
+++ b/ojluni/src/main/native/Net.c
@@ -167,6 +167,7 @@
#endif
fd = socket(domain, type, 0);
+ tagSocket(env, fd);
if (fd < 0) {
return handleSocketError(env, errno);
}
@@ -180,6 +181,7 @@
JNU_ThrowByNameWithLastError(env,
JNU_JAVANETPKG "SocketException",
"sun.nio.ch.Net.setIntOption");
+ untagSocket(env, fd);
close(fd);
return -1;
}
@@ -193,6 +195,7 @@
JNU_ThrowByNameWithLastError(env,
JNU_JAVANETPKG "SocketException",
"sun.nio.ch.Net.setIntOption");
+ untagSocket(env, fd);
close(fd);
return -1;
}
@@ -206,6 +209,7 @@
JNU_ThrowByNameWithLastError(env,
JNU_JAVANETPKG "SocketException",
"sun.nio.ch.Net.setIntOption");
+ untagSocket(env, fd);
close(fd);
return -1;
}
diff --git a/ojluni/src/main/native/NetworkInterface.c b/ojluni/src/main/native/NetworkInterface.c
index ff80041..94cdd03 100755
--- a/ojluni/src/main/native/NetworkInterface.c
+++ b/ojluni/src/main/native/NetworkInterface.c
@@ -452,6 +452,7 @@
(*env)->ReleaseStringUTFChars(env, name, name_utf);
+ untagSocket(env, sock);
close(sock);
return ret;
}
@@ -475,6 +476,7 @@
ret = getFlags(sock, name_utf, &flags);
+ untagSocket(env, sock);
close(sock);
(*env)->ReleaseStringUTFChars(env, name, name_utf);
@@ -705,6 +707,7 @@
}
freeifaddrs(origifa);
+ untagSocket(env, sock);
close(sock);
return ifs;
@@ -985,6 +988,7 @@
return -1;
}
+ tagSocket(env, sock);
return sock;
}
@@ -1015,6 +1019,7 @@
/* Linux starting from 2.6.? kernel allows ioctl call with either IPv4 or IPv6 socket regardless of type
of address of an interface */
+ tagSocket(env, sock);
return sock;
}
diff --git a/ojluni/src/main/native/PlainDatagramSocketImpl.c b/ojluni/src/main/native/PlainDatagramSocketImpl.c
index f4857df..1b1e3f6 100755
--- a/ojluni/src/main/native/PlainDatagramSocketImpl.c
+++ b/ojluni/src/main/native/PlainDatagramSocketImpl.c
@@ -987,6 +987,7 @@
"Error creating socket");
return;
}
+ tagSocket(env, fd);
#ifdef AF_INET6
/* Disable IPV6_V6ONLY to ensure dual-socket support */
@@ -995,6 +996,7 @@
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
sizeof(int)) < 0) {
NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
+ untagSocket(env, fd);
close(fd);
return;
}
@@ -1059,6 +1061,7 @@
return;
}
(*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
+ untagSocket(env, fd);
NET_SocketClose(fd);
}
diff --git a/ojluni/src/main/native/PlainSocketImpl.c b/ojluni/src/main/native/PlainSocketImpl.c
index 5010851..db25104 100755
--- a/ojluni/src/main/native/PlainSocketImpl.c
+++ b/ojluni/src/main/native/PlainSocketImpl.c
@@ -180,6 +180,7 @@
NET_ThrowNew(env, errno, "can't create socket");
return;
}
+ tagSocket(env, fd);
#ifdef AF_INET6
/* Disable IPV6_V6ONLY to ensure dual-socket support */
@@ -188,6 +189,7 @@
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
sizeof(int)) < 0) {
NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
+ untagSocket(env, fd);
close(fd);
return;
}
@@ -205,6 +207,7 @@
if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
sizeof(arg)) < 0) {
NET_ThrowNew(env, errno, "cannot set SO_REUSEADDR");
+ untagSocket(env, fd);
close(fd);
return;
}
@@ -746,6 +749,7 @@
socketAddressObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
if (socketAddressObj == NULL) {
/* should be pending exception */
+ untagSocket(env, fd);
close(newfd);
return;
}
@@ -815,6 +819,7 @@
}
if (fd != -1) {
(*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
+ untagSocket(env, fd);
NET_SocketClose(fd);
}
}
diff --git a/ojluni/src/main/native/net_util_md.c b/ojluni/src/main/native/net_util_md.c
index 27a45ad..c41d8bc 100755
--- a/ojluni/src/main/native/net_util_md.c
+++ b/ojluni/src/main/native/net_util_md.c
@@ -412,6 +412,7 @@
/**
* SIOCGLIFNUM failed - assume IPv6 not configured
*/
+ untagSocket(env, fd);
close(fd);
return JNI_FALSE;
}
diff --git a/ojluni/src/main/native/net_util_md.h b/ojluni/src/main/native/net_util_md.h
index cc0c033..46fa8dd 100755
--- a/ojluni/src/main/native/net_util_md.h
+++ b/ojluni/src/main/native/net_util_md.h
@@ -59,6 +59,9 @@
extern int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout);
#endif
+extern int tagSocket(JNIEnv* env, int fd);
+extern void untagSocket(JNIEnv* env, int fd);
+
#else
#define NET_Timeout JVM_Timeout
@@ -75,6 +78,9 @@
#define NET_Select select
#define NET_Poll poll
+#define tagSocket(env,fd) (void)0
+#define untagSocket(env,fd) (void)0
+
#endif
diff --git a/ojluni/src/main/native/openjdksub.mk b/ojluni/src/main/native/openjdksub.mk
index 6ec6be1..1f88335 100644
--- a/ojluni/src/main/native/openjdksub.mk
+++ b/ojluni/src/main/native/openjdksub.mk
@@ -66,6 +66,7 @@
Bits.c \
Character.cpp \
Register.cpp \
+ socket_tagger_util.cpp \
LOCAL_C_INCLUDES += \
libcore/$(srcdir) \
diff --git a/ojluni/src/main/native/socket_tagger_util.cpp b/ojluni/src/main/native/socket_tagger_util.cpp
new file mode 100644
index 0000000..b03d0aa
--- /dev/null
+++ b/ojluni/src/main/native/socket_tagger_util.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * 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. Google designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Google 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.
+ */
+
+#include "JNIHelp.h"
+#include "JniConstants.h"
+
+extern "C" {
+
+int tagSocket(JNIEnv* env, int fd) {
+ if (env->ExceptionOccurred()) { return fd; }
+ jmethodID get = env->GetStaticMethodID(JniConstants::socketTaggerClass,
+ "get", "()Ldalvik/system/SocketTagger;");
+ jobject socketTagger =
+ env->CallStaticObjectMethod(JniConstants::socketTaggerClass, get);
+ jmethodID tag = env->GetMethodID(JniConstants::socketTaggerClass,
+ "tag", "(Ljava/io/FileDescriptor;)V");
+
+ jobject fileDescriptor = jniCreateFileDescriptor(env, fd);
+ env->CallVoidMethod(socketTagger, tag, fileDescriptor);
+ return fd;
+}
+
+void untagSocket(JNIEnv* env, int fd) {
+ if (env->ExceptionOccurred()) { return; }
+ jmethodID get = env->GetStaticMethodID(JniConstants::socketTaggerClass,
+ "get", "()Ldalvik/system/SocketTagger;");
+ jobject socketTagger =
+ env->CallStaticObjectMethod(JniConstants::socketTaggerClass, get);
+ jmethodID untag = env->GetMethodID(JniConstants::socketTaggerClass,
+ "untag", "(Ljava/io/FileDescriptor;)V");
+
+ jobject fileDescriptor = jniCreateFileDescriptor(env, fd);
+ env->CallVoidMethod(socketTagger, untag, fileDescriptor);
+}
+
+}
diff --git a/support/src/test/java/libcore/java/security/TestKeyStore.java b/support/src/test/java/libcore/java/security/TestKeyStore.java
index 0fb8f2a..d6e6c91 100644
--- a/support/src/test/java/libcore/java/security/TestKeyStore.java
+++ b/support/src/test/java/libcore/java/security/TestKeyStore.java
@@ -18,6 +18,7 @@
import com.android.org.bouncycastle.asn1.DEROctetString;
import com.android.org.bouncycastle.asn1.x509.BasicConstraints;
+import com.android.org.bouncycastle.asn1.x509.CRLReason;
import com.android.org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import com.android.org.bouncycastle.asn1.x509.GeneralName;
import com.android.org.bouncycastle.asn1.x509.GeneralNames;
@@ -25,13 +26,28 @@
import com.android.org.bouncycastle.asn1.x509.KeyPurposeId;
import com.android.org.bouncycastle.asn1.x509.KeyUsage;
import com.android.org.bouncycastle.asn1.x509.NameConstraints;
+import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import com.android.org.bouncycastle.asn1.x509.X509Extensions;
+import com.android.org.bouncycastle.cert.X509CertificateHolder;
+import com.android.org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
+import com.android.org.bouncycastle.cert.ocsp.BasicOCSPResp;
+import com.android.org.bouncycastle.cert.ocsp.BasicOCSPRespBuilder;
+import com.android.org.bouncycastle.cert.ocsp.CertificateID;
+import com.android.org.bouncycastle.cert.ocsp.CertificateStatus;
+import com.android.org.bouncycastle.cert.ocsp.OCSPException;
+import com.android.org.bouncycastle.cert.ocsp.OCSPResp;
+import com.android.org.bouncycastle.cert.ocsp.OCSPRespBuilder;
+import com.android.org.bouncycastle.cert.ocsp.RevokedStatus;
import com.android.org.bouncycastle.jce.provider.BouncyCastleProvider;
+import com.android.org.bouncycastle.operator.DigestCalculatorProvider;
+import com.android.org.bouncycastle.operator.OperatorCreationException;
+import com.android.org.bouncycastle.operator.bc.BcDigestCalculatorProvider;
+import com.android.org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.io.PrintStream;
import java.math.BigInteger;
-import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
@@ -48,16 +64,14 @@
import java.security.UnrecoverableEntryException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
-import java.security.interfaces.ECPrivateKey;
-import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
-import java.util.Vector;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManager;
@@ -431,9 +445,9 @@
* name.
*
* If a CA is provided, it will be used to sign the generated
- * certificate. Otherwise, the certificate will be self
- * signed. The certificate will be valid for one day before and
- * one day after the time of creation.
+ * certificate and OCSP responses. Otherwise, the certificate
+ * will be self signed. The certificate will be valid for one
+ * day before and one day after the time of creation.
*
* Based on:
* org.bouncycastle.jce.provider.test.SigTest
@@ -581,7 +595,11 @@
long now = System.currentTimeMillis();
Date start = new Date(now - millisPerDay);
Date end = new Date(now + millisPerDay);
- BigInteger serial = BigInteger.valueOf(1);
+
+ // Generate a random serial number.
+ byte[] serialBytes = new byte[16];
+ new SecureRandom().nextBytes(serialBytes);
+ BigInteger serial = new BigInteger(1, serialBytes);
String keyAlgorithm = privateKey.getAlgorithm();
String signatureAlgorithm;
@@ -808,6 +826,53 @@
return rootCertificate(keyStore, algorithm);
}
+ private static OCSPResp generateOCSPResponse(PrivateKeyEntry server, PrivateKeyEntry issuer,
+ CertificateStatus status) throws CertificateException {
+ try {
+ X509Certificate serverCertJca = (X509Certificate) server.getCertificate();
+ X509Certificate caCertJca = (X509Certificate) issuer.getCertificate();
+
+ X509CertificateHolder caCert = new JcaX509CertificateHolder(caCertJca);
+
+ DigestCalculatorProvider digCalcProv = new BcDigestCalculatorProvider();
+ BasicOCSPRespBuilder basicBuilder = new BasicOCSPRespBuilder(
+ SubjectPublicKeyInfo.getInstance(caCertJca.getPublicKey().getEncoded()),
+ digCalcProv.get(CertificateID.HASH_SHA1));
+
+ CertificateID certId = new CertificateID(digCalcProv.get(CertificateID.HASH_SHA1),
+ caCert, serverCertJca.getSerialNumber());
+
+ basicBuilder.addResponse(certId, status);
+
+ BasicOCSPResp resp = basicBuilder.build(
+ new JcaContentSignerBuilder("SHA256withRSA").build(issuer.getPrivateKey()),
+ null, new Date());
+
+ OCSPRespBuilder builder = new OCSPRespBuilder();
+ return builder.build(OCSPRespBuilder.SUCCESSFUL, resp);
+ } catch (Exception e) {
+ throw new CertificateException("cannot generate OCSP response", e);
+ }
+ }
+
+ public static byte[] getOCSPResponseForGood(PrivateKeyEntry server, PrivateKeyEntry issuer) throws CertificateException {
+ try {
+ return generateOCSPResponse(server, issuer, CertificateStatus.GOOD).getEncoded();
+ } catch (IOException e) {
+ throw new CertificateException(e);
+ }
+ }
+
+ public static byte[] getOCSPResponseForRevoked(PrivateKeyEntry server, PrivateKeyEntry issuer)
+ throws CertificateException {
+ try {
+ return generateOCSPResponse(server, issuer,
+ new RevokedStatus(new Date(), CRLReason.keyCompromise)).getEncoded();
+ } catch (IOException e) {
+ throw new CertificateException(e);
+ }
+ }
+
/**
* Return the only self-signed root certificate in a keystore for
* the given algorithm. Throws IllegalStateException if there are