Merge "reflect: Clean up Proxy to remove dead code"
diff --git a/benchmarks/src/benchmarks/ReferenceBenchmark.java b/benchmarks/src/benchmarks/ReferenceBenchmark.java
index 80bcb5e..f1b84a3 100644
--- a/benchmarks/src/benchmarks/ReferenceBenchmark.java
+++ b/benchmarks/src/benchmarks/ReferenceBenchmark.java
@@ -18,6 +18,9 @@
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Benchmark to evaluate the performance of References.
@@ -67,4 +70,58 @@
}
}
}
+
+ // How fast can references can be implicitly allocated, enqueued, and
+ // removed?
+ public void timeAllocImplicitEnqueueAndRemove(int reps) {
+ ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
+ List<Object> refs = new ArrayList<Object>();
+ for (int i = 0; i < reps; i++) {
+ refs.add(new PhantomReference<Object>(new Object(), queue));
+ }
+ Runtime.getRuntime().gc();
+ for (int i = 0; i < reps; i++) {
+ try {
+ queue.remove();
+ } catch (InterruptedException ie) {
+ i--;
+ }
+ }
+ }
+
+ static private class FinalizableObject {
+ AtomicInteger count;
+
+ public FinalizableObject(AtomicInteger count) {
+ this.count = count;
+ }
+
+ @Override
+ protected void finalize() {
+ count.incrementAndGet();
+ }
+ }
+
+ // How fast does finalization run?
+ public void timeFinalization(int reps) {
+ // Allocate a bunch of finalizable objects.
+ int n = reps;
+ AtomicInteger count = new AtomicInteger(0);
+ for (int i = 0; i < n; i++) {
+ new FinalizableObject(count);
+ }
+
+ // Run GC so the objects will be collected for finalization.
+ Runtime.getRuntime().gc();
+
+ // Wait for finalization.
+ Runtime.getRuntime().runFinalization();
+
+ // Double check all the objects were finalized.
+ int got = count.get();
+ if (n != got) {
+ throw new IllegalStateException(
+ String.format("Only %i of %i objects finalized?", got, n));
+ }
+ }
}
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index cf6c852..9b5439e 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -1448,8 +1448,8 @@
description: "OkHttp tests that fail on Wear devices due to a lack of memory",
bug: 20055487,
names: [
- "com.squareup.okhttp.internal.spdy.Http20Draft09Test#tooLargeDataFrame",
- "com.squareup.okhttp.internal.spdy.Spdy3Test#tooLargeDataFrame"
+ "com.squareup.okhttp.internal.framed.Http2Test#tooLargeDataFrame",
+ "com.squareup.okhttp.internal.framed.Spdy3Test#tooLargeDataFrame"
]
},
{
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
index 0bc8920..173e37e 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
@@ -602,7 +602,7 @@
try {
JarFile jar = new JarFile(signedFile);
- JarEntry entry = new JarEntry(entryName3);
+ JarEntry entry = jar.getJarEntry(entryName3);
entry.setSize(1076);
InputStream in = jar.getInputStream(entry);
// BEGIN android-added
diff --git a/libart/src/main/java/java/lang/Daemons.java b/libart/src/main/java/java/lang/Daemons.java
index e59643c..15a8ab6 100644
--- a/libart/src/main/java/java/lang/Daemons.java
+++ b/libart/src/main/java/java/lang/Daemons.java
@@ -157,20 +157,9 @@
} catch (OutOfMemoryError e) {
continue;
}
- enqueue(list);
+ ReferenceQueue.enqueuePending(list);
}
}
-
- private void enqueue(Reference<?> list) {
- Reference<?> start = list;
- do {
- // pendingNext is owned by the GC so no synchronization is required.
- Reference<?> next = list.pendingNext;
- list.pendingNext = null;
- list.enqueueInternal();
- list = next;
- } while (list != start);
- }
}
private static class FinalizerDaemon extends Daemon {
diff --git a/luni/src/test/java/libcore/java/io/FileInputStreamTest.java b/luni/src/test/java/libcore/java/io/FileInputStreamTest.java
index b6650ff..398adbc 100644
--- a/luni/src/test/java/libcore/java/io/FileInputStreamTest.java
+++ b/luni/src/test/java/libcore/java/io/FileInputStreamTest.java
@@ -22,6 +22,11 @@
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.system.ErrnoException;
+import android.system.OsConstants;
import junit.framework.TestCase;
import libcore.io.IoUtils;
@@ -204,4 +209,36 @@
FileInputStream input = new FileInputStream(file);
assertTrue(input.available() == 0);
}
+
+ // http://b/25695227
+ public void testFdLeakWhenOpeningDirectory() throws Exception {
+ File phile = IoUtils.createTemporaryDirectory("test_bug_25695227");
+
+ try {
+ new FileInputStream(phile);
+ fail();
+ } catch (FileNotFoundException expected) {
+ }
+
+ assertTrue(getOpenFdsForPrefix("test_bug_25695227").isEmpty());
+ }
+
+ private static List<Integer> getOpenFdsForPrefix(String path) throws Exception {
+ File[] fds = new File("/proc/self/fd").listFiles();
+ List<Integer> list = new ArrayList<>();
+ for (File fd : fds) {
+ try {
+ File fdPath = new File(android.system.Os.readlink(fd.getAbsolutePath()));
+ if (fdPath.getName().startsWith(path)) {
+ list.add(Integer.valueOf(fd.getName()));
+ }
+ } catch (ErrnoException e) {
+ if (e.errno != OsConstants.ENOENT) {
+ throw e.rethrowAsIOException();
+ }
+ }
+ }
+
+ return list;
+ }
}
diff --git a/luni/src/test/java/libcore/java/net/URLTest.java b/luni/src/test/java/libcore/java/net/URLTest.java
index 07e651c..2717d14 100644
--- a/luni/src/test/java/libcore/java/net/URLTest.java
+++ b/luni/src/test/java/libcore/java/net/URLTest.java
@@ -22,6 +22,8 @@
import java.net.URISyntaxException;
import java.net.URI;
import java.net.URL;
+
+import dalvik.system.BlockGuard;
import junit.framework.TestCase;
import libcore.util.SerializationTester;
@@ -712,35 +714,40 @@
assertEquals("a_b.c.d.net", url.getHost());
}
- // http://b/7369778
- public void testToURILeniantThrowsURISyntaxExceptionWithPartialTrailingEscape()
- throws Exception {
- // make sure if there a partial trailing escape that we don't throw the wrong exception
- URL[] badUrls = new URL[] {
- new URL("http://example.com/?foo=%%bar"),
- new URL("http://example.com/?foo=%%bar%"),
- new URL("http://example.com/?foo=%%bar%2"),
- new URL("http://example.com/?foo=%%bar%%"),
- new URL("http://example.com/?foo=%%bar%%%"),
- new URL("http://example.com/?foo=%%bar%%%%"),
- };
- for (URL badUrl : badUrls) {
- try {
- badUrl.toURILenient();
- fail();
- } catch (URISyntaxException expected) {
+ // http://b/26895969
+ // http://b/26798800
+ public void testHashCodeAndEqualsDoesNotPerformNetworkIo() throws Exception {
+ final BlockGuard.Policy oldPolicy = BlockGuard.getThreadPolicy();
+ BlockGuard.setThreadPolicy(new BlockGuard.Policy() {
+ @Override
+ public void onWriteToDisk() {
+ fail("Blockguard.Policy.onWriteToDisk");
}
- }
- // make sure we properly handle an normal escape at the end of a string
- String[] goodUrls = new String[] {
- "http://example.com/?foo=bar",
- "http://example.com/?foo=bar%20",
- };
- for (String goodUrl : goodUrls) {
- assertEquals(new URI(goodUrl), new URL(goodUrl).toURILenient());
+ @Override
+ public void onReadFromDisk() {
+ fail("Blockguard.Policy.onReadFromDisk");
+ }
+
+ @Override
+ public void onNetwork() {
+ fail("Blockguard.Policy.onNetwork");
+ }
+
+ @Override
+ public int getPolicyMask() {
+ return 0;
+ }
+ });
+
+ try {
+ URL url = new URL("http://www.google.com/");
+ URL url2 = new URL("http://www.nest.com/");
+
+ url.equals(url2);
+ url2.hashCode();
+ } finally {
+ BlockGuard.setThreadPolicy(oldPolicy);
}
}
-
- // Adding a new test? Consider adding an equivalent test to URITest.java
}
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 c901a08..f87cf4d 100644
--- a/luni/src/test/java/libcore/java/nio/channels/SocketChannelTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/SocketChannelTest.java
@@ -19,8 +19,10 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.lang.reflect.Field;
import java.net.ConnectException;
import java.net.Socket;
+import java.net.SocketImpl;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
@@ -264,4 +266,14 @@
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);
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/CalendarTest.java b/luni/src/test/java/libcore/java/util/CalendarTest.java
index f7113d0..7f30b3d 100644
--- a/luni/src/test/java/libcore/java/util/CalendarTest.java
+++ b/luni/src/test/java/libcore/java/util/CalendarTest.java
@@ -210,8 +210,22 @@
}
// https://code.google.com/p/android/issues/detail?id=45877
- public void test_clear_45877() {
+ public void test_clear_45877_morning() {
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("America/Los_Angeles"));
+ // 3rd February 2016 05:32:40.000 America/Los_Angeles time.
+ cal.setTimeInMillis(1454506360000L);
+ checkClear(cal, 0, 28800000);
+ }
+
+ // https://code.google.com/p/android/issues/detail?id=45877
+ public void test_clear_45877_afternoon() {
+ GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("America/Los_Angeles"));
+ // 3rd February 2016 12:32:40.000 America/Los_Angeles time.
+ cal.setTimeInMillis(1454531560000L);
+ checkClear(cal, 12, 72000000);
+ }
+
+ private void checkClear(GregorianCalendar cal, int expectedHourOfDay, long expectedMillis) {
cal.set(Calendar.YEAR, 1970);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.DAY_OF_MONTH, 1);
@@ -226,7 +240,7 @@
assertFalse(cal.isSet(Calendar.HOUR_OF_DAY));
// When we call get, unset fields are computed.
- assertEquals(0, cal.get(Calendar.HOUR_OF_DAY));
+ assertEquals(expectedHourOfDay, cal.get(Calendar.HOUR_OF_DAY));
// And set fields stay the same.
assertEquals(1, cal.get(Calendar.DAY_OF_MONTH));
@@ -234,7 +248,7 @@
assertTrue(cal.isSet(Calendar.DAY_OF_MONTH));
assertTrue(cal.isSet(Calendar.HOUR_OF_DAY));
- assertEquals(28800000, cal.getTimeInMillis());
+ assertEquals(expectedMillis, cal.getTimeInMillis());
cal.set(Calendar.HOUR_OF_DAY, 1);
assertEquals(32400000, cal.getTimeInMillis());
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java
index 5e3a3d5..d50a170 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java
@@ -661,6 +661,20 @@
}
}
+ public void test_SSLEngine_endpointVerification_Success() throws Exception {
+ TestSSLContext c = TestSSLContext.create();
+ TestSSLEnginePair p = TestSSLEnginePair.create(c, new TestSSLEnginePair.Hooks() {
+ @Override
+ void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+ SSLParameters p = client.getSSLParameters();
+ p.setEndpointIdentificationAlgorithm("HTTPS");
+ client.setSSLParameters(p);
+ }
+ });
+ assertConnected(p);
+ c.close();
+ }
+
public void test_SSLEngine_getEnableSessionCreation() throws Exception {
TestSSLContext c = TestSSLContext.create();
SSLEngine e = c.clientContext.createSSLEngine();
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
index 278d44e..d44cda9 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
@@ -68,6 +68,7 @@
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.StandardConstants;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
@@ -333,6 +334,13 @@
assertFalse(session.isValid());
}
+ public void test_SSLSocket_getHandshakeSession() throws Exception {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ SSLSocket ssl = (SSLSocket) sf.createSocket();
+ SSLSession session = ssl.getHandshakeSession();
+ assertNull(session);
+ }
+
public void test_SSLSocket_startHandshake() throws Exception {
final TestSSLContext c = TestSSLContext.create();
SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
@@ -343,6 +351,7 @@
@Override public Void call() throws Exception {
server.startHandshake();
assertNotNull(server.getSession());
+ assertNull(server.getHandshakeSession());
try {
server.getSession().getPeerCertificates();
fail();
@@ -393,8 +402,8 @@
final TestSSLContext c = TestSSLContext.create();
final ExecutorService executor = Executors.newSingleThreadExecutor();
- final SSLSocket client1 = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
- c.port);
+ final SSLSocket client1 = (SSLSocket) c.clientContext.getSocketFactory()
+ .createSocket(c.host.getHostName(), c.port);
final SSLSocket server1 = (SSLSocket) c.serverSocket.accept();
final Future<byte[]> future1 = executor.submit(new SSLServerSessionIdCallable(server1));
client1.startHandshake();
@@ -406,8 +415,8 @@
client1.close();
server1.close();
- final SSLSocket client2 = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
- c.port);
+ final SSLSocket client2 = (SSLSocket) c.clientContext.getSocketFactory()
+ .createSocket(c.host.getHostName(), c.port);
final SSLSocket server2 = (SSLSocket) c.serverSocket.accept();
final Future<byte[]> future2 = executor.submit(new SSLServerSessionIdCallable(server2));
client2.startHandshake();
@@ -585,6 +594,7 @@
assertSame(client, socket);
assertTrue(socket instanceof SSLSocket);
+ assertNull(((SSLSocket) socket).getHandshakeSession());
synchronized (handshakeCompletedListenerCalled) {
handshakeCompletedListenerCalled[0] = true;
@@ -1015,6 +1025,14 @@
assertEquals(p.getWantClientAuth(), ssl.getWantClientAuth());
assertEquals(p.getNeedClientAuth(), ssl.getNeedClientAuth());
+
+ assertNull(p.getEndpointIdentificationAlgorithm());
+ p.setEndpointIdentificationAlgorithm(null);
+ assertNull(p.getEndpointIdentificationAlgorithm());
+ p.setEndpointIdentificationAlgorithm("HTTPS");
+ assertEquals("HTTPS", p.getEndpointIdentificationAlgorithm());
+ p.setEndpointIdentificationAlgorithm("FOO");
+ assertEquals("FOO", p.getEndpointIdentificationAlgorithm());
}
public void test_SSLSocket_setSSLParameters() throws Exception {
@@ -1198,6 +1216,83 @@
server.close();
}
+ public void test_SSLSocket_endpointIdentification_Success() throws Exception {
+ final TestSSLContext c = TestSSLContext.create();
+ SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket();
+ SSLParameters p = client.getSSLParameters();
+ p.setEndpointIdentificationAlgorithm("HTTPS");
+ client.connect(new InetSocketAddress(c.host, c.port));
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Future<Void> future = executor.submit(new Callable<Void>() {
+ @Override public Void call() throws Exception {
+ server.startHandshake();
+ assertNotNull(server.getSession());
+ try {
+ server.getSession().getPeerCertificates();
+ fail();
+ } catch (SSLPeerUnverifiedException expected) {
+ }
+ Certificate[] localCertificates = server.getSession().getLocalCertificates();
+ assertNotNull(localCertificates);
+ TestKeyStore.assertChainLength(localCertificates);
+ assertNotNull(localCertificates[0]);
+ TestSSLContext.assertCertificateInKeyStore(localCertificates[0],
+ c.serverKeyStore);
+ return null;
+ }
+ });
+ executor.shutdown();
+ client.startHandshake();
+ assertNotNull(client.getSession());
+ assertNull(client.getSession().getLocalCertificates());
+ Certificate[] peerCertificates = client.getSession().getPeerCertificates();
+ assertNotNull(peerCertificates);
+ TestKeyStore.assertChainLength(peerCertificates);
+ assertNotNull(peerCertificates[0]);
+ TestSSLContext.assertCertificateInKeyStore(peerCertificates[0], c.serverKeyStore);
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ }
+
+ public void test_SSLSocket_endpointIdentification_Failure() throws Exception {
+ final TestSSLContext c = TestSSLContext.create();
+ SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(
+ InetAddress.getByName("127.0.0.2"), c.port);
+ SSLParameters p = client.getSSLParameters();
+ p.setEndpointIdentificationAlgorithm("HTTPS");
+ client.setSSLParameters(p);
+ // client.connect(new InetSocketAddress(c.host, c.port));
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Future<Void> future = executor.submit(new Callable<Void>() {
+ @Override public Void call() throws Exception {
+ try {
+ server.startHandshake();
+ fail("Should receive SSLHandshakeException as server");
+ } catch (SSLHandshakeException expected) {
+ }
+ return null;
+ }
+ });
+ executor.shutdown();
+ try {
+ client.startHandshake();
+ fail("Should throw when hostname does not match expected");
+ } catch (SSLHandshakeException expected) {
+ } finally {
+ try {
+ future.get();
+ } finally {
+ client.close();
+ server.close();
+ c.close();
+ }
+ }
+ }
+
public void test_SSLSocket_setSoTimeout_basic() throws Exception {
ServerSocket listening = new ServerSocket(0);
@@ -1811,6 +1906,7 @@
assertNotNull(requestedNames);
assertEquals(1, requestedNames.size());
SNIServerName serverName = requestedNames.get(0);
+ assertEquals(StandardConstants.SNI_HOST_NAME, serverName.getType());
assertTrue(serverName instanceof SNIHostName);
SNIHostName serverHostName = (SNIHostName) serverName;
assertEquals("www.example.com", serverHostName.getAsciiName());
diff --git a/ojluni/src/main/java/java/lang/ref/Reference.java b/ojluni/src/main/java/java/lang/ref/Reference.java
index 32abb9b..160eca1 100755
--- a/ojluni/src/main/java/java/lang/ref/Reference.java
+++ b/ojluni/src/main/java/java/lang/ref/Reference.java
@@ -26,8 +26,6 @@
package java.lang.ref;
-import sun.misc.Cleaner;
-
/**
* Abstract base class for reference objects. This class defines the
@@ -57,13 +55,32 @@
private static boolean slowPathEnabled = false;
volatile T referent; /* Treated specially by GC */
- volatile ReferenceQueue<? super T> queue;
- volatile Reference queueNext;
+ final ReferenceQueue<? super T> queue;
+
+ /*
+ * This field forms a singly-linked list of reference objects that have
+ * been enqueued. The queueNext field is non-null if and only if this
+ * reference has been enqueued. After this reference has been enqueued and
+ * before it has been removed from its queue, the queueNext field points
+ * to the next reference on the queue. The last reference on a queue
+ * points to itself. Once this reference has been removed from the
+ * reference queue, the queueNext field points to the
+ * ReferenceQueue.sQueueNextUnenqueued sentinel reference object for the
+ * rest of this reference's lifetime.
+ * <p>
+ * Access to the queueNext field is guarded by synchronization on a lock
+ * internal to 'queue'.
+ */
+ Reference queueNext;
/**
- * @hide
+ * The pendingNext field is initially set by the GC. After the GC forms a
+ * complete circularly linked list, the list is handed off to the
+ * ReferenceQueueDaemon using the ReferenceQueue.class lock. The
+ * ReferenceQueueDaemon can then read the pendingNext fields without
+ * additional synchronization.
*/
- public volatile Reference<?> pendingNext;
+ Reference<?> pendingNext;
/* -- Referent accessor and setters -- */
@@ -105,26 +122,11 @@
* been enqueued
*/
public boolean isEnqueued() {
- return queueNext != null;
- }
-
- /** @hide */
- public final synchronized boolean enqueueInternal() {
- if (this instanceof Cleaner) {
- // If this reference is a Cleaner, then simply invoke the clean method instead
- // of enqueueing it in the queue. Cleaners are associated with dummy queues that
- // are never polled and objects are never enqueued on them.
- Cleaner cl = (sun.misc.Cleaner) this;
- cl.clean();
- return true;
- }
-
- if (queue != null && queueNext == null) {
- queue.enqueue(this);
- queue = null;
- return true;
- }
- return false;
+ // Contrary to what the documentation says, this method returns false
+ // after this reference object has been removed from its queue
+ // (b/26647823). ReferenceQueue.isEnqueued preserves this historically
+ // incorrect behavior.
+ return queue != null && queue.isEnqueued(this);
}
/**
@@ -139,7 +141,7 @@
* it was not registered with a queue when it was created
*/
public boolean enqueue() {
- return enqueueInternal();
+ return queue != null && queue.enqueue(this);
}
diff --git a/ojluni/src/main/java/java/lang/ref/ReferenceQueue.java b/ojluni/src/main/java/java/lang/ref/ReferenceQueue.java
index 1bf4941..80c65d9 100755
--- a/ojluni/src/main/java/java/lang/ref/ReferenceQueue.java
+++ b/ojluni/src/main/java/java/lang/ref/ReferenceQueue.java
@@ -26,6 +26,8 @@
package java.lang.ref;
+import sun.misc.Cleaner;
+
/**
* Reference queues, to which registered reference objects are appended by the
* garbage collector after the appropriate reachability changes are detected.
@@ -35,6 +37,10 @@
*/
public class ReferenceQueue<T> {
+ // Reference.queueNext will be set to sQueueNextUnenqueued to indicate
+ // when a reference has been enqueued and removed from its queue.
+ private static final Reference sQueueNextUnenqueued = new PhantomReference(null, null);
+
// NOTE: This implementation of ReferenceQueue is FIFO (queue-like) whereas
// the OpenJdk implementation is LIFO (stack-like).
private Reference<? extends T> head = null;
@@ -47,18 +53,68 @@
*/
public ReferenceQueue() { }
- boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */
- synchronized (lock) {
- if (tail == null) {
- head = r;
- } else {
- tail.queueNext = r;
- }
- tail = r;
- tail.queueNext = r;
- lock.notifyAll();
+ /**
+ * Enqueue the given reference onto this queue.
+ * The caller is responsible for ensuring the lock is held on this queue,
+ * and for calling notifyAll on this queue after the reference has been
+ * enqueued. Returns true if the reference was enqueued successfully,
+ * false if the reference had already been enqueued.
+ * @GuardedBy("lock")
+ */
+ private boolean enqueueLocked(Reference<? extends T> r) {
+ // Verify the reference has not already been enqueued.
+ if (r.queueNext != null) {
+ return false;
+ }
+
+ if (r instanceof Cleaner) {
+ // If this reference is a Cleaner, then simply invoke the clean method instead
+ // of enqueueing it in the queue. Cleaners are associated with dummy queues that
+ // are never polled and objects are never enqueued on them.
+ Cleaner cl = (sun.misc.Cleaner) r;
+ cl.clean();
+
+ // Update queueNext to indicate that the reference has been
+ // enqueued, but is now removed from the queue.
+ r.queueNext = sQueueNextUnenqueued;
return true;
}
+
+ if (tail == null) {
+ head = r;
+ } else {
+ tail.queueNext = r;
+ }
+ tail = r;
+ tail.queueNext = r;
+ return true;
+ }
+
+ /**
+ * Test if the given reference object has been enqueued but not yet
+ * removed from the queue, assuming this is the reference object's queue.
+ */
+ boolean isEnqueued(Reference<? extends T> reference) {
+ synchronized (lock) {
+ return reference.queueNext != null && reference.queueNext != sQueueNextUnenqueued;
+ }
+ }
+
+ /**
+ * Enqueue the reference object on the receiver.
+ *
+ * @param reference
+ * reference object to be enqueued.
+ * @return true if the reference was enqueued.
+ */
+ boolean enqueue(Reference<? extends T> reference) {
+ synchronized (lock) {
+ if (enqueueLocked(reference)) {
+ lock.notifyAll();
+ return true;
+ }
+ return false;
+ }
}
// @GuardedBy("lock")
@@ -71,7 +127,10 @@
} else {
head = head.queueNext;
}
- r.queueNext = null;
+
+ // Update queueNext to indicate that the reference has been
+ // enqueued, but is now removed from the queue.
+ r.queueNext = sQueueNextUnenqueued;
return r;
}
@@ -150,7 +209,51 @@
return remove(0);
}
- /** @hide */
+ /**
+ * Enqueue the given list of currently pending (unenqueued) references.
+ *
+ * @hide
+ */
+ public static void enqueuePending(Reference<?> list) {
+ Reference<?> start = list;
+ do {
+ ReferenceQueue queue = list.queue;
+ if (queue == null) {
+ Reference<?> next = list.pendingNext;
+
+ // Make pendingNext a self-loop to preserve the invariant that
+ // once enqueued, pendingNext is non-null -- without leaking
+ // the object pendingNext was previously pointing to.
+ list.pendingNext = list;
+ list = next;
+ } else {
+ // To improve performance, we try to avoid repeated
+ // synchronization on the same queue by batching enqueue of
+ // consecutive references in the list that have the same
+ // queue.
+ synchronized (queue.lock) {
+ do {
+ Reference<?> next = list.pendingNext;
+
+ // Make pendingNext a self-loop to preserve the
+ // invariant that once enqueued, pendingNext is
+ // non-null -- without leaking the object pendingNext
+ // was previously pointing to.
+ list.pendingNext = list;
+ queue.enqueueLocked(list);
+ list = next;
+ } while (list != start && list.queue == queue);
+ queue.lock.notifyAll();
+ }
+ }
+ } while (list != start);
+ }
+
+ /**
+ * List of references that the GC says need to be enqueued.
+ * Protected by ReferenceQueue.class lock.
+ * @hide
+ */
public static Reference<?> unenqueued = null;
static void add(Reference<?> list) {
diff --git a/ojluni/src/main/java/java/net/URI.java b/ojluni/src/main/java/java/net/URI.java
index b3dbaad..5a78d6e 100755
--- a/ojluni/src/main/java/java/net/URI.java
+++ b/ojluni/src/main/java/java/net/URI.java
@@ -34,7 +34,6 @@
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.CharacterCodingException;
@@ -43,7 +42,6 @@
import java.lang.Character; // for javadoc
import java.lang.NullPointerException; // for javadoc
-import libcore.net.UriCodec;
/**
@@ -468,40 +466,6 @@
public final class URI
implements Comparable<URI>, Serializable
{
- static final String UNRESERVED = "_-!.~\'()*";
- static final String PUNCTUATION = ",;:$&+=";
- static final UriCodec AUTHORITY_ENCODER = new PartEncoder("@[]");
-
- /** for java.net.URL, which foolishly combines these two parts */
- static final UriCodec FILE_AND_QUERY_ENCODER = new PartEncoder("/@?");
-
- /** for query, fragment, and scheme-specific part */
- static final UriCodec ALL_LEGAL_ENCODER = new PartEncoder("?/[]@");
-
- /**
- * Encodes the unescaped characters of {@code s} that are not permitted.
- * Permitted characters are:
- * <ul>
- * <li>Unreserved characters in <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>.
- * <li>{@code extraOkayChars},
- * <li>non-ASCII, non-control, non-whitespace characters
- * </ul>
- */
- private static class PartEncoder extends UriCodec {
- private final String extraLegalCharacters;
-
- PartEncoder(String extraLegalCharacters) {
- this.extraLegalCharacters = extraLegalCharacters;
- }
-
- @Override protected boolean isRetained(char c) {
- return UNRESERVED.indexOf(c) != -1
- || PUNCTUATION.indexOf(c) != -1
- || extraLegalCharacters.indexOf(c) != -1
- || (c > 127 && !Character.isSpaceChar(c) && !Character.isISOControl(c));
- }
- }
-
// Note: Comments containing the word "ASSERT" indicate places where a
// throw of an InternalError should be replaced by an appropriate assertion
// statement once asserts are enabled in the build.
diff --git a/ojluni/src/main/java/java/net/URL.java b/ojluni/src/main/java/java/net/URL.java
index 2372cc4..b585e2b 100755
--- a/ojluni/src/main/java/java/net/URL.java
+++ b/ojluni/src/main/java/java/net/URL.java
@@ -843,16 +843,32 @@
* equivalent hosts, have the same port number on the host, and the same
* file and fragment of the file.<p>
*
- * Two hosts are considered equivalent if both host names can be resolved
- * into the same IP addresses; else if either host name can't be
- * resolved, the host names must be equal without regard to case; or both
- * host names equal to null.<p>
+ * Returns true if this URL equals {@code o}. URLs are equal if they have
+ * the same protocol, host, port, file, and reference.
*
- * Since hosts comparison requires name resolution, this operation is a
- * blocking operation. <p>
- *
- * Note: The defined behavior for <code>equals</code> is known to
- * be inconsistent with virtual hosting in HTTP.
+ * <h3>Network I/O Warning</h3>
+ * <p>Some implementations of URL.equals() resolve host names over the
+ * network. This is problematic:
+ * <ul>
+ * <li><strong>The network may be slow.</strong> Many classes, including
+ * core collections like {@link java.util.Map Map} and {@link java.util.Set
+ * Set} expect that {@code equals} and {@code hashCode} will return quickly.
+ * By violating this assumption, this method posed potential performance
+ * problems.
+ * <li><strong>Equal IP addresses do not imply equal content.</strong>
+ * Virtual hosting permits unrelated sites to share an IP address. This
+ * method could report two otherwise unrelated URLs to be equal because
+ * they're hosted on the same server.</li>
+ * <li><strong>The network may not be available.</strong> Two URLs could be
+ * equal when a network is available and unequal otherwise.</li>
+ * <li><strong>The network may change.</strong> The IP address for a given
+ * host name varies by network and over time. This is problematic for mobile
+ * devices. Two URLs could be equal on some networks and unequal on
+ * others.</li>
+ * </ul>
+ * <p>This problem is fixed in Android 4.0 (Ice Cream Sandwich). In that
+ * release, URLs are only equal if their host names are equal (ignoring
+ * case).
*
* @param obj the URL to compare against.
* @return <code>true</code> if the objects are the same;
@@ -1294,14 +1310,6 @@
}
hashCode = -1;
}
-
- public URI toURILenient() throws URISyntaxException {
- URLStreamHandler handler = getURLStreamHandler(protocol);
- if (handler == null) {
- throw new IllegalStateException(protocol);
- }
- return new URI(handler.toExternalForm(this, true));
- }
}
class Parts {
diff --git a/ojluni/src/main/java/java/net/URLStreamHandler.java b/ojluni/src/main/java/java/net/URLStreamHandler.java
index 0be5d75..e64b9b8 100755
--- a/ojluni/src/main/java/java/net/URLStreamHandler.java
+++ b/ojluni/src/main/java/java/net/URLStreamHandler.java
@@ -27,12 +27,9 @@
package java.net;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.File;
-import java.io.OutputStream;
-import java.util.Hashtable;
+import java.util.Objects;
+
import sun.net.util.IPAddressUtil;
-import sun.net.www.ParseUtil;
/**
* The abstract class <code>URLStreamHandler</code> is the common
@@ -368,9 +365,10 @@
* @since 1.3
*/
protected boolean equals(URL u1, URL u2) {
- String ref1 = u1.getRef();
- String ref2 = u2.getRef();
- return (ref1 == ref2 || (ref1 != null && ref1.equals(ref2))) &&
+ return Objects.equals(u1.getRef(), u2.getRef()) &&
+ Objects.equals(u1.getQuery(), u2.getQuery()) &&
+ // sameFile compares the protocol, file, port & host components of
+ // the URLs.
sameFile(u1, u2);
}
@@ -383,40 +381,14 @@
* @since 1.3
*/
protected int hashCode(URL u) {
- int h = 0;
-
- // Generate the protocol part.
- String protocol = u.getProtocol();
- if (protocol != null)
- h += protocol.hashCode();
-
- // Generate the host part.
- InetAddress addr = getHostAddress(u);
- if (addr != null) {
- h += addr.hashCode();
- } else {
- String host = u.getHost();
- if (host != null)
- h += host.toLowerCase().hashCode();
- }
-
- // Generate the file part.
- String file = u.getFile();
- if (file != null)
- h += file.hashCode();
-
- // Generate the port part.
- if (u.getPort() == -1)
- h += getDefaultPort();
- else
- h += u.getPort();
-
- // Generate the ref part.
- String ref = u.getRef();
- if (ref != null)
- h += ref.hashCode();
-
- return h;
+ // Hash on the same set of fields that we compare in equals().
+ return Objects.hash(
+ u.getRef(),
+ u.getQuery(),
+ u.getProtocol(),
+ u.getFile(),
+ u.getHost(),
+ u.getPort());
}
/**
@@ -493,18 +465,8 @@
* @since 1.3
*/
protected boolean hostsEqual(URL u1, URL u2) {
- // ----- BEGIN android -----
- // Stop doing host lookups in URL#equals, it's silly.
- //
- // InetAddress a1 = getHostAddress(u1);
- // InetAddress a2 = getHostAddress(u2);
- // // if we have internet address for both, compare them
- // if (a1 != null && a2 != null) {
- // return a1.equals(a2);
- // // else, if both have host names, compare them
- // } else if (u1.getHost() != null && u2.getHost() != null)
+ // Android changed: Don't compare the InetAddresses of the hosts.
if (u1.getHost() != null && u2.getHost() != null)
- // ----- END android -----
return u1.getHost().equalsIgnoreCase(u2.getHost());
else
return u1.getHost() == null && u2.getHost() == null;
@@ -518,10 +480,6 @@
* @return a string representation of the <code>URL</code> argument.
*/
protected String toExternalForm(URL u) {
- return toExternalForm(u, false);
- }
-
- String toExternalForm(URL u, boolean escapeIllegalCharacters) {
// pre-compute length of StringBuffer
int len = u.getProtocol().length() + 1;
if (u.getAuthority() != null && u.getAuthority().length() > 0)
@@ -540,27 +498,15 @@
result.append(":");
if (u.getAuthority() != null) {// ANDROID: && u.getAuthority().length() > 0) {
result.append("//");
- if (escapeIllegalCharacters) {
- URI.AUTHORITY_ENCODER.appendPartiallyEncoded(result, u.getAuthority());
- } else {
- result.append(u.getAuthority());
- }
+ result.append(u.getAuthority());
}
String fileAndQuery = u.getFile();
if (fileAndQuery != null) {
- if (escapeIllegalCharacters) {
- URI.FILE_AND_QUERY_ENCODER.appendPartiallyEncoded(result, fileAndQuery);
- } else {
- result.append(fileAndQuery);
- }
+ result.append(fileAndQuery);
}
if (u.getRef() != null) {
result.append("#");
- if (escapeIllegalCharacters) {
- URI.ALL_LEGAL_ENCODER.appendPartiallyEncoded(result, u.getRef());
- } else {
- result.append(u.getRef());
- }
+ result.append(u.getRef());
}
return result.toString();
}
diff --git a/ojluni/src/main/java/java/util/WeakHashMap.java b/ojluni/src/main/java/java/util/WeakHashMap.java
index a8ca523..652b053 100755
--- a/ojluni/src/main/java/java/util/WeakHashMap.java
+++ b/ojluni/src/main/java/java/util/WeakHashMap.java
@@ -243,9 +243,10 @@
/**
* A randomizing value associated with this instance that is applied to
* hash code of keys to make hash collisions harder to find.
+ *
+ * This hash seed is only used if {@code useAltHashing} is true.
*/
transient int hashSeed;
- volatile boolean seedSet = false;
@SuppressWarnings("unchecked")
private Entry<K,V>[] newTable(int n) {
@@ -279,6 +280,11 @@
threshold = (int)(capacity * loadFactor);
useAltHashing = sun.misc.VM.isBooted() &&
(capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
+ if (useAltHashing) {
+ hashSeed = sun.misc.Hashing.randomHashSeed(this);
+ } else {
+ hashSeed = 0;
+ }
}
/**
@@ -357,14 +363,6 @@
int h;
if (useAltHashing) {
- if (!seedSet) {
- synchronized(this) {
- if (!seedSet) {
- hashSeed = sun.misc.Hashing.randomHashSeed(this);
- seedSet = true;
- }
- }
- }
h = hashSeed;
if (k instanceof String) {
return sun.misc.Hashing.stringHash32((String) k);
@@ -572,6 +570,9 @@
useAltHashing |= sun.misc.VM.isBooted() &&
(newCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
boolean rehash = oldAltHashing ^ useAltHashing;
+ if (rehash) {
+ hashSeed = sun.misc.Hashing.randomHashSeed(this);
+ }
transfer(oldTable, newTable, rehash);
table = newTable;
diff --git a/ojluni/src/main/java/java/util/zip/ZipEntry.java b/ojluni/src/main/java/java/util/zip/ZipEntry.java
index c67a0af..af1573e 100755
--- a/ojluni/src/main/java/java/util/zip/ZipEntry.java
+++ b/ojluni/src/main/java/java/util/zip/ZipEntry.java
@@ -59,7 +59,7 @@
public static final int DEFLATED = 8;
- /** @hide - for testing only */
+ /** @hide - Called from StrictJarFile native code. */
public ZipEntry(String name, String comment, long crc, long compressedSize,
long size, int compressionMethod, int time, byte[] extra,
long dataOffset) {
diff --git a/ojluni/src/main/java/sun/nio/ch/FileDescriptorHolderSocketImpl.java b/ojluni/src/main/java/sun/nio/ch/FileDescriptorHolderSocketImpl.java
new file mode 100644
index 0000000..d7a9fc6
--- /dev/null
+++ b/ojluni/src/main/java/sun/nio/ch/FileDescriptorHolderSocketImpl.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * 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. The Android Open Source
+ * Project designates this particular file as subject to the "Classpath"
+ * exception as provided by The Android Open Source Project 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.
+ */
+
+package sun.nio.ch;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.SocketImpl;
+
+/**
+ * This class is only used for {@link SocketAdaptor} to be backward-compatible
+ * with older Android versions which always set the {@code impl} field of
+ * {@link Socket}. As such none of the methods in this class are implemented
+ * since {@link SocketAdaptor} should override everything in {@link Socket}
+ * which may access the {@code impl} field.
+ */
+class FileDescriptorHolderSocketImpl extends SocketImpl {
+ public FileDescriptorHolderSocketImpl(FileDescriptor fd) {
+ this.fd = fd;
+ }
+
+ @Override
+ public void setOption(int optID, Object value) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object getOption(int optID) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void create(boolean stream) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void connect(String host, int port) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void connect(InetAddress address, int port) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void connect(SocketAddress address, int timeout) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void bind(InetAddress host, int port) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void listen(int backlog) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void accept(SocketImpl s) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected InputStream getInputStream() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected OutputStream getOutputStream() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected int available() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void close() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void sendUrgentData(int data) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/ojluni/src/main/java/sun/nio/ch/SocketAdaptor.java b/ojluni/src/main/java/sun/nio/ch/SocketAdaptor.java
index d2ebde5..4240aea 100755
--- a/ojluni/src/main/java/sun/nio/ch/SocketAdaptor.java
+++ b/ojluni/src/main/java/sun/nio/ch/SocketAdaptor.java
@@ -61,7 +61,7 @@
private volatile int timeout = 0;
private SocketAdaptor(SocketChannelImpl sc) throws SocketException {
- super((SocketImpl) null);
+ super(new FileDescriptorHolderSocketImpl(sc.getFD()));
this.sc = sc;
}
diff --git a/ojluni/src/main/java/sun/security/provider/CertPathProvider.java b/ojluni/src/main/java/sun/security/provider/CertPathProvider.java
index a36bcd9..f48bd1e 100644
--- a/ojluni/src/main/java/sun/security/provider/CertPathProvider.java
+++ b/ojluni/src/main/java/sun/security/provider/CertPathProvider.java
@@ -43,7 +43,7 @@
put("CertPathBuilder.PKIX ValidationAlgorithm", "RFC3280");
// CertPathValidator
- put("CertPathValidator.PKIX", "sun.security.provider.certPath.PKIXCertPathValidator");
+ put("CertPathValidator.PKIX", "sun.security.provider.certpath.PKIXCertPathValidator");
put("CertPathValidator.PKIX ImplementedIn", "Software");
put("CertPathValidator.PKIX ValidationAlgorithm", "RFC3280");
}
diff --git a/ojluni/src/main/java/sun/util/PreHashedMap.java b/ojluni/src/main/java/sun/util/PreHashedMap.java
deleted file mode 100755
index f9cde50e..0000000
--- a/ojluni/src/main/java/sun/util/PreHashedMap.java
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2004, 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.
- */
-
-package sun.util;
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.AbstractMap;
-import java.util.AbstractSet;
-import java.util.NoSuchElementException;
-
-
-/**
- * A precomputed hash map.
- *
- * <p> Subclasses of this class are of the following form:
- *
- * <blockquote><pre>
- * class FooMap
- * extends sun.util.PreHashedMap<String>
- * {
- *
- * private FooMap() {
- * super(ROWS, SIZE, SHIFT, MASK);
- * }
- *
- * protected void init(Object[] ht) {
- * ht[0] = new Object[] { "key-1", value_1 };
- * ht[1] = new Object[] { "key-2", value_2,
- * new Object { "key-3", value_3 } };
- * ...
- * }
- *
- * }</pre></blockquote>
- *
- * <p> The <tt>init</tt> method is invoked by the <tt>PreHashedMap</tt>
- * constructor with an object array long enough for the map's rows. The method
- * must construct the hash chain for each row and store it in the appropriate
- * element of the array.
- *
- * <p> Each entry in the map is represented by a unique hash-chain node. The
- * final node of a hash chain is a two-element object array whose first element
- * is the entry's key and whose second element is the entry's value. A
- * non-final node of a hash chain is a three-element object array whose first
- * two elements are the entry's key and value and whose third element is the
- * next node in the chain.
- *
- * <p> Instances of this class are mutable and are not safe for concurrent
- * access. They may be made immutable and thread-safe via the appropriate
- * methods in the {@link java.util.Collections} utility class.
- *
- * <p> In the JDK build, subclasses of this class are typically created via the
- * <tt>Hasher</tt> program in the <tt>make/tools/Hasher</tt> directory.
- *
- * @author Mark Reinhold
- * @since 1.5
- *
- * @see java.util.AbstractMap
- */
-
-public abstract class PreHashedMap<V>
- extends AbstractMap<String,V>
-{
-
- private final int rows;
- private final int size;
- private final int shift;
- private final int mask;
- private final Object[] ht;
-
- /**
- * Creates a new map.
- *
- * <p> This constructor invokes the {@link #init init} method, passing it a
- * newly-constructed row array that is <tt>rows</tt> elements long.
- *
- * @param rows
- * The number of rows in the map
- * @param size
- * The number of entries in the map
- * @param shift
- * The value by which hash codes are right-shifted
- * @param mask
- * The value with which hash codes are masked after being shifted
- */
- protected PreHashedMap(int rows, int size, int shift, int mask) {
- this.rows = rows;
- this.size = size;
- this.shift = shift;
- this.mask = mask;
- this.ht = new Object[rows];
- init(ht);
- }
-
- /**
- * Initializes this map.
- *
- * <p> This method must construct the map's hash chains and store them into
- * the appropriate elements of the given hash-table row array.
- *
- * @param rows
- * The row array to be initialized
- */
- protected abstract void init(Object[] ht);
-
- @SuppressWarnings("unchecked")
- private V toV(Object x) {
- return (V)x;
- }
-
- // Android-added: Add a method to hash Strings.
- //
- // TODO: Why does this say hash(Object) instead of hash(String).
- private static final int hash(Object o) {
- String s = (String) o;
- char[] val = s.toCharArray();
- int h = 0;
- if (val.length > 0) {
- for (int i = 0; i < val.length; i++) {
- h = 31 * h + val[i];
- }
- }
- return h;
- }
-
- public V get(Object k) {
- // Android-changed: Use hash(k) instead of k.hashCode().
- int h = (hash(k) >> shift) & mask;
- Object[] a = (Object[])ht[h];
- if (a == null) return null;
- for (;;) {
- if (a[0].equals(k))
- return toV(a[1]);
- if (a.length < 3)
- return null;
- a = (Object[])a[2];
- }
- }
-
- /**
- * @throws UnsupportedOperationException
- * If the given key is not part of this map's initial key set
- */
- public V put(String k, V v) {
- // Android-changed: Use hash(k) instead of k.hashCode().
- int h = (hash(k) >> shift) & mask;
- Object[] a = (Object[])ht[h];
- if (a == null)
- throw new UnsupportedOperationException(k);
- for (;;) {
- if (a[0].equals(k)) {
- V ov = toV(a[1]);
- a[1] = v;
- return ov;
- }
- if (a.length < 3)
- throw new UnsupportedOperationException(k);
- a = (Object[])a[2];
- }
- }
-
- public Set<String> keySet() {
- return new AbstractSet<String> () {
-
- public int size() {
- return size;
- }
-
- public Iterator<String> iterator() {
- return new Iterator<String>() {
- private int i = -1;
- Object[] a = null;
- String cur = null;
-
- private boolean findNext() {
- if (a != null) {
- if (a.length == 3) {
- a = (Object[])a[2];
- cur = (String)a[0];
- return true;
- }
- i++;
- a = null;
- }
- cur = null;
- if (i >= rows)
- return false;
- if (i < 0 || ht[i] == null) {
- do {
- if (++i >= rows)
- return false;
- } while (ht[i] == null);
- }
- a = (Object[])ht[i];
- cur = (String)a[0];
- return true;
- }
-
- public boolean hasNext() {
- if (cur != null)
- return true;
- return findNext();
- }
-
- public String next() {
- if (cur == null) {
- if (!findNext())
- throw new NoSuchElementException();
- }
- String s = cur;
- cur = null;
- return s;
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- };
- }
- };
- }
-
- public Set<Map.Entry<String,V>> entrySet() {
- return new AbstractSet<Map.Entry<String,V>> () {
-
- public int size() {
- return size;
- }
-
- public Iterator<Map.Entry<String,V>> iterator() {
- return new Iterator<Map.Entry<String,V>>() {
- final Iterator<String> i = keySet().iterator();
-
- public boolean hasNext() {
- return i.hasNext();
- }
-
- public Map.Entry<String,V> next() {
- return new Map.Entry<String,V>() {
- String k = i.next();
- public String getKey() { return k; }
- public V getValue() { return get(k); }
- public int hashCode() {
- V v = get(k);
- return (k.hashCode()
- + (v == null
- ? 0
- : v.hashCode()));
- }
- @SuppressWarnings("unchecked")
- public boolean equals(Object ob) {
- if (ob == this)
- return true;
- if (!(ob instanceof Map.Entry))
- return false;
- Map.Entry<String,V> that
- = (Map.Entry<String,V>)ob;
- return ((this.getKey() == null
- ? that.getKey() == null
- : this.getKey()
- .equals(that.getKey()))
- &&
- (this.getValue() == null
- ? that.getValue() == null
- : this.getValue()
- .equals(that.getValue())));
- }
- public V setValue(V v) {
- throw new UnsupportedOperationException();
- }
- };
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- };
- }
- };
- }
-
-}
diff --git a/ojluni/src/main/native/io_util_md.c b/ojluni/src/main/native/io_util_md.c
index 1df4b9d..4b1de48 100755
--- a/ojluni/src/main/native/io_util_md.c
+++ b/ojluni/src/main/native/io_util_md.c
@@ -83,6 +83,7 @@
fstat(fd, &stat);
if (S_ISDIR(stat.st_mode)) {
+ close(fd);
errno = EISDIR; // For Exception message
throwFileNotFoundException(env, path);
return;
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index f6e3966..29f53aa 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -1124,6 +1124,7 @@
ojluni/src/main/java/sun/nio/ch/EPollSelectorProvider.java \
ojluni/src/main/java/sun/nio/ch/ExtendedSocketOption.java \
ojluni/src/main/java/sun/nio/ch/FileChannelImpl.java \
+ ojluni/src/main/java/sun/nio/ch/FileDescriptorHolderSocketImpl.java \
ojluni/src/main/java/sun/nio/ch/FileDispatcherImpl.java \
ojluni/src/main/java/sun/nio/ch/FileDispatcher.java \
ojluni/src/main/java/sun/nio/ch/FileKey.java \
@@ -1441,7 +1442,6 @@
ojluni/src/main/java/sun/util/logging/LoggingProxy.java \
ojluni/src/main/java/sun/util/logging/LoggingSupport.java \
ojluni/src/main/java/sun/util/logging/PlatformLogger.java \
- ojluni/src/main/java/sun/util/PreHashedMap.java \
ojluni/src/main/java/sun/util/ResourceBundleEnumeration.java \
ojluni/src/main/java/sun/util/resources/OpenListResourceBundle.java \
$(openjdk_javadoc_files)
diff --git a/support/src/test/java/libcore/java/security/StandardNames.java b/support/src/test/java/libcore/java/security/StandardNames.java
index f7b8337..9eb9e6c 100644
--- a/support/src/test/java/libcore/java/security/StandardNames.java
+++ b/support/src/test/java/libcore/java/security/StandardNames.java
@@ -758,6 +758,8 @@
addBoth( "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384");
addOpenSsl("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256");
addOpenSsl("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384");
+ addOpenSsl("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256");
+ addOpenSsl("TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256");
// Pre-Shared Key (PSK) cipher suites
addOpenSsl("TLS_PSK_WITH_RC4_128_SHA");
@@ -765,6 +767,7 @@
addOpenSsl("TLS_PSK_WITH_AES_256_CBC_SHA");
addOpenSsl("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA");
addOpenSsl("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA");
+ addOpenSsl("TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256");
// RFC 5746's Signaling Cipher Suite Value to indicate a request for secure renegotiation
addBoth(CIPHER_SUITE_SECURE_RENEGOTIATION);
@@ -924,8 +927,10 @@
"SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
"SSL_RSA_WITH_RC4_128_MD5",
"TLS_EMPTY_RENEGOTIATION_INFO_SCSV")
- : Arrays.asList("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+ : Arrays.asList("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
@@ -948,6 +953,7 @@
// NOTE: This list needs to be kept in sync with Javadoc of javax.net.ssl.SSLSocket and
// javax.net.ssl.SSLEngine.
public static final List<String> CIPHER_SUITES_DEFAULT_PSK = Arrays.asList(
+ "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA",
"TLS_PSK_WITH_AES_128_CBC_SHA",
@@ -966,7 +972,8 @@
"AES_128_CBC",
"AES_256_CBC",
"AES_128_GCM",
- "AES_256_GCM"));
+ "AES_256_GCM",
+ "CHACHA20_POLY1305"));
private static final Set<String> PERMITTED_DEFAULT_MACS =
new HashSet<String>(Arrays.asList("SHA",
diff --git a/support/src/test/java/libcore/javax/net/ssl/TestSSLContext.java b/support/src/test/java/libcore/javax/net/ssl/TestSSLContext.java
index 8173e9d..1daa2a1 100644
--- a/support/src/test/java/libcore/javax/net/ssl/TestSSLContext.java
+++ b/support/src/test/java/libcore/javax/net/ssl/TestSSLContext.java
@@ -33,6 +33,7 @@
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.X509TrustManager;
import junit.framework.Assert;
import libcore.java.security.StandardNames;
@@ -83,8 +84,8 @@
public final char[] serverStorePassword;
public final KeyManager[] clientKeyManagers;
public final KeyManager[] serverKeyManagers;
- public final X509TrustManager clientTrustManager;
- public final X509TrustManager serverTrustManager;
+ public final X509ExtendedTrustManager clientTrustManager;
+ public final X509ExtendedTrustManager serverTrustManager;
public final SSLContext clientContext;
public final SSLContext serverContext;
public final SSLServerSocket serverSocket;
@@ -97,8 +98,8 @@
char[] serverStorePassword,
KeyManager[] clientKeyManagers,
KeyManager[] serverKeyManagers,
- X509TrustManager clientTrustManager,
- X509TrustManager serverTrustManager,
+ X509ExtendedTrustManager clientTrustManager,
+ X509ExtendedTrustManager serverTrustManager,
SSLContext clientContext,
SSLContext serverContext,
SSLServerSocket serverSocket,
@@ -189,8 +190,8 @@
serverKeyStore, serverStorePassword,
clientKeyManagers,
serverKeyManagers,
- (X509TrustManager) clientTrustManagers,
- (X509TrustManager) serverTrustManagers,
+ (X509ExtendedTrustManager) clientTrustManagers,
+ (X509ExtendedTrustManager) serverTrustManagers,
clientContext, serverContext,
serverSocket, host, port);
} catch (RuntimeException e) {
diff --git a/support/src/test/java/libcore/javax/net/ssl/TestTrustManager.java b/support/src/test/java/libcore/javax/net/ssl/TestTrustManager.java
index dc4bb28..b703984 100644
--- a/support/src/test/java/libcore/javax/net/ssl/TestTrustManager.java
+++ b/support/src/test/java/libcore/javax/net/ssl/TestTrustManager.java
@@ -20,6 +20,7 @@
import java.net.Socket;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
@@ -28,15 +29,16 @@
/**
* TestTrustManager is a simple proxy class that wraps an existing
- * X509TrustManager to provide debug logging and recording of
+ * X509ExtendedTrustManager to provide debug logging and recording of
* values.
*/
-public final class TestTrustManager implements X509TrustManager {
+public final class TestTrustManager extends X509ExtendedTrustManager {
private static final boolean LOG = false;
private static final PrintStream out = LOG ? System.out : new NullPrintStream();
private final X509TrustManager trustManager;
+ private final X509ExtendedTrustManager extendedTrustManager;
public static TrustManager[] wrap(TrustManager[] trustManagers) {
TrustManager[] result = trustManagers.clone();
@@ -47,14 +49,23 @@
}
public static TrustManager wrap(TrustManager trustManager) {
- if (trustManager instanceof X509TrustManager) {
+ if (trustManager instanceof X509ExtendedTrustManager) {
+ return new TestTrustManager((X509ExtendedTrustManager) trustManager);
+ } else if (trustManager instanceof X509TrustManager) {
return new TestTrustManager((X509TrustManager) trustManager);
}
return trustManager;
}
+ public TestTrustManager(X509ExtendedTrustManager trustManager) {
+ out.println("TestTrustManager.<init> extendedTrustManager=" + trustManager);
+ this.extendedTrustManager = trustManager;
+ this.trustManager = trustManager;
+ }
+
public TestTrustManager(X509TrustManager trustManager) {
out.println("TestTrustManager.<init> trustManager=" + trustManager);
+ this.extendedTrustManager = null;
this.trustManager = trustManager;
}
@@ -73,6 +84,50 @@
}
}
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket)
+ throws CertificateException {
+ if (extendedTrustManager == null) {
+ out.print("(fallback to X509TrustManager) ");
+ checkClientTrusted(chain, authType);
+ return;
+ }
+ out.print("TestTrustManager.checkClientTrusted "
+ + "chain=" + chain.length + " "
+ + "authType=" + authType + " "
+ + "socket=" + socket + " ");
+ try {
+ assertClientAuthType(authType);
+ extendedTrustManager.checkClientTrusted(chain, authType, socket);
+ out.println("OK");
+ } catch (CertificateException e) {
+ e.printStackTrace(out);
+ throw e;
+ }
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
+ throws CertificateException {
+ if (extendedTrustManager == null) {
+ out.print("(fallback to X509TrustManager) ");
+ checkClientTrusted(chain, authType);
+ return;
+ }
+ out.print("TestTrustManager.checkClientTrusted "
+ + "chain=" + chain.length + " "
+ + "authType=" + authType + " "
+ + "engine=" + engine + " ");
+ try {
+ assertClientAuthType(authType);
+ extendedTrustManager.checkClientTrusted(chain, authType, engine);
+ out.println("OK");
+ } catch (CertificateException e) {
+ e.printStackTrace(out);
+ throw e;
+ }
+ }
+
private void assertClientAuthType(String authType) {
if (!StandardNames.CLIENT_AUTH_TYPES.contains(authType)) {
throw new AssertionError("Unexpected client auth type " + authType);
@@ -94,6 +149,50 @@
}
}
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket)
+ throws CertificateException {
+ if (extendedTrustManager == null) {
+ out.print("(fallback to X509TrustManager) ");
+ checkServerTrusted(chain, authType);
+ return;
+ }
+ out.print("TestTrustManager.checkServerTrusted "
+ + "chain=" + chain.length + " "
+ + "authType=" + authType + " "
+ + "socket=" + socket.toString() + " ");
+ try {
+ assertServerAuthType(authType);
+ extendedTrustManager.checkServerTrusted(chain, authType, socket);
+ out.println("OK");
+ } catch (CertificateException e) {
+ e.printStackTrace(out);
+ throw e;
+ }
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
+ throws CertificateException {
+ if (extendedTrustManager == null) {
+ out.print("(fallback to X509TrustManager) ");
+ checkServerTrusted(chain, authType);
+ return;
+ }
+ out.print("TestTrustManager.checkServerTrusted "
+ + "chain=" + chain.length + " "
+ + "authType=" + authType + " "
+ + "engine=" + engine.toString() + " ");
+ try {
+ assertServerAuthType(authType);
+ extendedTrustManager.checkServerTrusted(chain, authType, engine);
+ out.println("OK");
+ } catch (CertificateException e) {
+ e.printStackTrace(out);
+ throw e;
+ }
+ }
+
private void assertServerAuthType(String authType) {
if (!StandardNames.SERVER_AUTH_TYPES.contains(authType)) {
throw new AssertionError("Unexpected server auth type " + authType);