Merge change 24897 into eclair

* changes:
  First cut at a tool to perform automated syncs from Harmony to Dalvik.
diff --git a/dx/etc/dx.bat b/dx/etc/dx.bat
index 2686d6a..1361bb6 100755
--- a/dx/etc/dx.bat
+++ b/dx/etc/dx.bat
@@ -40,12 +40,47 @@
 set jarpath=%frameworkdir%%jarfile%
 
 set javaOpts=
+set args=
 
-REM If you want DX to have more memory when executing, uncomment the
-REM following line and adjust the value accordingly. Use "java -X" for
-REM a list of options you can pass here.
-REM 
-REM set javaOpts=-Xmx256M
+REM By default, give dx a max heap size of 1 gig. This can be overridden
+REM by using a "-JXmx..." option (see below).
+set defaultMx=-Xmx1024M
 
-call java %javaOpts% -Djava.ext.dirs=%frameworkdir% -jar %jarpath% %*
+REM capture all arguments to process them below
+set params=%*
+
+:nextArg
+if "%params%"=="" goto endArgs
+    REM Note: advanced substitions don't work on %1..%N. We need to assign to
+    REM a variable first.
+    REM We also can't use %1..%N directly because an option such as --output=name
+    REM gets automagically converted into %1=--output and %2=name (yes, really!)
+    REM Instead we manually extract the first token from the params variable.
+    for /F "tokens=1*" %%a in ("%params%") do call :getArg "%%a" "%%b"
+
+    if "%defaultMx%"=="" goto notXmx
+    if "%A:~0,5%" NEQ "-JXmx" goto notXmx
+        set defaultMx=
+    :notXmx
+
+    if "%A:~0,2%" NEQ "-J" goto notJ
+        set javaOpts=%javaOpts% -%A:~2%
+        goto nextArg
+
+    :notJ
+        set args=%args% %A%
+        goto nextArg
+
+:getArg
+    REM this subroutine is called by the for /F with the first argument of params
+    REM and the rest of the line. The "goto :eof" actually exits the subroutine.
+    set A=%~1
+    set params=%~2
+    goto :eof
+
+:endArgs
+
+set javaOpts=%javaOpts% %defaultMx%
+
+call java %javaOpts% -Djava.ext.dirs=%frameworkdir% -jar %jarpath% %args%
 
diff --git a/libcore/archive/src/main/java/java/util/jar/JarFile.java b/libcore/archive/src/main/java/java/util/jar/JarFile.java
index d6e8339..6f4eb83 100644
--- a/libcore/archive/src/main/java/java/util/jar/JarFile.java
+++ b/libcore/archive/src/main/java/java/util/jar/JarFile.java
@@ -68,6 +68,10 @@
 
         private JarVerifier.VerifierEntry entry;
 
+        // BEGIN android-added
+        private boolean done = false;
+        // END android-added
+
         JarFileInputStream(InputStream is, ZipEntry ze,
                 JarVerifier.VerifierEntry e) {
             super(is);
@@ -78,6 +82,10 @@
 
         @Override
         public int read() throws IOException {
+            // BEGIN android-changed
+            if (done) {
+                return -1;
+            }
             if (count > 0) {
                 int r = super.read();
                 if (r != -1) {
@@ -87,16 +95,24 @@
                     count = 0;
                 }
                 if (count == 0) {
+                    done = true;
                     entry.verify();
                 }
                 return r;
             } else {
+                done = true;
+                entry.verify();
                 return -1;
             }
+            // END android-changed
         }
 
         @Override
         public int read(byte[] buf, int off, int nbytes) throws IOException {
+            // BEGIN android-changed
+            if (done) {
+                return -1;
+            }
             if (count > 0) {
                 int r = super.read(buf, off, nbytes);
                 if (r != -1) {
@@ -110,22 +126,25 @@
                     count = 0;
                 }
                 if (count == 0) {
+                    done = true;
                     entry.verify();
                 }
                 return r;
             } else {
+                done = true;
+                entry.verify();
                 return -1;
             }
+            // END android-changed
         }
 
         // BEGIN android-added
         @Override
         public int available() throws IOException {
-            if (count > 0) {
-                return super.available();
-            } else {
+            if (done) {
                 return 0;
             }
+            return super.available();
         }
         // END android-added
 
diff --git a/libcore/archive/src/main/java/java/util/jar/Pack200.java b/libcore/archive/src/main/java/java/util/jar/Pack200.java
index 8145fa1..3e7081d 100644
--- a/libcore/archive/src/main/java/java/util/jar/Pack200.java
+++ b/libcore/archive/src/main/java/java/util/jar/Pack200.java
@@ -57,7 +57,7 @@
                     public Object run() {
                         String className = System
                                 .getProperty(SYSTEM_PROPERTY_PACKER,
-                                        "org.apache.harmony.archive.internal.pack200.Pack200PackerAdapter"); //$NON-NLS-1$
+                                        "org.apache.harmony.pack200.Pack200PackerAdapter"); //$NON-NLS-1$
                         try {
                             // TODO Not sure if this will cause problems with
                             // loading the packer
@@ -87,7 +87,7 @@
                     public Object run() {
                         String className = System
                                 .getProperty(SYSTEM_PROPERTY_UNPACKER,
-                                        "org.apache.harmony.archive.internal.pack200.Pack200UnpackerAdapter");//$NON-NLS-1$
+                                        "org.apache.harmony.unpack200.Pack200UnpackerAdapter");//$NON-NLS-1$
                         try {
                             return ClassLoader.getSystemClassLoader()
                                     .loadClass(className).newInstance();
diff --git a/libcore/archive/src/main/java/java/util/zip/GZIPInputStream.java b/libcore/archive/src/main/java/java/util/zip/GZIPInputStream.java
index bb84f5b..cc7a019 100644
--- a/libcore/archive/src/main/java/java/util/zip/GZIPInputStream.java
+++ b/libcore/archive/src/main/java/java/util/zip/GZIPInputStream.java
@@ -161,39 +161,55 @@
         if (closed) {
             throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$
         }
-        if (eof) {
+        // BEGIN android-changed
+        if (eos) {
             return -1;
         }
         // avoid int overflow, check null buffer
-        if (off <= buffer.length && nbytes >= 0 && off >= 0
-                && buffer.length - off >= nbytes) {
-            int val = super.read(buffer, off, nbytes);
-            if (val != -1) {
-                crc.update(buffer, off, val);
-            } else if (!eos) {
-                eos = true;
-                // Get non-compressed bytes read by fill
-                int size = inf.getRemaining();
-                final int trailerSize = 8; // crc (4 bytes) + total out (4
-                // bytes)
-                byte[] b = new byte[trailerSize];
-                int copySize = (size > trailerSize) ? trailerSize : size;
-
-                System.arraycopy(buf, len - size, b, 0, copySize);
-                readFully(b, copySize, trailerSize - copySize);
-
-                if (getLong(b, 0) != crc.getValue()) {
-                    throw new IOException(Messages.getString("archive.20")); //$NON-NLS-1$
-                }
-                if ((int) getLong(b, 4) != inf.getTotalOut()) {
-                    throw new IOException(Messages.getString("archive.21")); //$NON-NLS-1$
-                }
-            }
-            return val;
+        if (off > buffer.length || nbytes < 0 || off < 0
+                || buffer.length - off < nbytes) {
+            throw new ArrayIndexOutOfBoundsException();
         }
-        throw new ArrayIndexOutOfBoundsException();
+
+        int bytesRead;
+        try {
+            bytesRead = super.read(buffer, off, nbytes);
+        } finally {
+            eos = eof; // update eos after every read(), even when it throws
+        }
+
+        if (bytesRead != -1) {
+            crc.update(buffer, off, bytesRead);
+        }
+
+        if (eos) {
+            verifyCrc();
+        }
+
+        return bytesRead;
+        // END android-changed
     }
 
+    // BEGIN android-added
+    private void verifyCrc() throws IOException {
+        // Get non-compressed bytes read by fill
+        int size = inf.getRemaining();
+        final int trailerSize = 8; // crc (4 bytes) + total out (4 bytes)
+        byte[] b = new byte[trailerSize];
+        int copySize = (size > trailerSize) ? trailerSize : size;
+
+        System.arraycopy(buf, len - size, b, 0, copySize);
+        readFully(b, copySize, trailerSize - copySize);
+
+        if (getLong(b, 0) != crc.getValue()) {
+            throw new IOException(Messages.getString("archive.20")); //$NON-NLS-1$
+        }
+        if ((int) getLong(b, 4) != inf.getTotalOut()) {
+            throw new IOException(Messages.getString("archive.21")); //$NON-NLS-1$
+        }
+    }
+    // END android-added
+
     private void readFully(byte[] buffer, int offset, int length)
             throws IOException {
         int result;
diff --git a/libcore/archive/src/main/java/java/util/zip/Inflater.java b/libcore/archive/src/main/java/java/util/zip/Inflater.java
index cb1ce68..048d959 100644
--- a/libcore/archive/src/main/java/java/util/zip/Inflater.java
+++ b/libcore/archive/src/main/java/java/util/zip/Inflater.java
@@ -51,7 +51,9 @@
 
     private boolean finished; // Set by the inflateImpl native
 
-    private boolean gotFirstByte = false;
+    // BEGIN android-removed
+    // private boolean gotFirstHeaderByte;
+    // END android-removed
 
     int inLength;
 
@@ -59,7 +61,9 @@
 
     private boolean needsDictionary; // Set by the inflateImpl native
 
-    private boolean pass_magic_number_check = true;
+    // BEGIN android-removed
+    // private boolean pass_magic_number_check = true;
+    // END android-removed
 
     private long streamHandle = -1;
 
@@ -82,6 +86,9 @@
      */
     public Inflater(boolean noHeader) {
         streamHandle = createStream(noHeader);
+        // BEGIN android-removed
+        // gotFirstHeaderByte = noHeader;
+        // END android-removed
     }
 
     private native long createStream(boolean noHeader1);
@@ -250,9 +257,11 @@
                 throw new IllegalStateException();
             }
 
-            if (!pass_magic_number_check) {
-                throw new DataFormatException();
-            }
+            // BEGIN android-removed
+            // if (!pass_magic_number_check) {
+            //     throw new DataFormatException();
+            // }
+            // END android-removed
 
             if (needsInput()) {
                 return 0;
@@ -398,21 +407,13 @@
         } else {
             throw new ArrayIndexOutOfBoundsException();
         }
-        // BEGIN android-note
-        // Note:  pass_magic_number_check is set to false when setInput is
-        //        called for the first time and for a single byte.
-        //        Since setInput is called only by InflaterInputStream.fill
-        //        with an arbitrary byte len this check seems quite useless.
-        // FIXME: We should find out whether the first byte has to be the magic
-        //        number in all cases and correct the check as well as place it
-        //        in setFileInput accordingly.
-        //        And at a first glance it doesn't look like the first byte has
-        //        to be 120.
-        // END android-note
-        if (!gotFirstByte && nbytes > 0) {
-            pass_magic_number_check = (buf[off] == MAGIC_NUMBER || nbytes > 1);
-            gotFirstByte = true;
-        }
+
+        // BEGIN android-removed
+        // if (!gotFirstHeaderByte && nbytes > 0) {
+        //     pass_magic_number_check = (buf[off] == MAGIC_NUMBER);
+        //     gotFirstHeaderByte = true;
+        //}
+        // END android-removed
     }
 
     // BEGIN android-added
diff --git a/libcore/archive/src/main/java/java/util/zip/InflaterInputStream.java b/libcore/archive/src/main/java/java/util/zip/InflaterInputStream.java
index 1fd3602..8a7c86b 100644
--- a/libcore/archive/src/main/java/java/util/zip/InflaterInputStream.java
+++ b/libcore/archive/src/main/java/java/util/zip/InflaterInputStream.java
@@ -53,6 +53,11 @@
 
     boolean closed;
 
+    /**
+     * True if this stream's last byte has been returned to the user. This
+     * could be because the underlying stream has been exhausted, or if errors
+     * were encountered while inflating that stream.
+     */
     boolean eof;
 
     static final int BUF_SIZE = 512;
@@ -165,41 +170,47 @@
             return 0;
         }
 
-        if (inf.finished()) {
-            eof = true;
+        // BEGIN android-changed
+        if (eof) {
             return -1;
         }
 
         // avoid int overflow, check null buffer
-        if (off <= buffer.length && nbytes >= 0 && off >= 0
-                && buffer.length - off >= nbytes) {
-            do {
-                if (inf.needsInput()) {
-                    fill();
-                }
-                int result;
-                try {
-                    result = inf.inflate(buffer, off, nbytes);
-                } catch (DataFormatException e) {
-                    if (len == -1) {
-                        throw new EOFException();
-                    }
-                    throw (IOException) (new IOException().initCause(e));
-                }
+        if (off > buffer.length || nbytes < 0 || off < 0
+                || buffer.length - off < nbytes) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+
+        do {
+            if (inf.needsInput()) {
+                fill();
+            }
+            // Invariant: if reading returns -1 or throws, eof must be true.
+            // It may also be true if the next read() should return -1.
+            try {
+                int result = inf.inflate(buffer, off, nbytes);
+                eof = inf.finished();
                 if (result > 0) {
                     return result;
-                } else if (inf.finished()) {
-                    eof = true;
+                } else if (eof) {
                     return -1;
                 } else if (inf.needsDictionary()) {
+                    eof = true;
                     return -1;
                 } else if (len == -1) {
+                    eof = true;
                     throw new EOFException();
                     // If result == 0, fill() and try again
                 }
-            } while (true);
-        }
-        throw new ArrayIndexOutOfBoundsException();
+            } catch (DataFormatException e) {
+                eof = true;
+                if (len == -1) {
+                    throw new EOFException();
+                }
+                throw (IOException) (new IOException().initCause(e));
+            }
+        } while (true);
+        // END android-changed
     }
 
     /**
@@ -252,7 +263,9 @@
                         (rem = nbytes - count) > buf.length ? buf.length
                                 : (int) rem);
                 if (x == -1) {
-                    eof = true;
+                    // BEGIN android-removed
+                    // eof = true;
+                    // END android-removed
                     return count;
                 }
                 count += x;
@@ -263,9 +276,18 @@
     }
 
     /**
-     * Returns whether data can be read from this stream.
+     * Returns 0 when when this stream has exhausted its input; and 1 otherwise.
+     * A result of 1 does not guarantee that further bytes can be returned,
+     * with or without blocking.
      *
-     * @return 0 if this stream has been closed, 1 otherwise.
+     * <p>Although consistent with the RI, this behavior is inconsistent with
+     * {@link InputStream#available()}, and violates the <a
+     * href="http://en.wikipedia.org/wiki/Liskov_substitution_principle">Liskov
+     * Substitution Principle</a>. This method should not be used.
+     *
+     * @return 0 if no further bytes are available. Otherwise returns 1,
+     *         which suggests (but does not guarantee) that additional bytes are
+     *         available.
      * @throws IOException
      *             If an error occurs.
      */
diff --git a/libcore/archive/src/main/java/java/util/zip/ZipInputStream.java b/libcore/archive/src/main/java/java/util/zip/ZipInputStream.java
index 1a35b1c..f86cbe0 100644
--- a/libcore/archive/src/main/java/java/util/zip/ZipInputStream.java
+++ b/libcore/archive/src/main/java/java/util/zip/ZipInputStream.java
@@ -125,8 +125,24 @@
                 return;
             }
         }
+
+        /*
+         * The following code is careful to leave the ZipInputStream in a
+         * consistent state, even when close() results in an exception. It does
+         * so by:
+         *  - pushing bytes back into the source stream
+         *  - reading a data descriptor footer from the source stream
+         *  - resetting fields that manage the entry being closed
+         */
+
         // Ensure all entry bytes are read
-        skip(Long.MAX_VALUE);
+        Exception failure = null;
+        try {
+            skip(Long.MAX_VALUE);
+        } catch (Exception e) {
+            failure = e;
+        }
+
         int inB, out;
         if (currentEntry.compressionMethod == DEFLATED) {
             inB = inf.getTotalIn();
@@ -135,12 +151,38 @@
             inB = inRead;
             out = inRead;
         }
-        int diff = 0;
+        int diff = entryIn - inB;
         // Pushback any required bytes
-        if ((diff = entryIn - inB) != 0) {
+        if (diff != 0) {
             ((PushbackInputStream) in).unread(buf, len - diff, diff);
         }
 
+        try {
+            readAndVerifyDataDescriptor(inB, out);
+        } catch (Exception e) {
+            if (failure == null) { // otherwise we're already going to throw
+                failure = e;
+            }
+        }
+
+        inf.reset();
+        lastRead = inRead = entryIn = len = 0;
+        crc.reset();
+        currentEntry = null;
+
+        if (failure != null) {
+            if (failure instanceof IOException) {
+                throw (IOException) failure;
+            } else if (failure instanceof RuntimeException) {
+                throw (RuntimeException) failure;
+            }
+            AssertionError error = new AssertionError();
+            error.initCause(failure);
+            throw error;
+        }
+    }
+
+    private void readAndVerifyDataDescriptor(int inB, int out) throws IOException {
         if (hasDD) {
             in.read(hdrBuf, 0, EXTHDR);
             if (getLong(hdrBuf, 0) != EXTSIG) {
@@ -156,26 +198,19 @@
         if (currentEntry.compressedSize != inB || currentEntry.size != out) {
             throw new ZipException(Messages.getString("archive.21")); //$NON-NLS-1$
         }
-
-        inf.reset();
-        lastRead = inRead = entryIn = len = 0;
-        crc.reset();
-        currentEntry = null;
     }
 
     /**
-     * Reads the next entry from this {@code ZipInputStream}.
+     * Reads the next entry from this {@code ZipInputStream} or {@code null} if
+     * no more entries are present.
      *
      * @return the next {@code ZipEntry} contained in the input stream.
      * @throws IOException
-     *             if the stream is not positioned at the beginning of an entry
-     *             or if an other {@code IOException} occurs.
+     *             if an {@code IOException} occurs.
      * @see ZipEntry
      */
     public ZipEntry getNextEntry() throws IOException {
-        if (currentEntry != null) {
-            closeEntry();
-        }
+        closeEntry();
         if (entriesEnd) {
             return null;
         }
@@ -257,9 +292,6 @@
             }
             currentEntry.setExtra(e);
         }
-        // BEGIN android-added
-        eof = false;
-        // END android-added
         return currentEntry;
     }
 
@@ -283,62 +315,56 @@
         if (closed) {
             throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$
         }
-        // END android-changed
         if (inf.finished() || currentEntry == null) {
             return -1;
         }
         // avoid int overflow, check null buffer
-        if (start <= buffer.length && length >= 0 && start >= 0
-                && buffer.length - start >= length) {
-            if (currentEntry.compressionMethod == STORED) {
-                int csize = (int) currentEntry.size;
-                if (inRead >= csize) {
-                    // BEGIN android-added
-                    eof = true;
-                    // END android-added
-                    return -1;
-                }
-                if (lastRead >= len) {
-                    lastRead = 0;
-                    if ((len = in.read(buf)) == -1) {
-                        // BEGIN android-added
-                        eof = true;
-                        // END android-added
-                        return -1;
-                    }
-                    entryIn += len;
-                }
-                // BEGIN android-changed
-                int toRead = length > (len - lastRead) ? len - lastRead : length;
-                // END android-changed
-                if ((csize - inRead) < toRead) {
-                    toRead = csize - inRead;
-                }
-                System.arraycopy(buf, lastRead, buffer, start, toRead);
-                lastRead += toRead;
-                inRead += toRead;
-                crc.update(buffer, start, toRead);
-                return toRead;
-            }
-            if (inf.needsInput()) {
-                fill();
-                if (len > 0) {
-                    entryIn += len;
-                }
-            }
-            int read = 0;
-            try {
-                read = inf.inflate(buffer, start, length);
-            } catch (DataFormatException e) {
-                throw new ZipException(e.getMessage());
-            }
-            if (read == 0 && inf.finished()) {
+        if (start > buffer.length || length < 0 || start < 0
+                || buffer.length - start < length) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+
+        if (currentEntry.compressionMethod == STORED) {
+            int csize = (int) currentEntry.size;
+            if (inRead >= csize) {
                 return -1;
             }
-            crc.update(buffer, start, read);
-            return read;
+            if (lastRead >= len) {
+                lastRead = 0;
+                if ((len = in.read(buf)) == -1) {
+                    eof = true;
+                    return -1;
+                }
+                entryIn += len;
+            }
+            int toRead = length > (len - lastRead) ? len - lastRead : length;
+            if ((csize - inRead) < toRead) {
+                toRead = csize - inRead;
+            }
+            System.arraycopy(buf, lastRead, buffer, start, toRead);
+            lastRead += toRead;
+            inRead += toRead;
+            crc.update(buffer, start, toRead);
+            return toRead;
         }
-        throw new ArrayIndexOutOfBoundsException();
+        if (inf.needsInput()) {
+            fill();
+            if (len > 0) {
+                entryIn += len;
+            }
+        }
+        int read;
+        try {
+            read = inf.inflate(buffer, start, length);
+        } catch (DataFormatException e) {
+            throw new ZipException(e.getMessage());
+        }
+        if (read == 0 && inf.finished()) {
+            return -1;
+        }
+        crc.update(buffer, start, read);
+        return read;
+        // END android-changed
     }
 
     /**
@@ -381,10 +407,7 @@
         if (closed) {
             throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$
         }
-        if (currentEntry == null) {
-            return 1;
-        }
-        return super.available();
+        return (currentEntry == null || inRead < currentEntry.size) ? 1 : 0;
         // END android-changed
     }
 
diff --git a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java
index 96321a4..d2a5110 100644
--- a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java
+++ b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java
@@ -18,10 +18,15 @@
 
 
 import dalvik.annotation.AndroidOnly;
-import dalvik.annotation.TestTargetClass;
 import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
 import dalvik.annotation.TestTargetNew;
 
+import junit.framework.TestCase;
+
+import tests.support.Support_PlatformFile;
+import tests.support.resource.Support_Resources;
+
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
@@ -41,10 +46,6 @@
 import java.util.zip.ZipException;
 import java.util.zip.ZipFile;
 
-import junit.framework.TestCase;
-import tests.support.Support_PlatformFile;
-import tests.support.resource.Support_Resources;
-
 
 @TestTargetClass(JarFile.class)
 public class JarFileTest extends TestCase {
@@ -74,14 +75,22 @@
 
     private final String jarName5 = "hyts_signed_inc.jar";
 
-    private final String integrateJar = "Integrate.jar";
-
     private final String entryName = "foo/bar/A.class";
 
     private final String entryName3 = "coucou/FileAccess.class";
 
+    private final String integrateJar = "Integrate.jar";
+
     private final String integrateJarEntry = "Test.class";
 
+    private final String emptyEntryJar = "EmptyEntries_signed.jar";
+
+    private final String emptyEntry1 = "subfolder/internalSubset01.js";
+
+    private final String emptyEntry2 = "svgtest.js";
+
+    private final String emptyEntry3 = "svgunit.js";
+
     private File resources;
 
     // custom security manager
@@ -1061,4 +1070,33 @@
             // expected
         }
     }
+
+    /**
+     * The jar is intact, but the entry object is modified.
+     */
+    @TestTargetNew(
+            level = TestLevel.PARTIAL_COMPLETE,
+            notes = "Regression test for issue introduced by HAROMNY-4569. "
+                + "signed archives containing files with size 0 could not get verified",
+            method = "getInputStream",
+            args = {ZipEntry.class}
+    )
+    public void testJarVerificationEmptyEntry() throws IOException {
+        Support_Resources.copyFile(resources, null, emptyEntryJar);
+        File f = new File(resources, emptyEntryJar);
+
+        JarFile jarFile = new JarFile(f);
+
+        ZipEntry zipEntry = jarFile.getJarEntry(emptyEntry1);
+        int res = jarFile.getInputStream(zipEntry).read(new byte[100], 0, 100);
+        assertEquals("Wrong length of empty jar entry", -1, res);
+
+        zipEntry = jarFile.getJarEntry(emptyEntry2);
+        res = jarFile.getInputStream(zipEntry).read(new byte[100], 0, 100);
+        assertEquals("Wrong length of empty jar entry", -1, res);
+
+        zipEntry = jarFile.getJarEntry(emptyEntry3);
+        res = jarFile.getInputStream(zipEntry).read();
+        assertEquals("Wrong length of empty jar entry", -1, res);
+    }
 }
diff --git a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarInputStreamTest.java b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarInputStreamTest.java
index 64e0e1a..5befa77 100644
--- a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarInputStreamTest.java
+++ b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarInputStreamTest.java
@@ -154,12 +154,12 @@
         assertEquals(actual, desired);
         jis.close();
 
-//        try {
-//            jis.getNextJarEntry(); //Android implementation does not throw exception
-//            fail("IOException expected");
-//        } catch (IOException ee) {
-//            // expected
-//        }
+        try {
+            jis.getNextJarEntry();
+            fail("IOException expected");
+        } catch (IOException ee) {
+            // expected
+        }
 
         File resources = Support_Resources.createTempFolder();
         Support_Resources.copyFile(resources, null, "Broken_entry.jar");
@@ -179,11 +179,9 @@
         method = "getNextJarEntry",
         args = {}
     )
-    @KnownFailure("IOException not thrown when using getNextJarEntry() after close().")
     public void test_getNextJarEntry_Ex() throws Exception {
         final Set<String> desired = new HashSet<String>(Arrays
-                .asList(new String[] {
-                        "foo/", "foo/bar/", "foo/bar/A.class", "Blah.txt"}));
+                .asList("foo/", "foo/bar/", "foo/bar/A.class", "Blah.txt"));
         Set<String> actual = new HashSet<String>();
         InputStream is = new URL(jarName).openConnection().getInputStream();
         JarInputStream jis = new JarInputStream(is);
@@ -196,7 +194,7 @@
         jis.close();
 
         try {
-            jis.getNextJarEntry(); //Android implementation does not throw exception
+            jis.getNextJarEntry();
             fail("IOException expected");
         } catch (IOException ee) {
             // expected
@@ -276,29 +274,21 @@
     )
     public void test_JarInputStream_Modified_Manifest_MainAttributes_getNextEntry()
             throws IOException {
-        String modJarName = Support_Resources
-                .getURL("Modified_Manifest_MainAttributes.jar");
-        InputStream is = new URL(modJarName).openConnection().getInputStream();
+        String modJarName = Support_Resources.getURL("Modified_Manifest_MainAttributes.jar");
+        InputStream is = new URL(modJarName).openConnection()
+                .getInputStream();
         JarInputStream jin = new JarInputStream(is, true);
-        ZipEntry zipEntry = null;
 
-        final int indexofDSA = 2;
-        final int totalEntries = 4;
-        int count = 0;
-        while (count == 0 || zipEntry != null) {
-            count++;
-            try {
-                zipEntry = jin.getNextEntry();
-                if (count == indexofDSA + 1) {
-                    fail("Should throw Security Exception");
-                }
-            } catch (SecurityException e) {
-                if (count != indexofDSA + 1) {
-                    throw e;
-                }
-            }
+        assertEquals("META-INF/TESTROOT.SF", jin.getNextEntry().getName());
+        assertEquals("META-INF/TESTROOT.DSA", jin.getNextEntry().getName());
+        try {
+            jin.getNextEntry();
+            fail();
+        } catch (SecurityException expected) {
         }
-        assertEquals(totalEntries + 2, count);
+        assertEquals("META-INF/", jin.getNextEntry().getName());
+        assertEquals("Test.class", jin.getNextEntry().getName());
+        assertNull(jin.getNextEntry());
         jin.close();
     }
 
@@ -542,7 +532,6 @@
         method = "close",
         args = {}
     )
-    @KnownFailure("The behaviour is different from RI, but not neccessarily wrong. However a strange exception message is given anyway!")
     public void test_closeAfterException() throws Exception {
         File resources = Support_Resources.createTempFolder();
         Support_Resources.copyFile(resources, null, "Broken_entry.jar");
@@ -555,7 +544,7 @@
         } catch (ZipException ee) {
             // expected
         }
-        jis.close(); // Android throws exception here, but RI throws when getNextEntry/read/skip are called.
+        jis.close();
         try {
             jis.getNextEntry();
             fail("IOException expected");
diff --git a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/DeflaterOutputStreamTest.java b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/DeflaterOutputStreamTest.java
index ed7238c..738f610 100644
--- a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/DeflaterOutputStreamTest.java
+++ b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/DeflaterOutputStreamTest.java
@@ -211,21 +211,22 @@
     )
     public void test_close() throws Exception {
         File f1 = File.createTempFile("close", ".tst");
-        FileOutputStream fos = new FileOutputStream(f1);
-        DeflaterOutputStream dos = new DeflaterOutputStream(fos);
-        byte byteArray[] = {1, 3, 4, 6};
-        dos.write(byteArray);
 
-        FileInputStream fis = new FileInputStream(f1);
-        InflaterInputStream iis = new InflaterInputStream(fis);
+        InflaterInputStream iis = new InflaterInputStream(new FileInputStream(f1));
         try {
             iis.read();
             fail("EOFException Not Thrown");
         } catch (EOFException e) {
         }
 
+        FileOutputStream fos = new FileOutputStream(f1);
+        DeflaterOutputStream dos = new DeflaterOutputStream(fos);
+        byte byteArray[] = {1, 3, 4, 6};
+        dos.write(byteArray);
         dos.close();
 
+        iis = new InflaterInputStream(new FileInputStream(f1));
+
         // Test to see if the finish method wrote the bytes to the file.
         assertEquals("Incorrect Byte Returned.", 1, iis.read());
         assertEquals("Incorrect Byte Returned.", 3, iis.read());
diff --git a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterInputStreamTest.java b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterInputStreamTest.java
index 2de996e..707f13b 100644
--- a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterInputStreamTest.java
+++ b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterInputStreamTest.java
@@ -32,6 +32,8 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.FileOutputStream;
+import java.io.EOFException;
 import java.util.zip.DeflaterOutputStream;
 import java.util.zip.Inflater;
 import java.util.zip.InflaterInputStream;
@@ -208,6 +210,42 @@
         }
     }
 
+    public void testAvailableNonEmptySource() throws Exception {
+        // this byte[] is a deflation of these bytes: { 1, 3, 4, 6 }
+        byte[] deflated = { 72, -119, 99, 100, 102, 97, 3, 0, 0, 31, 0, 15, 0 };
+        InputStream in = new InflaterInputStream(new ByteArrayInputStream(deflated));
+        // InflaterInputStream.available() returns either 1 or 0, even though
+        // that contradicts the behavior defined in InputStream.available()
+        assertEquals(1, in.read());
+        assertEquals(1, in.available());
+        assertEquals(3, in.read());
+        assertEquals(1, in.available());
+        assertEquals(4, in.read());
+        assertEquals(1, in.available());
+        assertEquals(6, in.read());
+        assertEquals(0, in.available());
+        assertEquals(-1, in.read());
+        assertEquals(-1, in.read());
+    }
+
+    public void testAvailableSkip() throws Exception {
+        // this byte[] is a deflation of these bytes: { 1, 3, 4, 6 }
+        byte[] deflated = { 72, -119, 99, 100, 102, 97, 3, 0, 0, 31, 0, 15, 0 };
+        InputStream in = new InflaterInputStream(new ByteArrayInputStream(deflated));
+        assertEquals(1, in.available());
+        assertEquals(4, in.skip(4));
+        assertEquals(0, in.available());
+    }
+
+    public void testAvailableEmptySource() throws Exception {
+        // this byte[] is a deflation of the empty file
+        byte[] deflated = { 120, -100, 3, 0, 0, 0, 0, 1 };
+        InputStream in = new InflaterInputStream(new ByteArrayInputStream(deflated));
+        assertEquals(-1, in.read());
+        assertEquals(-1, in.read());
+        assertEquals(0, in.available());
+    }
+
     /**
      * @tests java.util.zip.InflaterInputStream#read(byte[], int, int)
      */
@@ -471,12 +509,11 @@
         InflaterInputStream iis = new InflaterInputStream(is);
 
         int available;
-        int read;
         for (int i = 0; i < 11; i++) {
-            read = iis.read();
+            iis.read();
             available = iis.available();
-            if (read == -1) {
-                assertEquals("Bytes Available Should Return 0 ", 0, available);
+            if (available == 0) {
+                assertEquals("Expected no more bytes to read", -1, iis.read());
             } else {
                 assertEquals("Bytes Available Should Return 1.", 1, available);
             }
diff --git a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterTest.java b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterTest.java
index 6039c5b..cd5d538 100644
--- a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterTest.java
+++ b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterTest.java
@@ -862,17 +862,6 @@
         byte[] b = new byte[1024];
         assertEquals(0, inflater.inflate(b));
         inflater.end();
-
-        // Regression for HARMONY-2510
-        inflater = new Inflater();
-        byte[] input = new byte[] {-1};
-        inflater.setInput(input);
-        try {
-            inflater.inflate(b);
-            fail("should throw DataFormateException");
-        } catch (DataFormatException e) {
-            // expected
-        }
     }
 
     /**
diff --git a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java
index c9e7bb8..b025e11 100644
--- a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java
+++ b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java
@@ -18,7 +18,6 @@
 package org.apache.harmony.archive.tests.java.util.zip;
 
 import dalvik.annotation.KnownFailure;
-import dalvik.annotation.BrokenTest;
 import dalvik.annotation.TestLevel;
 import dalvik.annotation.TestTargetClass;
 import dalvik.annotation.TestTargetNew;
diff --git a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipInputStreamTest.java b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipInputStreamTest.java
index ac332fa..c5efedc 100644
--- a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipInputStreamTest.java
+++ b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipInputStreamTest.java
@@ -17,7 +17,6 @@
 
 package org.apache.harmony.archive.tests.java.util.zip;
 
-import dalvik.annotation.KnownFailure;
 import dalvik.annotation.TestLevel;
 import dalvik.annotation.TestTargetClass;
 import dalvik.annotation.TestTargetNew;
@@ -30,6 +29,7 @@
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.zip.ZipEntry;
@@ -174,8 +174,6 @@
         method = "close",
         args = {}
     )
-    @KnownFailure("after an exception has been thrown wile reading a "
-            + "call to close also throws an exception.")
     public void test_closeAfterException() throws Exception {
         File resources = Support_Resources.createTempFolder();
         Support_Resources.copyFile(resources, null, "Broken_manifest.jar");
@@ -281,6 +279,31 @@
         }
     }
 
+    @TestTargetNew(
+            level = TestLevel.PARTIAL_COMPLETE,
+            method = "read",
+            args = {byte[].class, int.class, int.class}
+    )
+    public void testReadOneByteAtATime() throws IOException {
+        InputStream in = new FilterInputStream(Support_Resources.getStream("hyts_ZipFile.zip")) {
+            @Override
+            public int read(byte[] buffer, int offset, int count) throws IOException {
+                return super.read(buffer, offset, 1); // one byte at a time
+            }
+
+            @Override
+            public int read(byte[] buffer) throws IOException {
+                return super.read(buffer, 0, 1); // one byte at a time
+            }
+        };
+
+        zis = new ZipInputStream(in);
+        while ((zentry = zis.getNextEntry()) != null) {
+            zentry.getName();
+        }
+        zis.close();
+    }
+
     /**
      * @tests java.util.zip.ZipInputStream#skip(long)
      */
@@ -360,19 +383,19 @@
         long entrySize = entry.getSize();
         assertTrue("Entry size was < 1", entrySize > 0);
         int i = 0;
-        for (i = 0; i < entrySize; i++) {
+        while (zis1.available() > 0) {
             zis1.skip(1);
-            if (zis1.available() == 0) break;
+            i++;
         }
         if (i != entrySize) {
             fail("ZipInputStream.available or ZipInputStream.skip does not " +
                     "working properly. Only skipped " + i +
                     " bytes instead of " + entrySize);
         }
-        zis1.skip(1);
-        assertTrue(zis1.available() == 0);
+        assertEquals(0, zis1.skip(1));
+        assertEquals(0, zis1.available());
         zis1.closeEntry();
-        assertFalse(zis.available() == 0);
+        assertEquals(1, zis.available());
         zis1.close();
         try {
             zis1.available();
diff --git a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipOutputStreamTest.java b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipOutputStreamTest.java
index 8ca551d..0398f03 100644
--- a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipOutputStreamTest.java
+++ b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipOutputStreamTest.java
@@ -86,7 +86,7 @@
         ZipEntry ze = new ZipEntry("testEntry");
         ze.setTime(System.currentTimeMillis());
         zos.putNextEntry(ze);
-        zos.write("Hello World".getBytes());
+        zos.write("Hello World".getBytes("UTF-8"));
         zos.closeEntry();
         assertTrue("closeEntry failed to update required fields",
                 ze.getSize() == 11 && ze.getCompressedSize() == 13);
diff --git a/libcore/crypto/src/main/java/javax/crypto/BadPaddingException.java b/libcore/crypto/src/main/java/javax/crypto/BadPaddingException.java
index 19fdaa8..5e2dd38 100644
--- a/libcore/crypto/src/main/java/javax/crypto/BadPaddingException.java
+++ b/libcore/crypto/src/main/java/javax/crypto/BadPaddingException.java
@@ -22,8 +22,6 @@
 /**
  * The exception that is thrown when a padding mechanism is expected for the
  * input data, but the input data does not have the proper padding bytes.
- * 
- * @since Android 1.0
  */
 public class BadPaddingException extends GeneralSecurityException {
 
@@ -37,7 +35,6 @@
      * 
      * @param msg
      *            the message
-     * @since Android 1.0
      */
     public BadPaddingException(String msg) {
         super(msg);
@@ -45,8 +42,6 @@
 
     /**
      * Creates a new instance of {@code BadPaddingException} with no message.
-     * 
-     * @since Android 1.0
      */
     public BadPaddingException() {
     }
diff --git a/libcore/crypto/src/main/java/javax/crypto/Cipher.java b/libcore/crypto/src/main/java/javax/crypto/Cipher.java
index ae72226..8e084ae 100644
--- a/libcore/crypto/src/main/java/javax/crypto/Cipher.java
+++ b/libcore/crypto/src/main/java/javax/crypto/Cipher.java
@@ -61,58 +61,41 @@
  * to be processed at a time can be optionally specified by appending it to the
  * mode name. e.g. <i>"AES/CFB8/NoPadding"</i>. If no number is specified, a
  * provider specific default value is used.
- * </p>
- * 
- * @since Android 1.0
  */
 public class Cipher {
 
     /**
      * Constant for decryption operation mode.
-     * 
-     * @since Android 1.0
      */
     public static final int DECRYPT_MODE = 2;
 
     /**
      * Constant for encryption operation mode.
-     * 
-     * @since Android 1.0
      */
     public static final int ENCRYPT_MODE = 1;
 
     /**
      * Constant indicating that the key to be unwrapped is a private key.
-     * 
-     * @since Android 1.0
      */
     public static final int PRIVATE_KEY = 2;
 
     /**
      * Constant indicating that the key to be unwrapped is a public key.
-     * 
-     * @since Android 1.0
      */
     public static final int PUBLIC_KEY = 1;
 
     /**
      * Constant indicating that the key to be unwrapped is a secret key.
-     * 
-     * @since Android 1.0
      */
     public static final int SECRET_KEY = 3;
 
     /**
      * Constant for key unwrapping operation mode.
-     * 
-     * @since Android 1.0
      */
     public static final int UNWRAP_MODE = 4;
 
     /**
      * Constant for key wrapping operation mode.
-     * 
-     * @since Android 1.0
      */
     public static final int WRAP_MODE = 3;
 
@@ -147,7 +130,7 @@
 
     /**
      * Creates a new Cipher instance.
-     * 
+     *
      * @param cipherSpi
      *            the implementation delegate of the cipher.
      * @param provider
@@ -157,7 +140,6 @@
      * @throws NullPointerException
      *             if either cipherSpi is {@code null} or provider is {@code
      *             null} and {@code cipherSpi} is a {@code NullCipherSpi}.
-     * @since Android 1.0
      */
     protected Cipher(CipherSpi cipherSpi, Provider provider,
             String transformation) {
@@ -178,7 +160,7 @@
      * transformation. The first found provider providing the transformation is
      * used to create the cipher. If no provider is found an exception is
      * thrown.
-     * 
+     *
      * @param transformation
      *            the name of the transformation to create a cipher for.
      * @return a cipher for the requested transformation.
@@ -189,7 +171,6 @@
      * @throws NoSuchPaddingException
      *             if no installed provider can provide the padding scheme in
      *             the <i>transformation</i>.
-     * @since Android 1.0
      */
     public static final Cipher getInstance(String transformation)
             throws NoSuchAlgorithmException, NoSuchPaddingException {
@@ -199,7 +180,7 @@
     /**
      * Creates a new cipher for the specified transformation provided by the
      * specified provider.
-     * 
+     *
      * @param transformation
      *            the name of the transformation to create a cipher for.
      * @param provider
@@ -216,7 +197,6 @@
      *             is not available.
      * @throws IllegalArgumentException
      *             if the specified provider is {@code null}.
-     * @since Android 1.0
      */
     public static final Cipher getInstance(String transformation,
             String provider) throws NoSuchAlgorithmException,
@@ -235,7 +215,7 @@
 
     /**
      * Creates a new cipher for the specified transformation.
-     * 
+     *
      * @param transformation
      *            the name of the transformation to create a cipher for.
      * @param provider
@@ -250,7 +230,6 @@
      *             is not available.
      * @throws IllegalArgumentException
      *             if the provider is {@code null}.
-     * @since Android 1.0
      */
     public static final Cipher getInstance(String transformation,
             Provider provider) throws NoSuchAlgorithmException,
@@ -373,9 +352,8 @@
 
     /**
      * Returns the provider of this cipher instance.
-     * 
+     *
      * @return the provider of this cipher instance.
-     * @since Android 1.0
      */
     public final Provider getProvider() {
         return provider;
@@ -386,10 +364,8 @@
      * <p>
      * This is the name of the <i>transformation</i> argument used in the
      * {@code getInstance} call creating this object.
-     * </p>
-     * 
+     *
      * @return the name of the algorithm of this cipher instance.
-     * @since Android 1.0.
      */
     public final String getAlgorithm() {
         return transformation;
@@ -397,9 +373,8 @@
 
     /**
      * Returns this ciphers block size (in bytes).
-     * 
+     *
      * @return this ciphers block size.
-     * @since Android 1.0
      */
     public final int getBlockSize() {
         return spiImpl.engineGetBlockSize();
@@ -408,13 +383,12 @@
     /**
      * Returns the length in bytes an output buffer needs to be when this cipher
      * is updated with {@code inputLen} bytes.
-     * 
+     *
      * @param inputLen
      *            the number of bytes of the input.
      * @return the output buffer length for the input length.
      * @throws IllegalStateException
      *             if this cipher instance is in an invalid state.
-     * @since Android 1.0
      */
     public final int getOutputSize(int inputLen) {
         if (mode == 0) {
@@ -426,9 +400,8 @@
 
     /**
      * Returns the <i>initialization vector</i> for this cipher instance.
-     * 
+     *
      * @return the <i>initialization vector</i> for this cipher instance.
-     * @since Android 1.0
      */
     public final byte[] getIV() {
         return spiImpl.engineGetIV();
@@ -440,11 +413,10 @@
      * These may be a the same parameters that were used to create this cipher
      * instance, or may be a combination of default and random parameters,
      * depending on the underlying cipher implementation.
-     * 
+     *
      * @return the parameters that where used to create this cipher instance, or
      *         {@code null} if this cipher instance does not have any
      *         parameters.
-     * @since Android 1.0
      */
     public final AlgorithmParameters getParameters() {
         return spiImpl.engineGetParameters();
@@ -452,9 +424,8 @@
 
     /**
      * Returns the exemption mechanism associated with this cipher.
-     * 
+     *
      * @return currently {@code null}
-     * @since Android 1.0
      */
     public final ExemptionMechanism getExemptionMechanism() {
         //FIXME implement getExemptionMechanism
@@ -473,7 +444,7 @@
      * The cipher is initialized for the specified operational mode (one of:
      * encryption, decryption, key wrapping or key unwrapping) depending on
      * {@code opmode}.
-     * </p>
+     * <p>
      * If this cipher instance needs any algorithm parameters or random values
      * that the specified key can not provide, the underlying implementation of
      * this cipher is supposed to generate the required parameters (using its
@@ -483,8 +454,7 @@
      * init} methods, the state of the instance is overridden, meaning that it
      * is equivalent to creating a new instance and calling its {@code init}
      * method.
-     * </p>
-     * 
+     *
      * @param opmode
      *            the operation this cipher instance should be initialized for
      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
@@ -494,7 +464,6 @@
      * @throws InvalidKeyException
      *             if the specified key can not be used to initialize this
      *             cipher instance.
-     * @since Android 1.0
      */
     public final void init(int opmode, Key key) throws InvalidKeyException {
         if (sec_rand == null) {
@@ -513,7 +482,7 @@
      * The cipher is initialized for the specified operational mode (one of:
      * encryption, decryption, key wrapping or key unwrapping) depending on
      * {@code opmode}.
-     * </p>
+     * <p>
      * If this cipher instance needs any algorithm parameters or random values
      * that the specified key can not provide, the underlying implementation of
      * this cipher is supposed to generate the required parameters (using its
@@ -523,8 +492,7 @@
      * When a cipher instance is initialized by a call to any of the {@code
      * init} methods, the state of the instance is overridden, means it is
      * equivalent to creating a new instance and calling it {@code init} method.
-     * </p>
-     * 
+     *
      * @param opmode
      *            the operation this cipher instance should be initialized for
      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
@@ -538,7 +506,6 @@
      *             cipher instance.
      * @throws InvalidParameterException
      *             if the specified opmode is invalid.
-     * @since Android 1.0
      */
     public final void init(int opmode, Key key, SecureRandom random)
             throws InvalidKeyException {
@@ -559,7 +526,7 @@
      * <p>
      * The cipher is initialized for the specified operational mode (one of:
      * encryption, decryption, key wrapping or key unwrapping).
-     * </p>
+     * <p>
      * If this cipher instance needs any algorithm parameters and {@code params}
      * is {@code null}, the underlying implementation of this cipher is supposed
      * to generate the required parameters (using its provider or random
@@ -568,8 +535,7 @@
      * When a cipher instance is initialized by a call to any of the {@code
      * init} methods, the state of the instance is overridden, means it is
      * equivalent to creating a new instance and calling it {@code init} method.
-     * </p>
-     * 
+     *
      * @param opmode
      *            the operation this cipher instance should be initialized for
      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
@@ -584,7 +550,6 @@
      * @throws InvalidAlgorithmParameterException
      *             it the specified parameters are inappropriate for this
      *             cipher.
-     * @since Android 1.0
      */
     public final void init(int opmode, Key key, AlgorithmParameterSpec params)
             throws InvalidKeyException, InvalidAlgorithmParameterException {
@@ -611,7 +576,7 @@
      * init} methods, the state of the instance is overridden, meaning that it
      * is equivalent to creating a new instance and calling it {@code init}
      * method.
-     * 
+     *
      * @param opmode
      *            the operation this cipher instance should be initialized for
      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
@@ -630,7 +595,6 @@
      *             cipher.
      * @throws InvalidParameterException
      *             if the specified {@code opmode} is invalid.
-     * @since Android 1.0
      */
     public final void init(int opmode, Key key, AlgorithmParameterSpec params,
             SecureRandom random) throws InvalidKeyException,
@@ -656,7 +620,7 @@
      * The cipher is initialized for the specified operation (one of:
      * encryption, decryption, key wrapping or key unwrapping) depending on
      * {@code opmode}.
-     * </p>
+     * <p>
      * If this cipher instance needs any algorithm parameters and {@code params}
      * is {@code null}, the underlying implementation of this cipher is supposed
      * to generate the required parameters (using its provider or random
@@ -666,8 +630,7 @@
      * init} methods, the state of the instance is overridden, meaning that it
      * is equivalent to creating a new instance and calling it {@code init}
      * method.
-     * </p>
-     * 
+     *
      * @param opmode
      *            the operation this cipher instance should be initialized for
      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
@@ -682,7 +645,6 @@
      * @throws InvalidAlgorithmParameterException
      *             it the specified parameters are inappropriate for this
      *             cipher.
-     * @since Android 1.0
      */
     public final void init(int opmode, Key key, AlgorithmParameters params)
             throws InvalidKeyException, InvalidAlgorithmParameterException {
@@ -699,7 +661,7 @@
      * The cipher will be initialized for the specified operation (one of:
      * encryption, decryption, key wrapping or key unwrapping) depending on
      * {@code opmode}.
-     * </p>
+     * <p>
      * If this cipher instance needs any algorithm parameters and {@code params}
      * is {@code null}, the underlying implementation of this cipher is supposed
      * to generate the required parameters (using its provider or random
@@ -708,8 +670,7 @@
      * When a cipher instance is initialized by a call to any of the {@code
      * init} methods, the state of the instance is overridden, means it is
      * equivalent to creating a new instance and calling it {@code init} method.
-     * </p>
-     * 
+     *
      * @param opmode
      *            the operation this cipher instance should be initialized for
      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
@@ -728,7 +689,6 @@
      *             cipher.
      * @throws InvalidParameterException
      *             if the specified {@code opmode} is invalid.
-     * @since Android 1.0
      */
     public final void init(int opmode, Key key, AlgorithmParameters params,
             SecureRandom random) throws InvalidKeyException,
@@ -768,7 +728,7 @@
      * When a cipher instance is initialized by a call to any of the {@code
      * init} methods, the state of the instance is overridden, means it is
      * equivalent to creating a new instance and calling it {@code init} method.
-     * 
+     *
      * @param opmode
      *            the operation this cipher instance should be initialized for
      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
@@ -778,7 +738,6 @@
      * @throws InvalidKeyException
      *             if the public key in the certificate can not be used to
      *             initialize this cipher instance.
-     * @since Android 1.0
      */
     public final void init(int opmode, Certificate certificate)
             throws InvalidKeyException {
@@ -795,7 +754,7 @@
      * The cipher will be initialized for the specified operation (one of:
      * encryption, decryption, key wrapping or key unwrapping) depending on
      * {@code opmode}.
-     * </p>
+     * <p>
      * It the type of the certificate is X.509 and the certificate has a <i>key
      * usage</i> extension field marked as critical, the specified {@code
      * opmode} has the be enabled for this key, otherwise an {@code
@@ -806,11 +765,11 @@
      * cipher is supposed to generate the required parameters (using its
      * provider or random values). Random values are generated using {@code
      * random}.
-     * </p>
+     * <p>
      * When a cipher instance is initialized by a call to any of the {@code
      * init} methods, the state of the instance is overridden, means it is
      * equivalent to creating a new instance and calling it {@code init} method.
-     * 
+     *
      * @param opmode
      *            the operation this cipher instance should be initialized for
      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
@@ -822,7 +781,6 @@
      * @throws InvalidKeyException
      *             if the public key in the certificate can not be used to
      *             initialize this cipher instance.
-     * @since Android 1.0
      */
     public final void init(int opmode, Certificate certificate,
             SecureRandom random) throws InvalidKeyException {
@@ -874,7 +832,7 @@
     /**
      * Continues a multi-part transformation (encryption or decryption). The
      * transformed bytes are returned.
-     * 
+     *
      * @param input
      *            the input bytes to transform.
      * @return the transformed bytes in a new buffer, or {@code null} if the
@@ -884,7 +842,6 @@
      *             decryption.
      * @throws IllegalArgumentException
      *             if the input is {@code null}.
-     * @since Android 1.0
      */
     public final byte[] update(byte[] input) {
         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
@@ -903,7 +860,7 @@
     /**
      * Continues a multi-part transformation (encryption or decryption). The
      * transformed bytes are returned.
-     * 
+     *
      * @param input
      *            the input bytes to transform.
      * @param inputOffset
@@ -919,7 +876,6 @@
      *             if the input is {@code null}, or if {@code inputOffset} and
      *             {@code inputLen} do not specify a valid chunk in the input
      *             buffer.
-     * @since Android 1.0
      */
     public final byte[] update(byte[] input, int inputOffset, int inputLen) {
         if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
@@ -949,8 +905,7 @@
      * a {@code ShortBufferException} is thrown. Use
      * {@link Cipher#getOutputSize getOutputSize} to check for the size of the
      * output buffer.
-     * </p>
-     * 
+     *
      * @param input
      *            the input bytes to transform.
      * @param inputOffset
@@ -969,7 +924,6 @@
      *             if the input is {@code null}, the output is {@code null}, or
      *             if {@code inputOffset} and {@code inputLen} do not specify a
      *             valid chunk in the input buffer.
-     * @since Android 1.0
      */
     public final int update(byte[] input, int inputOffset, int inputLen,
             byte[] output) throws ShortBufferException {
@@ -984,8 +938,7 @@
      * a {@code ShortBufferException} is thrown. Use
      * {@link Cipher#getOutputSize getOutputSize} to check for the size of the
      * output buffer.
-     * </p>
-     * 
+     *
      * @param input
      *            the input bytes to transform.
      * @param inputOffset
@@ -1006,7 +959,6 @@
      *             if the input is {@code null}, the output is {@code null}, or
      *             if {@code inputOffset} and {@code inputLen} do not specify a
      *             valid chunk in the input buffer.
-     * @since Android 1.0
      */
     public final int update(byte[] input, int inputOffset, int inputLen,
             byte[] output, int outputOffset) throws ShortBufferException {
@@ -1046,8 +998,7 @@
      * bytes a {@code ShortBufferException} is thrown. Use
      * {@link Cipher#getOutputSize getOutputSize} to check for the size of the
      * output buffer.
-     * </p>
-     * 
+     *
      * @param input
      *            the input buffer to transform.
      * @param output
@@ -1061,7 +1012,6 @@
      * @throws IllegalArgumentException
      *             if the input buffer and the output buffer are the identical
      *             object.
-     * @since Android 1.0
      */
     public final int update(ByteBuffer input, ByteBuffer output)
             throws ShortBufferException {
@@ -1081,8 +1031,7 @@
      * <p>
      * Processes any bytes that may have been buffered in previous {@code
      * update} calls.
-     * </p>
-     * 
+     *
      * @return the final bytes from the transformation.
      * @throws IllegalBlockSizeException
      *             if the size of the resulting bytes is not a multiple of the
@@ -1092,7 +1041,6 @@
      * @throws IllegalStateException
      *             if this cipher instance is not initialized for encryption or
      *             decryption.
-     * @since Android 1.0
      */
     public final byte[] doFinal() throws IllegalBlockSizeException,
             BadPaddingException {
@@ -1108,9 +1056,9 @@
      * <p>
      * Processes any bytes that may have been buffered in previous {@code
      * update} calls.
-     * </p>
+     * <p>
      * The final transformed bytes are stored in the {@code output} buffer.
-     * 
+     *
      * @param output
      *            the output buffer.
      * @param outputOffset
@@ -1126,7 +1074,6 @@
      * @throws IllegalStateException
      *             if this cipher instance is not initialized for encryption or
      *             decryption.
-     * @since Android 1.0
      */
     public final int doFinal(byte[] output, int outputOffset)
             throws IllegalBlockSizeException, ShortBufferException,
@@ -1147,8 +1094,7 @@
      * <p>
      * Processes the bytes in {@code input} buffer, and any bytes that have been
      * buffered in previous {@code update} calls.
-     * </p>
-     * 
+     *
      * @param input
      *            the input buffer.
      * @return the final bytes from the transformation.
@@ -1160,7 +1106,6 @@
      * @throws IllegalStateException
      *             if this cipher instance is not initialized for encryption or
      *             decryption.
-     * @since Android 1.0
      */
     public final byte[] doFinal(byte[] input) throws IllegalBlockSizeException,
             BadPaddingException {
@@ -1177,7 +1122,7 @@
      * Processes the {@code inputLen} bytes in {@code input} buffer at {@code
      * inputOffset}, and any bytes that have been buffered in previous {@code
      * update} calls.
-     * 
+     *
      * @param input
      *            the input buffer.
      * @param inputOffset
@@ -1196,7 +1141,6 @@
      * @throws IllegalArgumentException
      *             if {@code inputOffset} and {@code inputLen} do not specify an
      *             valid chunk in the input buffer.
-     * @since Android 1.0
      */
     public final byte[] doFinal(byte[] input, int inputOffset, int inputLen)
             throws IllegalBlockSizeException, BadPaddingException {
@@ -1218,7 +1162,7 @@
      * Processes the {@code inputLen} bytes in {@code input} buffer at {@code
      * inputOffset}, and any bytes that have been buffered in previous {@code
      * update} calls.
-     * 
+     *
      * @param input
      *            the input buffer.
      * @param inputOffset
@@ -1241,7 +1185,6 @@
      * @throws IllegalArgumentException
      *             if {@code inputOffset} and {@code inputLen} do not specify an
      *             valid chunk in the input buffer.
-     * @since Android 1.0
      */
     public final int doFinal(byte[] input, int inputOffset, int inputLen,
             byte[] output) throws ShortBufferException,
@@ -1255,8 +1198,7 @@
      * Processes the {@code inputLen} bytes in {@code input} buffer at {@code
      * inputOffset}, and any bytes that have been buffered in previous {@code
      * update} calls.
-     * </p>
-     * 
+     *
      * @param input
      *            the input buffer.
      * @param inputOffset
@@ -1281,7 +1223,6 @@
      * @throws IllegalArgumentException
      *             if {@code inputOffset} and {@code inputLen} do not specify an
      *             valid chunk in the input buffer.
-     * @since Android 1.0
      */
     public final int doFinal(byte[] input, int inputOffset, int inputLen,
             byte[] output, int outputOffset) throws ShortBufferException,
@@ -1306,8 +1247,7 @@
      * {@code input.position()}, and any bytes that have been buffered in
      * previous {@code update} calls. The transformed bytes are placed into
      * {@code output} buffer.
-     * </p>
-     * 
+     *
      * @param input
      *            the input buffer.
      * @param output
@@ -1326,7 +1266,6 @@
      * @throws IllegalStateException
      *             if this cipher instance is not initialized for encryption or
      *             decryption.
-     * @since Android 1.0
      */
     public final int doFinal(ByteBuffer input, ByteBuffer output)
             throws ShortBufferException, IllegalBlockSizeException,
@@ -1344,7 +1283,7 @@
 
     /**
      * Wraps a key using this cipher instance.
-     * 
+     *
      * @param key
      *            the key to wrap.
      * @return the wrapped key.
@@ -1355,7 +1294,6 @@
      *             if this cipher instance can not wrap this key.
      * @throws IllegalStateException
      *             if this cipher instance is not initialized for wrapping.
-     * @since Android 1.0
      */
     public final byte[] wrap(Key key) throws IllegalBlockSizeException,
             InvalidKeyException {
@@ -1368,7 +1306,7 @@
 
     /**
      * Unwraps a key using this cipher instance.
-     * 
+     *
      * @param wrappedKey
      *            the wrapped key to unwrap.
      * @param wrappedKeyAlgorithm
@@ -1386,7 +1324,6 @@
      *             {@code wrappedKeyType} for the {@code wrappedKeyAlgorithm}.
      * @throws IllegalStateException
      *             if this cipher instance is not initialized for unwrapping.
-     * @since Android 1.0
      */
     public final Key unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
             int wrappedKeyType) throws InvalidKeyException,
@@ -1401,7 +1338,7 @@
 
     /**
      * Returns the maximum key length for the specified transformation.
-     * 
+     *
      * @param transformation
      *            the transformation name.
      * @return the maximum key length, currently {@code Integer.MAX_VALUE}.
@@ -1410,7 +1347,6 @@
      *             be found.
      * @throws NullPointerException
      *             if {@code transformation} is {@code null}.
-     * @since Android 1.0
      */
     public static final int getMaxAllowedKeyLength(String transformation)
             throws NoSuchAlgorithmException {
@@ -1425,7 +1361,7 @@
     /**
      * Returns the maximum cipher parameter value for the specified
      * transformation. If there is no maximum limit, {@code null} is returned.
-     * 
+     *
      * @param transformation
      *            the transformation name.
      * @return a parameter spec holding the maximum value or {@code null}.
@@ -1435,7 +1371,6 @@
      *             be found.
      * @throws NullPointerException
      *             if {@code transformation} is {@code null}.
-     * @since Android 1.0
      */
     public static final AlgorithmParameterSpec getMaxAllowedParameterSpec(
             String transformation) throws NoSuchAlgorithmException {
diff --git a/libcore/crypto/src/main/java/javax/crypto/CipherInputStream.java b/libcore/crypto/src/main/java/javax/crypto/CipherInputStream.java
index ca64c49..b2c626d 100644
--- a/libcore/crypto/src/main/java/javax/crypto/CipherInputStream.java
+++ b/libcore/crypto/src/main/java/javax/crypto/CipherInputStream.java
@@ -32,9 +32,6 @@
  * by a {@code CipherInputStream}. For example, if a cipher initialized for
  * decryption is used with a {@code CipherInputStream}, the {@code
  * CipherInputStream} tries to read the data an decrypt them before returning.
- * </p>
- * 
- * @since Android 1.0
  */
 public class CipherInputStream extends FilterInputStream {
 
@@ -48,12 +45,11 @@
     /**
      * Creates a new {@code CipherInputStream} instance for an {@code
      * InputStream} and a cipher.
-     * 
+     *
      * @param is
      *            the input stream to read data from.
      * @param c
      *            the cipher to process the data with.
-     * @since Android 1.0
      */
     public CipherInputStream(InputStream is, Cipher c) {
         super(is);
@@ -65,11 +61,9 @@
      * InputStream} without a cipher.
      * <p>
      * A {@code NullCipher} is created and used to process the data.
-     * </p>
-     * 
+     *
      * @param is
      *            the input stream to read data from.
-     * @since Android 1.0
      */
     protected CipherInputStream(InputStream is) {
         this(is, new NullCipher());
@@ -77,11 +71,10 @@
 
     /**
      * Reads the next byte from this cipher input stream.
-     * 
+     *
      * @return the next byte, or {@code -1} if the end of the stream is reached.
      * @throws IOException
      *             if an error occurs.
-     * @since Android 1.0
      */
     @Override
     public int read() throws IOException {
@@ -114,14 +107,13 @@
     /**
      * Reads the next {@code b.length} bytes from this input stream into buffer
      * {@code b}.
-     * 
+     *
      * @param b
      *            the buffer to be filled with data.
      * @return the number of bytes filled into buffer {@code b}, or {@code -1}
      *         if the end of the stream is reached.
      * @throws IOException
      *             if an error occurs.
-     * @since Android 1.0
      */
     @Override
     public int read(byte[] b) throws IOException {
@@ -134,8 +126,7 @@
      * <p>
      * if {@code b} is {@code null}, the next {@code len} bytes are read and
      * discarded.
-     * </p>
-     * 
+     *
      * @param b
      *            the buffer to be filled with data.
      * @param off
@@ -148,7 +139,6 @@
      *             if an error occurs.
      * @throws NullPointerException
      *             if the underlying input stream is {@code null}.
-     * @since Android 1.0
      */
     @Override
     public int read(byte[] b, int off, int len) throws IOException {
@@ -175,15 +165,12 @@
      * The number of bytes skipped depends on the result of a call to
      * {@link CipherInputStream#available() available}. The smaller of n and the
      * result are the number of bytes being skipped.
-     * </p>
-     * Skipping is (currently) not supported in Android.
-     * 
+     *
      * @param n
      *            the number of bytes that should be skipped.
      * @return the number of bytes actually skipped.
      * @throws IOException
      *             if an error occurs
-     * @since Android 1.0
      */
     @Override
     public long skip(long n) throws IOException {
@@ -199,13 +186,11 @@
     }
 
     /**
-     * Returns the number of bytes available without blocking. It (currently)
-     * always returns {@code 0} in Android.
-     * 
+     * Returns the number of bytes available without blocking.
+     *
      * @return the number of bytes available, currently zero.
      * @throws IOException
      *             if an error occurs
-     * @since Android 1.0
      */
     @Override
     public int available() throws IOException {
@@ -215,10 +200,9 @@
     /**
      * Closes this {@code CipherInputStream}, also closes the underlying input
      * stream and call {@code doFinal} on the cipher object.
-     * 
+     *
      * @throws IOException
      *             if an error occurs.
-     * @since Android 1.0
      */
     @Override
     public void close() throws IOException {
@@ -232,15 +216,15 @@
     }
 
     /**
-     * Returns whether this input stream supports {@code mark} and {@code reset}
-     * , which it does not.
-     * 
+     * Returns whether this input stream supports {@code mark} and
+     * {@code reset}, which it does not.
+     *
      * @return false, since this input stream does not support {@code mark} and
      *         {@code reset}.
-     * @since Android 1.0
      */
     @Override
     public boolean markSupported() {
         return false;
     }
 }
+
diff --git a/libcore/crypto/src/main/java/javax/crypto/CipherOutputStream.java b/libcore/crypto/src/main/java/javax/crypto/CipherOutputStream.java
index 8bce42b..1f95b99 100644
--- a/libcore/crypto/src/main/java/javax/crypto/CipherOutputStream.java
+++ b/libcore/crypto/src/main/java/javax/crypto/CipherOutputStream.java
@@ -31,9 +31,6 @@
  * by a {@code CipherOutputStream}. For example, if a cipher initialized for
  * encryption is used with a {@code CipherOutputStream}, the {@code
  * CipherOutputStream} tries to encrypt the data writing it out.
- * </p>
- * 
- * @since Android 1.0
  */
 public class CipherOutputStream extends FilterOutputStream {
 
@@ -43,12 +40,11 @@
     /**
      * Creates a new {@code CipherOutputStream} instance for an {@code
      * OutputStream} and a {@code Cipher}.
-     * 
+     *
      * @param os
      *            the output stream to write data to.
      * @param c
      *            the cipher to process the data with.
-     * @since Android 1.0
      */
     public CipherOutputStream(OutputStream os, Cipher c) {
         super(os);
@@ -60,11 +56,9 @@
      * OutputStream} without a cipher.
      * <p>
      * A {@code NullCipher} is created to process the data.
-     * </p>
-     * 
+     *
      * @param os
      *            the output stream to write the data to.
-     * @since Android 1.0
      */
     protected CipherOutputStream(OutputStream os) {
         this(os, new NullCipher());
@@ -72,12 +66,11 @@
 
     /**
      * Writes the single byte to this cipher output stream.
-     * 
+     *
      * @param b
      *            the byte to write.
      * @throws IOException
      *             if an error occurs.
-     * @since Android 1.0
      */
     @Override
     public void write(int b) throws IOException {
@@ -91,12 +84,11 @@
 
     /**
      * Writes the buffer of bytes to this cipher output stream.
-     * 
+     *
      * @param b
      *            the buffer of bytes.
      * @throws IOException
      *             if an error occurs.
-     * @since Android 1.0
      */
     @Override
     public void write(byte[] b) throws IOException {
@@ -106,7 +98,7 @@
     /**
      * Writes the {@code len} bytes from buffer {@code b} starting at offset
      * {@code off} to this cipher output stream.
-     * 
+     *
      * @param b
      *            the buffer.
      * @param off
@@ -115,7 +107,6 @@
      *            the number of bytes.
      * @throws IOException
      *             if an error occurs.
-     * @since Android 1.0
      */
     @Override
     public void write(byte[] b, int off, int len) throws IOException {
@@ -130,7 +121,7 @@
 
     /**
      * Flushes this cipher output stream.
-     * 
+     *
      * @throws IOException
      *             if an error occurs
      */
@@ -145,7 +136,7 @@
      * On the underlying cipher {@code doFinal} will be invoked, and any
      * buffered bytes from the cipher are also written out, and the cipher is
      * reset to its initial state. The underlying output stream is also closed.
-     * 
+     *
      * @throws IOException
      *             if an error occurs.
      */
@@ -173,3 +164,4 @@
         }
     }
 }
+
diff --git a/libcore/crypto/src/main/java/javax/crypto/CipherSpi.java b/libcore/crypto/src/main/java/javax/crypto/CipherSpi.java
index f6da929..50fdd49 100644
--- a/libcore/crypto/src/main/java/javax/crypto/CipherSpi.java
+++ b/libcore/crypto/src/main/java/javax/crypto/CipherSpi.java
@@ -44,7 +44,7 @@
  * </ul>
  * The following behavior should be implemented for obtaining {@code Cipher}
  * instances.
- * </p>
+ * <p>
  * When one of the {@link Cipher#getInstance} factory methods is called with a
  * <i>transformation</i> that is only an <i>algorithm</i>, check if the provider
  * defines a {@code CipherSpi} for "algorithm", if so: return it, otherwise
@@ -76,53 +76,46 @@
  * padding name and return it, otherwise throw a
  * {@link NoSuchAlgorithmException}.
  * </ul>
- * </p>
- * 
+ *
  * @see Cipher
- * @since Android 1.0
  */
 public abstract class CipherSpi {
 
     /**
      * Creates a new {@code CipherSpi} instance.
-     * 
-     * @since Android 1.0
      */
     public CipherSpi() {
     }
 
     /**
      * Sets the mode for this cipher.
-     * 
+     *
      * @param mode
      *            the name of the cipher mode.
      * @throws NoSuchAlgorithmException
      *             if the specified cipher mode is not supported by this
      *             provider.
-     * @since Android 1.0
      */
     protected abstract void engineSetMode(String mode)
             throws NoSuchAlgorithmException;
 
     /**
      * Sets the padding method for this cipher.
-     * 
+     *
      * @param padding
      *            the name of the padding method.
      * @throws NoSuchPaddingException
      *             if the specified padding method is not supported by this
      *             cipher.
-     * @since Android 1.0
      */
     protected abstract void engineSetPadding(String padding)
             throws NoSuchPaddingException;
 
     /**
      * Returns the block size of this cipher (in bytes)
-     * 
+     *
      * @return the block size of this cipher, or zero if this cipher is not a
      *         block cipher.
-     * @since Android 1.0
      */
     protected abstract int engineGetBlockSize();
 
@@ -133,21 +126,18 @@
      * <p>
      * The actual output length of the next call to {@code update} or {@code
      * doFinal} may be smaller than the length returned by this method.
-     * </p>
-     * 
+     *
      * @param inputLen
      *            the length of the input (in bytes).
      * @return the size for a buffer (in bytes).
-     * @since Android 1.0
      */
     protected abstract int engineGetOutputSize(int inputLen);
 
     /**
      * Returns the Initialization Vector (IV) that was used to initialize this
      * cipher or {@code null} if none was used.
-     * 
+     *
      * @return the Initialization Vector (IV), or {@code null} if none was used.
-     * @since Android 1.0
      */
     protected abstract byte[] engineGetIV();
 
@@ -157,12 +147,10 @@
      * These may be a the same parameters that were used to create this cipher
      * instance, or may be a combination of default and random parameters,
      * depending on the underlying cipher implementation.
-     * </p>
-     * 
+     *
      * @return the parameters that where used to create this cipher instance, or
      *         {@code null} if this cipher instance does not have any parameters
      *         at all.
-     * @since Android 1.0
      */
     protected abstract AlgorithmParameters engineGetParameters();
 
@@ -173,7 +161,7 @@
      * The cipher will be initialized for the specified operation (one of:
      * encryption, decryption, key wrapping or key unwrapping) depending on
      * {@code opmode}.
-     * </p>
+     * <p>
      * If this cipher instance needs any algorithm parameters or random values
      * that the specified key cannot provide, the underlying implementation of
      * this cipher is supposed to generate the required parameters (using its
@@ -183,8 +171,7 @@
      * When a cipher instance is initialized by a call to any of the {@code
      * init} methods, the state of the instance is overridden, means it is
      * equivalent to creating a new instance and calling it {@code init} method.
-     * </p>
-     * 
+     *
      * @param opmode
      *            the operation this cipher instance should be initialized for
      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
@@ -196,7 +183,6 @@
      * @throws InvalidKeyException
      *             if the specified key cannot be used to initialize this cipher
      *             instance.
-     * @since Android 1.0
      */
     protected abstract void engineInit(int opmode, Key key, SecureRandom random)
             throws InvalidKeyException;
@@ -208,7 +194,7 @@
      * The cipher will be initialized for the specified operation (one of:
      * encryption, decryption, key wrapping or key unwrapping) depending on
      * {@code opmode}.
-     * </p>
+     * <p>
      * If this cipher instance needs any algorithm parameters and {@code params}
      * is {@code null}, the underlying implementation of this cipher is supposed
      * to generate the required parameters (using its provider or random
@@ -217,8 +203,7 @@
      * When a cipher instance is initialized by a call to any of the {@code
      * init} methods, the state of the instance is overridden, means it is
      * equivalent to creating a new instance and calling it {@code init} method.
-     * </p>
-     * 
+     *
      * @param opmode
      *            the operation this cipher instance should be initialized for
      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
@@ -235,7 +220,6 @@
      * @throws InvalidAlgorithmParameterException
      *             it the specified parameters are inappropriate for this
      *             cipher.
-     * @since Android 1.0
      */
     protected abstract void engineInit(int opmode, Key key,
             AlgorithmParameterSpec params, SecureRandom random)
@@ -248,7 +232,7 @@
      * The cipher will be initialized for the specified operation (one of:
      * encryption, decryption, key wrapping or key unwrapping) depending on
      * {@code opmode}.
-     * </p>
+     * <p>
      * If this cipher instance needs any algorithm parameters and {@code params}
      * is {@code null}, the underlying implementation of this cipher is supposed
      * to generate the required parameters (using its provider or random
@@ -257,8 +241,7 @@
      * When a cipher instance is initialized by a call to any of the {@code
      * init} methods, the state of the instance is overridden, means it is
      * equivalent to creating a new instance and calling it {@code init} method.
-     * </p>
-     * 
+     *
      * @param opmode
      *            the operation this cipher instance should be initialized for
      *            (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code
@@ -275,7 +258,6 @@
      * @throws InvalidAlgorithmParameterException
      *             if the specified parameters are inappropriate for this
      *             cipher.
-     * @since Android 1.0
      */
     protected abstract void engineInit(int opmode, Key key,
             AlgorithmParameters params, SecureRandom random)
@@ -284,7 +266,7 @@
     /**
      * Continues a multi-part transformation (encryption or decryption). The
      * transformed bytes are returned.
-     * 
+     *
      * @param input
      *            the input bytes to transform.
      * @param inputOffset
@@ -299,7 +281,6 @@
      * @throws IllegalArgumentException
      *             if the input is null, or if {@code inputOffset} and {@code
      *             inputLen} do not specify a valid chunk in the input buffer.
-     * @since Android 1.0
      */
     protected abstract byte[] engineUpdate(byte[] input, int inputOffset,
             int inputLen);
@@ -312,8 +293,7 @@
      * a {@code ShortBufferException} is thrown. Use
      * {@link Cipher#getOutputSize getOutputSize} to check for the size of the
      * output buffer.
-     * </p>
-     * 
+     *
      * @param input
      *            the input bytes to transform.
      * @param inputOffset
@@ -327,7 +307,6 @@
      * @return the number of bytes placed in output.
      * @throws ShortBufferException
      *             if the size of the {@code output} buffer is too small.
-     * @since Android 1.0
      */
     protected abstract int engineUpdate(byte[] input, int inputOffset,
             int inputLen, byte[] output, int outputOffset)
@@ -342,8 +321,7 @@
      * bytes a {@code ShortBufferException} is thrown. Use
      * {@link Cipher#getOutputSize getOutputSize} to check for the size of the
      * output buffer.
-     * </p>
-     * 
+     *
      * @param input
      *            the input buffer to transform.
      * @param output
@@ -351,7 +329,6 @@
      * @return the number of bytes stored in the output buffer.
      * @throws ShortBufferException
      *             if the size of the {@code output} buffer is too small.
-     * @since Android 1.0
      */
     protected int engineUpdate(ByteBuffer input, ByteBuffer output)
             throws ShortBufferException {
@@ -395,8 +372,7 @@
      * Processes the {@code inputLen} bytes in {@code input} buffer at {@code
      * inputOffset}, and any bytes that have been buffered in previous {@code
      * update} calls.
-     * </p>
-     * 
+     *
      * @param input
      *            the input buffer.
      * @param inputOffset
@@ -409,7 +385,6 @@
      *             cipher block size.
      * @throws BadPaddingException
      *             if the padding of the data does not match the padding scheme.
-     * @since Android 1.0
      */
     protected abstract byte[] engineDoFinal(byte[] input, int inputOffset,
             int inputLen) throws IllegalBlockSizeException, BadPaddingException;
@@ -418,10 +393,9 @@
      * Finishes a multi-part transformation (encryption or decryption).
      * <p>
      * Processes the {@code inputLen} bytes in {@code input} buffer at
-     * {@code inputOffset}, and any bytes that have been buffered in previous 
+     * {@code inputOffset}, and any bytes that have been buffered in previous
      * {@code update} calls.
-     * </p>
-     * 
+     *
      * @param input
      *            the input buffer.
      * @param inputOffset
@@ -440,7 +414,6 @@
      *             cipher block size.
      * @throws BadPaddingException
      *             if the padding of the data does not match the padding scheme.
-     * @since Android 1.0
      */
     protected abstract int engineDoFinal(byte[] input, int inputOffset,
             int inputLen, byte[] output, int outputOffset)
@@ -454,8 +427,7 @@
      * {@code input.position()}, and any bytes that have been buffered in
      * previous {@code update} calls. The transformed bytes are placed into
      * {@code output} buffer.
-     * </p>
-     * 
+     *
      * @param input
      *            the input buffer.
      * @param output
@@ -519,7 +491,7 @@
      * this class (for backwards compatibility, it cannot be abstract). If this
      * method is not overridden, it throws an {@code
      * UnsupportedOperationException}.
-     * 
+     *
      * @param key
      *            the key to wrap.
      * @return the wrapped key
@@ -528,7 +500,6 @@
      *             cipher block size.
      * @throws InvalidKeyException
      *             if this cipher instance cannot wrap this key.
-     * @since Android 1.0
      */
     protected byte[] engineWrap(Key key) throws IllegalBlockSizeException,
             InvalidKeyException {
@@ -542,8 +513,7 @@
      * This method has been added to this class (for backwards compatibility, it
      * cannot be abstract). If this method is not overridden, it throws an
      * {@code UnsupportedOperationException}.
-     * </p>
-     * 
+     *
      * @param wrappedKey
      *            the wrapped key to unwrap.
      * @param wrappedKeyAlgorithm
@@ -559,7 +529,6 @@
      * @throws NoSuchAlgorithmException
      *             if no provider can be found that can create a key of type
      *             {@code wrappedKeyType} for the {@code wrappedKeyAlgorithm}.
-     * @since Android 1.0
      */
     protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
             int wrappedKeyType) throws InvalidKeyException,
@@ -573,17 +542,16 @@
      * added to this class (for backwards compatibility, it cannot be abstract).
      * If this method is not overridden, it throws an {@code
      * UnsupportedOperationException}.
-     * 
+     *
      * @param key
      *            the key to get the size for.
      * @return the size of a specified key object in bits.
      * @throws InvalidKeyException
      *             if the size of the key cannot be determined by this
      *             implementation.
-     * @since Android 1.0
      */
     protected int engineGetKeySize(Key key) throws InvalidKeyException {
         throw new UnsupportedOperationException(
                 Messages.getString("crypto.12")); //$NON-NLS-1$
     }
-}
+}
\ No newline at end of file
diff --git a/libcore/crypto/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java b/libcore/crypto/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java
index 301cd49..2d0fd25 100644
--- a/libcore/crypto/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java
+++ b/libcore/crypto/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java
@@ -46,7 +46,6 @@
  * #8 - Private-Key Information Syntax Standard</a>.
  * <p>
  * The definition of ASN.1 is as follows:
- * </p>
  * <dl>
  * EncryptedPrivateKeyInfo ::= SEQUENCE {
  * <dd>encryptionAlgorithm AlgorithmIdentifier,</dd>
@@ -57,8 +56,6 @@
  * <dd>algorithm OBJECT IDENTIFIER,</dd>
  * <dd>parameters ANY DEFINED BY algorithm OPTIONAL }</dd>
  * </dl>
- * 
- * @since Android 1.0
  */
 public class EncryptedPrivateKeyInfo {
     // Encryption algorithm name
@@ -75,14 +72,13 @@
     /**
      * Creates an {@code EncryptedPrivateKeyInfo} instance from its encoded
      * representation by parsing it.
-     * 
+     *
      * @param encoded
      *            the encoded representation of this object
      * @throws IOException
      *             if parsing the encoded representation fails.
      * @throws NullPointerException
      *             if {@code encoded} is {@code null}.
-     * @since Android 1.0
      */
     public EncryptedPrivateKeyInfo(byte[] encoded)
             throws IOException {
@@ -127,7 +123,7 @@
     /**
      * Creates an {@code EncryptedPrivateKeyInfo} instance from an algorithm
      * name and its encrypted data.
-     * 
+     *
      * @param encrAlgName
      *            the name of an algorithm.
      * @param encryptedData
@@ -139,7 +135,6 @@
      *             null}.
      * @throws IllegalArgumentException
      *             if {@code encryptedData} is empty.
-     * @since Android 1.0
      */
     public EncryptedPrivateKeyInfo(String encrAlgName, byte[] encryptedData)
         throws NoSuchAlgorithmException {
@@ -166,7 +161,7 @@
     /**
      * Creates an {@code EncryptedPrivateKeyInfo} instance from the
      * encryption algorithm parameters an its encrypted data.
-     * 
+     *
      * @param algParams
      *            the encryption algorithm parameters.
      * @param encryptedData
@@ -177,7 +172,6 @@
      * @throws NullPointerException
      *             if {@code algParams} or {@code encryptedData} is
      *             {@code null}.
-     * @since Android 1.0
      */
     public EncryptedPrivateKeyInfo(AlgorithmParameters algParams,
             byte[] encryptedData)
@@ -204,9 +198,8 @@
 
     /**
      * Returns the name of the encryption algorithm.
-     * 
+     *
      * @return the name of the encryption algorithm.
-     * @since Android 1.0
      */
     public String getAlgName() {
         return algName;
@@ -214,9 +207,8 @@
 
     /**
      * Returns the parameters used by the encryption algorithm.
-     * 
+     *
      * @return the parameters used by the encryption algorithm.
-     * @since Android 1.0
      */
     public AlgorithmParameters getAlgParameters() {
         return algParameters;
@@ -224,10 +216,9 @@
 
     /**
      * Returns the encrypted data of this key.
-     * 
+     *
      * @return the encrypted data of this key, each time this method is called a
      *         new array is returned.
-     * @since Android 1.0
      */
     public byte[] getEncryptedData() {
         byte[] ret = new byte[encryptedData.length];
@@ -242,8 +233,7 @@
      * The cipher must be initialize in either {@code Cipher.DECRYPT_MODE} or
      * {@code Cipher.UNWRAP_MODE} with the same parameters and key used for
      * encrypting this.
-     * </p>
-     * 
+     *
      * @param cipher
      *            the cipher initialized for decrypting the encrypted data.
      * @return the extracted {@code PKCS8EncodedKeySpec}.
@@ -252,7 +242,6 @@
      *             encrypted data.
      * @throws NullPointerException
      *             if {@code cipher} is {@code null}.
-     * @since Android 1.0
      */
     public PKCS8EncodedKeySpec getKeySpec(Cipher cipher)
         throws InvalidKeySpecException {
@@ -280,7 +269,7 @@
     /**
      * Returns the {@code PKCS8EncodedKeySpec} object extracted from the
      * encrypted data.
-     * 
+     *
      * @param decryptKey
      *            the key to decrypt the encrypted data with.
      * @return the extracted {@code PKCS8EncodedKeySpec}.
@@ -292,7 +281,6 @@
      *             data.
      * @throws NullPointerException
      *             if {@code decryptKey} is {@code null}.
-     * @since Android 1.0
      */
     public PKCS8EncodedKeySpec getKeySpec(Key decryptKey)
         throws NoSuchAlgorithmException,
@@ -331,7 +319,7 @@
     /**
      * Returns the {@code PKCS8EncodedKeySpec} object extracted from the
      * encrypted data.
-     * 
+     *
      * @param decryptKey
      *            the key to decrypt the encrypted data with.
      * @param providerName
@@ -349,7 +337,6 @@
      * @throws NullPointerException
      *             if {@code decryptKey} or {@code providerName} is {@code null}
      *             .
-     * @since Android 1.0
      */
     public PKCS8EncodedKeySpec getKeySpec(Key decryptKey, String providerName)
         throws NoSuchProviderException, 
@@ -393,7 +380,7 @@
     /**
      * Returns the {@code PKCS8EncodedKeySpec} object extracted from the
      * encrypted data.
-     * 
+     *
      * @param decryptKey
      *            the key to decrypt the encrypted data with.
      * @param provider
@@ -407,7 +394,6 @@
      *             data.
      * @throws NullPointerException
      *             if {@code decryptKey} or {@code provider} is {@code null}.
-     * @since Android 1.0
      */
     public PKCS8EncodedKeySpec getKeySpec(Key decryptKey, Provider provider)
         throws NoSuchAlgorithmException,
@@ -448,11 +434,10 @@
 
     /**
      * Returns the ASN.1 encoded representation of this object.
-     * 
+     *
      * @return the ASN.1 encoded representation of this object.
      * @throws IOException
      *             if encoding this object fails.
-     * @since Android 1.0
      */
     public byte[] getEncoded() throws IOException {
         if (encoded == null) {
diff --git a/libcore/crypto/src/main/java/javax/crypto/ExemptionMechanism.java b/libcore/crypto/src/main/java/javax/crypto/ExemptionMechanism.java
index 7c68d28..76c88cb 100644
--- a/libcore/crypto/src/main/java/javax/crypto/ExemptionMechanism.java
+++ b/libcore/crypto/src/main/java/javax/crypto/ExemptionMechanism.java
@@ -34,8 +34,6 @@
 /**
  * This class implements the functionality of an exemption mechanism such as
  * <i>key recovery</i>, <i>key weakening</i>, or <i>key escrow</i>.
- * 
- * @since Android 1.0
  */
 public class ExemptionMechanism {
 
@@ -62,14 +60,13 @@
 
     /**
      * Creates a {@code ExemptionMechanism} instance.
-     * 
+     *
      * @param exmechSpi
      *            the implementation delegate.
      * @param provider
      *            the associated provider.
      * @param mechanism
      *            the name of the mechanism.
-     * @since Android 1.0
      */
     protected ExemptionMechanism(ExemptionMechanismSpi exmechSpi,
             Provider provider, String mechanism) {
@@ -81,9 +78,8 @@
 
     /**
      * Returns the name of this {@code ExemptionMechanism}.
-     * 
+     *
      * @return the name of this {@code ExemptionMechanism}.
-     * @since Android 1.0
      */
     public final String getName() {
         return mechanism;
@@ -92,7 +88,7 @@
     /**
      * Returns a new {@code ExemptionMechanism} instance that provides the
      * specified exemption mechanism algorithm.
-     * 
+     *
      * @param algorithm
      *            the name of the requested exemption mechanism.
      * @return the new {@code ExemptionMechanism} instance.
@@ -100,7 +96,6 @@
      *             if the specified algorithm is not available by any provider.
      * @throws NullPointerException
      *             if the algorithm parameter is {@code null}.
-     * @since Android 1.0
      */
     public static final ExemptionMechanism getInstance(String algorithm)
             throws NoSuchAlgorithmException {
@@ -117,7 +112,7 @@
     /**
      * Returns a new {@code ExemptionMechansm} instance that provides the
      * specified exemption mechanism algorithm from the specified provider.
-     * 
+     *
      * @param algorithm
      *            the name of the requested exemption mechanism.
      * @param provider
@@ -132,7 +127,6 @@
      *             if the algorithm parameter is {@code null}.
      * @throws IllegalArgumentException
      *             if the provider parameter is {@code null}.
-     * @since Android 1.0
      */
     public static final ExemptionMechanism getInstance(String algorithm,
             String provider) throws NoSuchAlgorithmException,
@@ -153,7 +147,7 @@
     /**
      * Returns a new {@code ExemptionMechanism} instance that provides the
      * specified exemption mechanism algorithm from the specified provider.
-     * 
+     *
      * @param algorithm
      *            the name of the requested exemption mechanism.
      * @param provider
@@ -166,7 +160,6 @@
      *             if the algorithm parameter is {@code null}.
      * @throws IllegalArgumentException
      *             if the provider parameter is {@code null}.
-     * @since Android 1.0
      */
     public static final ExemptionMechanism getInstance(String algorithm,
             Provider provider) throws NoSuchAlgorithmException {
@@ -185,9 +178,8 @@
 
     /**
      * Returns the provider of this {@code ExemptionMechanism} instance.
-     * 
+     *
      * @return the provider of this {@code ExemptionMechanism} instance.
-     * @since Android 1.0
      */
     public final Provider getProvider() {
         return provider;
@@ -197,7 +189,7 @@
      * Returns whether the result blob for this {@code ExemptionMechanism}
      * instance has been generated successfully and that the specified key is
      * the same as the one that was used to initialize and generate.
-     * 
+     *
      * @param key
      *            the key to verify.
      * @return whether the result blob for this {@code ExemptionMechanism}
@@ -205,7 +197,6 @@
      * @throws ExemptionMechanismException
      *             if an error occurs while determining whether the result blob
      *             has been generated successfully.
-     * @since Android 1.0
      */
     public final boolean isCryptoAllowed(Key key)
             throws ExemptionMechanismException {
@@ -222,14 +213,13 @@
      * Returns the size in bytes for the output buffer needed to hold the output
      * of the next {@link #genExemptionBlob} call, given the specified {@code
      * inputLen} (in bytes).
-     * 
+     *
      * @param inputLen
      *            the specified input length (in bytes).
      * @return the size in bytes for the output buffer.
      * @throws IllegalStateException
      *             if this {@code ExemptionMechanism} instance is not
      *             initialized.
-     * @since Android 1.0
      */
     public final int getOutputSize(int inputLen) throws IllegalStateException {
         if (!isInit) {
@@ -241,14 +231,13 @@
     /**
      * Initializes this {@code ExemptionMechanism} instance with the
      * specified key.
-     * 
+     *
      * @param key
      *            the key to initialize this instance with.
      * @throws InvalidKeyException
      *             if the key cannot be used to initialize this mechanism.
      * @throws ExemptionMechanismException
      *             if error(s) occur during initialization.
-     * @since Android 1.0
      */
     public final void init(Key key) throws InvalidKeyException,
             ExemptionMechanismException {
@@ -261,7 +250,7 @@
     /**
      * Initializes this {@code ExemptionMechanism} instance with the
      * specified key and algorithm parameters.
-     * 
+     *
      * @param key
      *            the key to initialize this instance with.
      * @param param
@@ -273,7 +262,6 @@
      *             mechanism.
      * @throws ExemptionMechanismException
      *             if error(s) occur during initialization.
-     * @since Android 1.0
      */
     public final void init(Key key, AlgorithmParameters param)
             throws InvalidKeyException, InvalidAlgorithmParameterException,
@@ -287,7 +275,7 @@
     /**
      * Initializes this {@code ExemptionMechanism} instance with the
      * specified key and algorithm parameters.
-     * 
+     *
      * @param key
      *            the key to initialize this instance with.
      * @param param
@@ -299,7 +287,6 @@
      *             mechanism.
      * @throws ExemptionMechanismException
      *             if error(s) occur during initialization.
-     * @since Android 1.0
      */
     public final void init(Key key, AlgorithmParameterSpec param)
             throws InvalidKeyException, InvalidAlgorithmParameterException,
@@ -312,14 +299,13 @@
 
     /**
      * Generates the result key blob for this exemption mechanism.
-     * 
+     *
      * @return the result key blob for this exemption mechanism.
      * @throws IllegalStateException
      *             if this {@code ExemptionMechanism} instance is not
      *             initialized.
      * @throws ExemptionMechanismException
      *             if error(s) occur during generation.
-     * @since Android 1.0
      */
     public final byte[] genExemptionBlob() throws IllegalStateException,
             ExemptionMechanismException {
@@ -335,7 +321,7 @@
     /**
      * Generates the result key blob for this exemption mechanism and stores it
      * into the {@code output} buffer.
-     * 
+     *
      * @param output
      *            the output buffer for the result key blob.
      * @return the number of bytes written to the {@code output} buffer.
@@ -346,7 +332,6 @@
      *             if the provided buffer is too small for the result key blob.
      * @throws ExemptionMechanismException
      *             if error(s) occur during generation.
-     * @since Android 1.0
      */
     public final int genExemptionBlob(byte[] output)
             throws IllegalStateException, ShortBufferException,
@@ -357,7 +342,7 @@
     /**
      * Generates the result key blob for this exemption mechanism and stores it
      * into the {@code output} buffer at offset {@code outputOffset}.
-     * 
+     *
      * @param output
      *            the output buffer for the result key blob.
      * @param outputOffset
@@ -370,7 +355,6 @@
      *             if the provided buffer is too small for the result key blob.
      * @throws ExemptionMechanismException
      *             if error(s) occur during generation.
-     * @since Android 1.0
      */
     public final int genExemptionBlob(byte[] output, int outputOffset)
             throws IllegalStateException, ShortBufferException,
@@ -386,8 +370,6 @@
 
     /**
      * Frees the references to the key used to initialize this instance.
-     * 
-     * @since Android 1.0
      */
     @Override
     protected void finalize() {
diff --git a/libcore/crypto/src/main/java/javax/crypto/ExemptionMechanismException.java b/libcore/crypto/src/main/java/javax/crypto/ExemptionMechanismException.java
index 3af498b..d094ac3 100644
--- a/libcore/crypto/src/main/java/javax/crypto/ExemptionMechanismException.java
+++ b/libcore/crypto/src/main/java/javax/crypto/ExemptionMechanismException.java
@@ -21,8 +21,6 @@
 
 /**
  * This is the base class for {@code ExemptionMechanismException}.
- * 
- * @since Android 1.0
  */
 public class ExemptionMechanismException extends GeneralSecurityException {
 
@@ -37,7 +35,6 @@
      * 
      * @param msg
      *            the exception message.
-     * @since Android 1.0
      */
     public ExemptionMechanismException(String msg) {
         super(msg);
@@ -45,8 +42,6 @@
 
     /**
      * Creates a new {@code ExemptionMechanismException} with no message.
-     * 
-     * @since Android 1.0
      */
     public ExemptionMechanismException() {
     }
diff --git a/libcore/crypto/src/main/java/javax/crypto/ExemptionMechanismSpi.java b/libcore/crypto/src/main/java/javax/crypto/ExemptionMechanismSpi.java
index cef1516..39a27f6 100644
--- a/libcore/crypto/src/main/java/javax/crypto/ExemptionMechanismSpi.java
+++ b/libcore/crypto/src/main/java/javax/crypto/ExemptionMechanismSpi.java
@@ -26,26 +26,21 @@
 /**
  * The <i>Service Provider Interface</i> (<b>SPI</b>) definition for the {@code
  * ExemptionMechanism} class.
- * 
- * @since Android 1.0
  */
 public abstract class ExemptionMechanismSpi {
 
     /**
      * Creates a new {@code ExemptionMechanismSpi} instance.
-     * 
-     * @since Android 1.0
      */
     public ExemptionMechanismSpi() {
     }
 
     /**
      * Generates the result key blob for this exemption mechanism.
-     * 
+     *
      * @return the result key blob for this exemption mechanism.
      * @throws ExemptionMechanismException
      *             if error(s) occur during generation.
-     * @since Android 1.0
      */
     protected abstract byte[] engineGenExemptionBlob()
             throws ExemptionMechanismException;
@@ -53,7 +48,7 @@
     /**
      * Generates the result key blob for this exemption mechanism and stores it
      * into the {@code output} buffer at offset {@code outputOffset}.
-     * 
+     *
      * @param output
      *            the output buffer for the result key blob.
      * @param outputOffset
@@ -63,7 +58,6 @@
      *             if the provided buffer is too small for the result key blob.
      * @throws ExemptionMechanismException
      *             if error(s) occur during generation.
-     * @since Android 1.0
      */
     protected abstract int engineGenExemptionBlob(byte[] output,
             int outputOffset) throws ShortBufferException,
@@ -73,7 +67,7 @@
      * Returns the size in bytes for the output buffer needed to hold the output
      * of the next {@link #engineGenExemptionBlob} call, given the specified
      * {@code inputLen} (in bytes).
-     * 
+     *
      * @param inputLen
      *            the specified input length (in bytes).
      * @return the size in bytes for the output buffer.
@@ -83,14 +77,13 @@
     /**
      * Initializes this {@code ExemptionMechanism} instance with the specified
      * key.
-     * 
+     *
      * @param key
      *            the key to initialize this instance with.
      * @throws InvalidKeyException
      *             if the key cannot be used to initialize this mechanism.
      * @throws ExemptionMechanismException
      *             if error(s) occur during initialization.
-     * @since Android 1.0
      */
     protected abstract void engineInit(Key key) throws InvalidKeyException,
             ExemptionMechanismException;
@@ -98,7 +91,7 @@
     /**
      * Initializes this {@code ExemptionMechanism} instance with the specified
      * key and algorithm parameters.
-     * 
+     *
      * @param key
      *            the key to initialize this instance with.
      * @param params
@@ -110,7 +103,6 @@
      *             mechanism.
      * @throws ExemptionMechanismException
      *             if error(s) occur during initialization.
-     * @since Android 1.0
      */
     protected abstract void engineInit(Key key, AlgorithmParameters params)
             throws InvalidKeyException, InvalidAlgorithmParameterException,
@@ -119,7 +111,7 @@
     /**
      * Initializes this {@code ExemptionMechanism} instance with the specified
      * key and algorithm parameters.
-     * 
+     *
      * @param key
      *            the key to initialize this instance with.
      * @param params
@@ -131,7 +123,6 @@
      *             mechanism.
      * @throws ExemptionMechanismException
      *             if error(s) occur during initialization.
-     * @since Android 1.0
      */
     protected abstract void engineInit(Key key, AlgorithmParameterSpec params)
             throws InvalidKeyException, InvalidAlgorithmParameterException,
diff --git a/libcore/crypto/src/main/java/javax/crypto/IllegalBlockSizeException.java b/libcore/crypto/src/main/java/javax/crypto/IllegalBlockSizeException.java
index e376b85..0766b7c 100644
--- a/libcore/crypto/src/main/java/javax/crypto/IllegalBlockSizeException.java
+++ b/libcore/crypto/src/main/java/javax/crypto/IllegalBlockSizeException.java
@@ -22,8 +22,6 @@
 /**
  * The exception, that is thrown when the data length provided to a block cipher
  * does not match the block size of the cipher.
- * 
- * @since Android 1.0
  */
 public class IllegalBlockSizeException extends GeneralSecurityException {
 
@@ -38,7 +36,6 @@
      * 
      * @param msg
      *            the message
-     * @since Android 1.0
      */
     public IllegalBlockSizeException(String msg) {
         super(msg);
@@ -46,8 +43,6 @@
 
     /**
      * Creates a new {@code IllegalBlockSizeException}.
-     * 
-     * @since Android 1.0
      */
     public IllegalBlockSizeException() {
     }
diff --git a/libcore/crypto/src/main/java/javax/crypto/KeyAgreement.java b/libcore/crypto/src/main/java/javax/crypto/KeyAgreement.java
index ee1f195..593aa37 100644
--- a/libcore/crypto/src/main/java/javax/crypto/KeyAgreement.java
+++ b/libcore/crypto/src/main/java/javax/crypto/KeyAgreement.java
@@ -34,8 +34,6 @@
  * This class provides the functionality for a key exchange protocol. This
  * enables two or more parties to agree on a secret key for symmetric
  * cryptography.
- * 
- * @since Android 1.0
  */
 public class KeyAgreement {
 
@@ -56,14 +54,13 @@
 
     /**
      * Creates a new {@code KeyAgreement} instance.
-     * 
+     *
      * @param keyAgreeSpi
      *            the <b>SPI</b> delegate.
      * @param provider
      *            the provider providing this KeyAgreement.
      * @param algorithm
      *            the name of the key agreement algorithm.
-     * @since Android 1.0
      */
     protected KeyAgreement(KeyAgreementSpi keyAgreeSpi, Provider provider,
             String algorithm) {
@@ -74,9 +71,8 @@
 
     /**
      * Returns the name of the key agreement algorithm.
-     * 
+     *
      * @return the name of the key agreement algorithm.
-     * @since Android 1.0
      */
     public final String getAlgorithm() {
         return algorithm;
@@ -84,9 +80,8 @@
 
     /**
      * Returns the provider for this {@code KeyAgreement} instance.
-     * 
+     *
      * @return the provider for this {@code KeyAgreement} instance.
-     * @since Android 1.0
      */
     public final Provider getProvider() {
         return provider;
@@ -94,7 +89,7 @@
 
     /**
      * Creates a new {@code KeyAgreement} for the specified algorithm.
-     * 
+     *
      * @param algorithm
      *            the name of the key agreement algorithm to create.
      * @return a key agreement for the specified algorithm.
@@ -102,7 +97,6 @@
      *             if no installed provider can provide the requested algorithm.
      * @throws NullPointerException
      *             if the specified algorithm is {@code null}.
-     * @since Android 1.0
      */
     public static final KeyAgreement getInstance(String algorithm)
             throws NoSuchAlgorithmException {
@@ -119,7 +113,7 @@
     /**
      * Creates a new {@code KeyAgreement} for the specified algorithm from the
      * specified provider.
-     * 
+     *
      * @param algorithm
      *            the name of the key agreement algorithm to create.
      * @param provider
@@ -134,7 +128,6 @@
      *             if the specified provider does not exist.
      * @throws IllegalArgumentException
      *             if the specified provider name is {@code null} or empty.
-     * @since Android 1.0
      */
     public static final KeyAgreement getInstance(String algorithm,
             String provider) throws NoSuchAlgorithmException,
@@ -152,7 +145,7 @@
     /**
      * Create a new {@code KeyAgreement} for the specified algorithm from the
      * specified provider.
-     * 
+     *
      * @param algorithm
      *            the name of the key agreement algorithm to create.
      * @param provider
@@ -184,13 +177,12 @@
 
     /**
      * Initializes this {@code KeyAgreement} with the specified key.
-     * 
+     *
      * @param key
      *            the key to initialize this key agreement.
      * @throws InvalidKeyException
      *             if the specified key cannot be used to initialize this key
      *             agreement.
-     * @since Android 1.0
      */
     public final void init(Key key) throws InvalidKeyException {
         spiImpl.engineInit(key, rndm);//new SecureRandom());
@@ -199,7 +191,7 @@
     /**
      * Initializes this {@code KeyAgreement} with the specified key and the
      * specified randomness source.
-     * 
+     *
      * @param key
      *            the key to initialize this key agreement.
      * @param random
@@ -207,7 +199,6 @@
      * @throws InvalidKeyException
      *             if the specified key cannot be used to initialize this key
      *             agreement.
-     * @since Android 1.0
      */
     public final void init(Key key, SecureRandom random)
             throws InvalidKeyException {
@@ -217,7 +208,7 @@
     /**
      * Initializes this {@code KeyAgreement} with the specified key and the
      * algorithm parameters.
-     * 
+     *
      * @param key
      *            the key to initialize this key agreement.
      * @param params
@@ -228,7 +219,6 @@
      * @throws InvalidAlgorithmParameterException
      *             if the specified parameters are invalid for this key
      *             agreement algorithm.
-     * @since Android 1.0
      */
     public final void init(Key key, AlgorithmParameterSpec params)
             throws InvalidKeyException, InvalidAlgorithmParameterException {
@@ -238,7 +228,7 @@
     /**
      * Initializes this {@code KeyAgreement} with the specified key, algorithm
      * parameters and randomness source.
-     * 
+     *
      * @param key
      *            the key to initialize this key agreement.
      * @param params
@@ -251,7 +241,6 @@
      * @throws InvalidAlgorithmParameterException
      *             if the specified parameters are invalid for this key
      *             agreement algorithm.
-     * @since Android 1.0
      */
     public final void init(Key key, AlgorithmParameterSpec params,
             SecureRandom random) throws InvalidKeyException,
@@ -262,7 +251,7 @@
     /**
      * Does the next (or the last) phase of the key agreement, using the
      * specified key.
-     * 
+     *
      * @param key
      *            the key received from the other party for this phase.
      * @param lastPhase
@@ -275,7 +264,6 @@
      *             this phase,
      * @throws IllegalStateException
      *             if this instance has not been initialized.
-     * @since Android 1.0
      */
     public final Key doPhase(Key key, boolean lastPhase)
             throws InvalidKeyException, IllegalStateException {
@@ -284,11 +272,10 @@
 
     /**
      * Generates the shared secret.
-     * 
+     *
      * @return the generated shared secret.
      * @throws IllegalStateException
      *             if this key agreement is not complete.
-     * @since Android 1.0
      */
     public final byte[] generateSecret() throws IllegalStateException {
         return spiImpl.engineGenerateSecret();
@@ -297,7 +284,7 @@
     /**
      * Generates the shared secret and stores it into the buffer {@code
      * sharedSecred} at {@code offset}.
-     * 
+     *
      * @param sharedSecret
      *            the buffer to store the shared secret.
      * @param offset
@@ -307,7 +294,6 @@
      *             if this key agreement is not complete.
      * @throws ShortBufferException
      *             if the specified buffer is too small for the shared secret.
-     * @since Android 1.0
      */
     public final int generateSecret(byte[] sharedSecret, int offset)
             throws IllegalStateException, ShortBufferException {
@@ -316,7 +302,7 @@
 
     /**
      * Generates the shared secret.
-     * 
+     *
      * @param algorithm
      *            the algorithm to for the {@code SecretKey}
      * @return the shared secret as a {@code SecretKey} of the specified
@@ -329,7 +315,6 @@
      * @throws InvalidKeyException
      *             if a {@code SecretKey} with the specified algorithm cannot be
      *             created using the generated shared secret.
-     * @since Android 1.0
      */
     public final SecretKey generateSecret(String algorithm)
             throws IllegalStateException, NoSuchAlgorithmException,
diff --git a/libcore/crypto/src/main/java/javax/crypto/KeyAgreementSpi.java b/libcore/crypto/src/main/java/javax/crypto/KeyAgreementSpi.java
index fa9f377..5011183 100644
--- a/libcore/crypto/src/main/java/javax/crypto/KeyAgreementSpi.java
+++ b/libcore/crypto/src/main/java/javax/crypto/KeyAgreementSpi.java
@@ -27,15 +27,11 @@
 /**
  * The <i>Service Provider Interface</i> (<b>SPI</b>) definition for the
  * {@code KeyAgreement} class.
- * 
- * @since Android 1.0
  */
 public abstract class KeyAgreementSpi {
- 
+
     /**
      * Creates a new {@code KeyAgreementSpi} instance.
-     * 
-     * @since Android 1.0
      */
     public KeyAgreementSpi() {
     }
@@ -43,7 +39,7 @@
     /**
      * Does the next (or the last) phase of the key agreement, using the
      * specified key.
-     * 
+     *
      * @param key
      *            the key received from the other party for this phase.
      * @param lastPhase
@@ -56,18 +52,16 @@
      *             this phase,
      * @throws IllegalStateException
      *             if this instance has not been initialized.
-     * @since Android 1.0
      */
     protected abstract Key engineDoPhase(Key key, boolean lastPhase)
             throws InvalidKeyException, IllegalStateException;
 
     /**
      * Generates the shared secret.
-     * 
+     *
      * @return the generated shared secret.
      * @throws IllegalStateException
      *             if this key agreement is not complete.
-     * @since Android 1.0
      */
     protected abstract byte[] engineGenerateSecret()
             throws IllegalStateException;
@@ -75,7 +69,7 @@
     /**
      * Generates the shared secret and stores it into the buffer {@code
      * sharedSecred} at {@code offset}.
-     * 
+     *
      * @param sharedSecret
      *            the buffer to store the shared secret.
      * @param offset
@@ -85,14 +79,13 @@
      *             if this key agreement is not complete.
      * @throws ShortBufferException
      *             if the specified buffer is too small for the shared secret.
-     * @since Android 1.0
      */
     protected abstract int engineGenerateSecret(byte[] sharedSecret, int offset)
             throws IllegalStateException, ShortBufferException;
 
     /**
      * Generates the shared secret.
-     * 
+     *
      * @param algorithm
      *            the algorithm to for the {@code SecretKey}
      * @return the shared secret as a {@code SecretKey} of the specified
@@ -105,7 +98,6 @@
      * @throws InvalidKeyException
      *             if a {@code SecretKey} with the specified algorithm cannot be
      *             created using the generated shared secret.
-     * @since Android 1.0
      */
     protected abstract SecretKey engineGenerateSecret(String algorithm)
             throws IllegalStateException, NoSuchAlgorithmException,
@@ -114,7 +106,7 @@
     /**
      * Initializes this {@code KeyAgreementSpi} with the specified key and the
      * specified randomness source.
-     * 
+     *
      * @param key
      *            the key to initialize this key agreement.
      * @param random
@@ -122,7 +114,6 @@
      * @throws InvalidKeyException
      *             if the specified key cannot be used to initialize this key
      *             agreement.
-     * @since Android 1.0
      */
     protected abstract void engineInit(Key key, SecureRandom random)
             throws InvalidKeyException;
@@ -130,7 +121,7 @@
     /**
      * Initializes this {@code KeyAgreementSpi} with the specified key,
      * algorithm parameters and randomness source.
-     * 
+     *
      * @param key
      *            the key to initialize this key agreement.
      * @param params
@@ -143,7 +134,6 @@
      * @throws InvalidAlgorithmParameterException
      *             if the specified parameters are invalid for this key
      *             agreement algorithm.
-     * @since Android 1.0
      */
     protected abstract void engineInit(Key key, AlgorithmParameterSpec params,
             SecureRandom random) throws InvalidKeyException,
diff --git a/libcore/crypto/src/main/java/javax/crypto/KeyGenerator.java b/libcore/crypto/src/main/java/javax/crypto/KeyGenerator.java
index 3243b39..f1dd3b2 100644
--- a/libcore/crypto/src/main/java/javax/crypto/KeyGenerator.java
+++ b/libcore/crypto/src/main/java/javax/crypto/KeyGenerator.java
@@ -32,8 +32,6 @@
 /**
  * This class provides the public API for generating symmetric cryptographic
  * keys.
- * 
- * @since Android 1.0
  */
 public class KeyGenerator {
 
@@ -54,14 +52,13 @@
 
     /**
      * Creates a new {@code KeyGenerator} instance.
-     * 
+     *
      * @param keyGenSpi
      *            the implementation delegate.
      * @param provider
      *            the implementation provider.
      * @param algorithm
      *            the name of the algorithm.
-     * @since Android 1.0
      */
     protected KeyGenerator(KeyGeneratorSpi keyGenSpi, Provider provider,
             String algorithm) {
@@ -72,9 +69,8 @@
 
     /**
      * Returns the name of the key generation algorithm.
-     * 
+     *
      * @return the name of the key generation algorithm.
-     * @since Android 1.0
      */
     public final String getAlgorithm() {
         return algorithm;
@@ -82,9 +78,8 @@
 
     /**
      * Returns the provider of this {@code KeyGenerator} instance.
-     * 
+     *
      * @return the provider of this {@code KeyGenerator} instance.
-     * @since Android 1.0
      */
     public final Provider getProvider() {
         return provider;
@@ -93,7 +88,7 @@
     /**
      * Creates a new {@code KeyGenerator} instance that provides the specified
      * key algorithm,
-     * 
+     *
      * @param algorithm
      *            the name of the requested key algorithm
      * @return the new {@code KeyGenerator} instance.
@@ -101,7 +96,6 @@
      *             if the specified algorithm is not available by any provider.
      * @throws NullPointerException
      *             if {@code algorithm} is {@code null}.
-     * @since Android 1.0
      */
     public static final KeyGenerator getInstance(String algorithm)
             throws NoSuchAlgorithmException {
@@ -118,7 +112,7 @@
     /**
      * Creates a new {@code KeyGenerator} instance that provides the specified
      * key algorithm from the specified provider.
-     * 
+     *
      * @param algorithm
      *            the name of the requested key algorithm.
      * @param provider
@@ -133,7 +127,6 @@
      *             if the specified provider is name is {@code null} or empty.
      * @throws NullPointerException
      *             if the specified algorithm name is {@code null}.
-     * @since Android 1.0
      */
     public static final KeyGenerator getInstance(String algorithm,
             String provider) throws NoSuchAlgorithmException,
@@ -151,7 +144,7 @@
     /**
      * Creates a new {@code KeyGenerator} instance that provides the specified
      * key algorithm from the specified provider.
-     * 
+     *
      * @param algorithm
      *            the name of the requested key algorithm.
      * @param provider
@@ -164,7 +157,6 @@
      *             if the specified provider is {@code null}.
      * @throws NullPointerException
      *             if the specified algorithm name is {@code null}.
-     * @since Android 1.0
      */
     public static final KeyGenerator getInstance(String algorithm,
             Provider provider) throws NoSuchAlgorithmException {
@@ -183,9 +175,8 @@
 
     /**
      * Generates a secret key.
-     * 
+     *
      * @return the generated secret key.
-     * @since Android 1.0
      */
     public final SecretKey generateKey() {
         return spiImpl.engineGenerateKey();
@@ -194,13 +185,12 @@
     /**
      * Initializes this {@code KeyGenerator} instance with the specified
      * algorithm parameters.
-     * 
+     *
      * @param params
      *            the parameters for the key generation algorithm.
      * @throws InvalidAlgorithmParameterException
      *             if the parameters cannot be used to initialize this key
      *             generator algorithm.
-     * @since Android 1.0
      */
     public final void init(AlgorithmParameterSpec params)
             throws InvalidAlgorithmParameterException {
@@ -210,7 +200,7 @@
     /**
      * Initializes this {@code KeyGenerator} instance with the specified
      * algorithm parameters and randomness source.
-     * 
+     *
      * @param params
      *            the parameters for the key generation algorithm.
      * @param random
@@ -218,7 +208,6 @@
      * @throws InvalidAlgorithmParameterException
      *             if the parameters cannot be uses to initialize this key
      *             generator algorithm.
-     * @since Android 1.0
      */
     public final void init(AlgorithmParameterSpec params, SecureRandom random)
             throws InvalidAlgorithmParameterException {
@@ -228,10 +217,9 @@
     /**
      * Initializes this {@code KeyGenerator} instance for the specified key size
      * (in bits).
-     * 
+     *
      * @param keysize
      *            the size of the key (in bits).
-     * @since Android 1.0
      */
     public final void init(int keysize) {
         spiImpl.engineInit(keysize, rndm);//new SecureRandom());
@@ -240,12 +228,11 @@
     /**
      * Initializes this {@code KeyGenerator} instance for the specified key size
      * (in bits) using the specified randomness source.
-     * 
+     *
      * @param keysize
      *            the size of the key (in bits).
      * @param random
      *            the randomness source for any random bytes.
-     * @since Android 1.0
      */
     public final void init(int keysize, SecureRandom random) {
         spiImpl.engineInit(keysize, random);
@@ -254,10 +241,9 @@
     /**
      * Initializes this {@code KeyGenerator} with the specified randomness
      * source.
-     * 
+     *
      * @param random
      *            the randomness source for any random bytes.
-     * @since Android 1.0
      */
     public final void init(SecureRandom random) {
         spiImpl.engineInit(random);
diff --git a/libcore/crypto/src/main/java/javax/crypto/KeyGeneratorSpi.java b/libcore/crypto/src/main/java/javax/crypto/KeyGeneratorSpi.java
index 165db69..edbbe43 100644
--- a/libcore/crypto/src/main/java/javax/crypto/KeyGeneratorSpi.java
+++ b/libcore/crypto/src/main/java/javax/crypto/KeyGeneratorSpi.java
@@ -26,30 +26,26 @@
  * {@code KeyGenerator} class.
  * 
  * @see KeyGenerator
- * @since Android 1.0
  */
 public abstract class KeyGeneratorSpi {
 
     /**
      * Creates a new {@code KeyGeneratorSpi} instance.
-     * 
-     * @since Android 1.0
      */
     public KeyGeneratorSpi() {
     }
 
     /**
      * Generates a secret key.
-     * 
+     *
      * @return the generated secret key.
-     * @since Android 1.0
      */
     protected abstract SecretKey engineGenerateKey();
 
     /**
      * Initializes this {@code KeyGeneratorSpi} instance with the specified
      * algorithm parameters and randomness source.
-     * 
+     *
      * @param params
      *            the parameters for the key generation algorithm.
      * @param random
@@ -57,7 +53,6 @@
      * @throws InvalidAlgorithmParameterException
      *             if the parameters cannot be uses to initialize this key
      *             generator algorithm.
-     * @since Android 1.0
      */
     protected abstract void engineInit(AlgorithmParameterSpec params,
             SecureRandom random) throws InvalidAlgorithmParameterException;
@@ -65,22 +60,20 @@
     /**
      * Initializes this {@code KeyGenerator} instance for the specified key
      * size (in bits) using the specified randomness source.
-     * 
+     *
      * @param keysize
      *            the size of the key (in bits).
      * @param random
      *            the randomness source for any random bytes.
-     * @since Android 1.0
      */
     protected abstract void engineInit(int keysize, SecureRandom random);
 
     /**
      * Initializes this {@code KeyGenerator} with the specified randomness
      * source.
-     * 
+     *
      * @param random
      *            the randomness source for any random bytes.
-     * @since Android 1.0
      */
     protected abstract void engineInit(SecureRandom random);
 }
\ No newline at end of file
diff --git a/libcore/crypto/src/main/java/javax/crypto/Mac.java b/libcore/crypto/src/main/java/javax/crypto/Mac.java
index 95f4539..94ea20e 100644
--- a/libcore/crypto/src/main/java/javax/crypto/Mac.java
+++ b/libcore/crypto/src/main/java/javax/crypto/Mac.java
@@ -34,8 +34,6 @@
 /**
  * This class provides the public API for <i>Message Authentication Code</i>
  * (MAC) algorithms.
- * 
- * @since Android 1.0
  */
 public class Mac implements Cloneable {
 
@@ -56,14 +54,13 @@
 
     /**
      * Creates a new {@code Mac} instance.
-     * 
+     *
      * @param macSpi
      *            the implementation delegate.
      * @param provider
      *            the implementation provider.
      * @param algorithm
      *            the name of the MAC algorithm.
-     * @since Android 1.0
      */
     protected Mac(MacSpi macSpi, Provider provider, String algorithm) {
         this.provider = provider;
@@ -76,7 +73,6 @@
      * Returns the name of the MAC algorithm.
      * 
      * @return the name of the MAC algorithm.
-     * @since Android 1.0
      */
     public final String getAlgorithm() {
         return algorithm;
@@ -84,9 +80,8 @@
 
     /**
      * Returns the provider of this {@code Mac} instance.
-     * 
+     *
      * @return the provider of this {@code Mac} instance.
-     * @since Android 1.0
      */
     public final Provider getProvider() {
         return provider;
@@ -102,8 +97,8 @@
      * @throws NoSuchAlgorithmException
      *             if the specified algorithm is not available by any provider.
      * @throws NullPointerException
-     *             if {@code algorithm} is {@code null}.
-     * @since Android 1.0
+     *             if {@code algorithm} is {@code null} (instead of
+     *             NoSuchAlgorithmException as in 1.4 release).
      */
     public static final Mac getInstance(String algorithm)
             throws NoSuchAlgorithmException {
@@ -133,8 +128,8 @@
      * @throws IllegalArgumentException
      *             if the specified provider name is {@code null} or empty.
      * @throws NullPointerException
-     *             if {@code algorithm} is {@code null}
-     * @since Android 1.0.
+     *             if {@code algorithm} is {@code null} (instead of
+     *             NoSuchAlgorithmException as in 1.4 release).
      */
     public static final Mac getInstance(String algorithm, String provider)
             throws NoSuchAlgorithmException, NoSuchProviderException {
@@ -163,8 +158,8 @@
      * @throws IllegalArgumentException
      *             if {@code provider} is {@code null}.
      * @throws NullPointerException
-     *             if {@code algorithm} is {@code null}.
-     * @since Android 1.0
+     *             if {@code algorithm} is {@code null} (instead of
+     *             NoSuchAlgorithmException as in 1.4 release).
      */
     public static final Mac getInstance(String algorithm, Provider provider)
             throws NoSuchAlgorithmException {
@@ -182,7 +177,7 @@
 
     /**
      * Returns the length of this MAC (in bytes).
-     * 
+     *
      * @return the length of this MAC (in bytes).
      */
     public final int getMacLength() {
@@ -192,7 +187,7 @@
     /**
      * Initializes this {@code Mac} instance with the specified key and
      * algorithm parameters.
-     * 
+     *
      * @param key
      *            the key to initialize this algorithm.
      * @param params
@@ -203,7 +198,6 @@
      * @throws InvalidAlgorithmParameterException
      *             if the specified parameters cannot be used to initialize this
      *             algorithm.
-     * @since Android 1.0
      */
     public final void init(Key key, AlgorithmParameterSpec params)
             throws InvalidKeyException, InvalidAlgorithmParameterException {
@@ -216,7 +210,7 @@
 
     /**
      * Initializes this {@code Mac} instance with the specified key.
-     * 
+     *
      * @param key
      *            the key to initialize this algorithm.
      * @throws InvalidKeyException
@@ -225,7 +219,6 @@
      * @throws RuntimeException
      *             if the specified key cannot be used to initialize this
      *             algorithm.
-     * @since Android 1.0
      */
     public final void init(Key key) throws InvalidKeyException {
         if (key == null) {
@@ -241,12 +234,11 @@
 
     /**
      * Updates this {@code Mac} instance with the specified byte.
-     * 
+     *
      * @param input
      *            the byte
      * @throws IllegalStateException
      *             if this MAC is not initialized.
-     * @since Android 1.0
      */
     public final void update(byte input) throws IllegalStateException {
         if (!isInitMac) {
@@ -258,7 +250,7 @@
     /**
      * Updates this {@code Mac} instance with the data from the specified buffer
      * {@code input} from the specified {@code offset} and length {@code len}.
-     * 
+     *
      * @param input
      *            the buffer.
      * @param offset
@@ -270,7 +262,6 @@
      * @throws IllegalArgumentException
      *             if {@code offset} and {@code len} do not specified a valid
      *             chunk in {@code input} buffer.
-     * @since Android 1.0
      */
     public final void update(byte[] input, int offset, int len)
             throws IllegalStateException {
@@ -288,12 +279,11 @@
 
     /**
      * Copies the buffer provided as input for further processing.
-     * 
+     *
      * @param input
      *            the buffer.
      * @throws IllegalStateException
      *             if this MAC is not initialized.
-     * @since Android 1.0
      */
     public final void update(byte[] input) throws IllegalStateException {
         if (!isInitMac) {
@@ -308,12 +298,11 @@
      * Updates this {@code Mac} instance with the data from the specified
      * buffer, starting at {@link ByteBuffer#position()}, including the next
      * {@link ByteBuffer#remaining()} bytes.
-     * 
+     *
      * @param input
      *            the buffer.
      * @throws IllegalStateException
      *             if this MAC is not initialized.
-     * @since Android 1.0
      */
     public final void update(ByteBuffer input) {
         if (!isInitMac) {
@@ -333,12 +322,10 @@
      * This {@code Mac} instance is reverted to its initial state and can be
      * used to start the next MAC computation with the same parameters or
      * initialized with different parameters.
-     * </p>
-     * 
+     *
      * @return the generated digest.
      * @throws IllegalStateException
      *             if this MAC is not initialized.
-     * @since Android 1.0
      */
     public final byte[] doFinal() throws IllegalStateException {
         if (!isInitMac) {
@@ -355,8 +342,7 @@
      * This {@code Mac} instance is reverted to its initial state and can be
      * used to start the next MAC computation with the same parameters or
      * initialized with different parameters.
-     * </p>
-     * 
+     *
      * @param output
      *            the output buffer
      * @param outOffset
@@ -368,7 +354,6 @@
      *             of the output buffer.
      * @throws IllegalStateException
      *             if this MAC is not initialized.
-     * @since Android 1.0
      */
     public final void doFinal(byte[] output, int outOffset)
             throws ShortBufferException, IllegalStateException {
@@ -401,14 +386,12 @@
      * This {@code Mac} instance is reverted to its initial state and can be
      * used to start the next MAC computation with the same parameters or
      * initialized with different parameters.
-     * </p>
-     * 
+     *
      * @param input
      *            the final bytes.
      * @return the generated digest.
      * @throws IllegalStateException
      *             if this MAC is not initialized.
-     * @since Android 1.0
      */
     public final byte[] doFinal(byte[] input) throws IllegalStateException {
         if (!isInitMac) {
@@ -426,9 +409,6 @@
      * This {@code Mac} instance is reverted to its initial state and can be
      * used to start the next MAC computation with the same parameters or
      * initialized with different parameters.
-     * </p>
-     * 
-     * @since Android 1.0
      */
     public final void reset() {
         spiImpl.engineReset();
@@ -436,11 +416,10 @@
 
     /**
      * Clones this {@code Mac} instance and the underlying implementation.
-     * 
+     *
      * @return the cloned instance.
      * @throws CloneNotSupportedException
      *             if the underlying implementation does not support cloning.
-     * @since Android 1.0
      */
     @Override
     public final Object clone() throws CloneNotSupportedException {
@@ -449,4 +428,4 @@
         mac.isInitMac = this.isInitMac; 
         return mac;
     }
-}
+}
\ No newline at end of file
diff --git a/libcore/crypto/src/main/java/javax/crypto/MacSpi.java b/libcore/crypto/src/main/java/javax/crypto/MacSpi.java
index 4756184..b2683d2 100644
--- a/libcore/crypto/src/main/java/javax/crypto/MacSpi.java
+++ b/libcore/crypto/src/main/java/javax/crypto/MacSpi.java
@@ -28,30 +28,26 @@
  * Mac} class.
  * 
  * @see Mac
- * @since Android 1.0
  */
 public abstract class MacSpi {
-    
+
     /**
      * Creates a new {@code MacSpi} instance.
-     * 
-     * @since Android 1.0
      */
     public MacSpi() {
     }
 
     /**
      * Returns the length of this MAC (in bytes).
-     * 
+     *
      * @return the length of this MAC (in bytes).
-     * @since Android 1.0
      */
     protected abstract int engineGetMacLength();
 
     /**
      * Initializes this {@code MacSpi} instance with the specified key and
      * algorithm parameters.
-     * 
+     *
      * @param key
      *            the key to initialize this algorithm.
      * @param params
@@ -62,17 +58,15 @@
      * @throws InvalidAlgorithmParameterException
      *             if the specified parameters cannot be used to initialize this
      *             algorithm.
-     * @since Android 1.0
      */
     protected abstract void engineInit(Key key, AlgorithmParameterSpec params)
             throws InvalidKeyException, InvalidAlgorithmParameterException;
 
     /**
      * Updates this {@code MacSpi} instance with the specified byte.
-     * 
+     *
      * @param input
      *            the byte.
-     * @since Android 1.0
      */
     protected abstract void engineUpdate(byte input);
 
@@ -80,14 +74,13 @@
      * Updates this {@code MacSpi} instance with the data from the specified
      * buffer {@code input} from the specified {@code offset} and length {@code
      * len}.
-     * 
+     *
      * @param input
      *            the buffer.
      * @param offset
      *            the offset in the buffer.
      * @param len
      *            the length of the data in the buffer.
-     * @since Android 1.0
      */
     protected abstract void engineUpdate(byte[] input, int offset, int len);
 
@@ -95,10 +88,9 @@
      * Updates this {@code MacSpi} instance with the data from the specified
      * buffer, starting at {@link ByteBuffer#position()}, including the next
      * {@link ByteBuffer#remaining()} bytes.
-     * 
+     *
      * @param input
      *            the buffer.
-     * @since Android 1.0
      */
     protected void engineUpdate(ByteBuffer input) {
         if (!input.hasRemaining()) {
@@ -126,10 +118,8 @@
      * This {@code MacSpi} instance is reverted to its initial state and
      * can be used to start the next MAC computation with the same parameters or
      * initialized with different parameters.
-     * </p>
-     * 
+     *
      * @return the generated digest.
-     * @since Android 1.0
      */
     protected abstract byte[] engineDoFinal();
 
@@ -139,19 +129,15 @@
      * This {@code MacSpi} instance is reverted to its initial state and can be
      * used to start the next MAC computation with the same parameters or
      * initialized with different parameters.
-     * </p>
-     * 
-     * @since Android 1.0
      */
     protected abstract void engineReset();
 
     /**
      * Clones this {@code MacSpi} instance.
-     * 
+     *
      * @return the cloned instance.
      * @throws CloneNotSupportedException
      *             if cloning is not supported.
-     * @since Android 1.0
      */
     @Override
     public Object clone() throws CloneNotSupportedException {
diff --git a/libcore/crypto/src/main/java/javax/crypto/NoSuchPaddingException.java b/libcore/crypto/src/main/java/javax/crypto/NoSuchPaddingException.java
index 4afb8ab..55e1f1e 100644
--- a/libcore/crypto/src/main/java/javax/crypto/NoSuchPaddingException.java
+++ b/libcore/crypto/src/main/java/javax/crypto/NoSuchPaddingException.java
@@ -22,8 +22,6 @@
 /**
  * The exception that is thrown when the requested padding mechanism is not
  * supported.
- * 
- * @since Android 1.0
  */
 public class NoSuchPaddingException extends GeneralSecurityException {
 
@@ -38,7 +36,6 @@
      * 
      * @param msg
      *            the message.
-     * @since Android 1.0
      */
     public NoSuchPaddingException(String msg) {
         super(msg);
@@ -46,8 +43,6 @@
 
     /**
      * Creates a new {@code NoSuchPaddingException}.
-     * 
-     * @since Android 1.0
      */
     public NoSuchPaddingException() {
     }
diff --git a/libcore/crypto/src/main/java/javax/crypto/NullCipher.java b/libcore/crypto/src/main/java/javax/crypto/NullCipher.java
index 49f96c2..fadf3ae 100644
--- a/libcore/crypto/src/main/java/javax/crypto/NullCipher.java
+++ b/libcore/crypto/src/main/java/javax/crypto/NullCipher.java
@@ -32,8 +32,6 @@
 /**
  * This class provides an identity cipher that does not transform the input data
  * in any way. The <i>encrypted</i> data is identical to the <i>plain text</i>.
- * 
- * @since Android 1.0
  */
 public class NullCipher extends Cipher {
 
diff --git a/libcore/crypto/src/main/java/javax/crypto/SealedObject.java b/libcore/crypto/src/main/java/javax/crypto/SealedObject.java
index 4e71453..bf453db 100644
--- a/libcore/crypto/src/main/java/javax/crypto/SealedObject.java
+++ b/libcore/crypto/src/main/java/javax/crypto/SealedObject.java
@@ -40,19 +40,13 @@
  * <p>
  * Since a {@code SealedObject} instance is a serializable object itself it can
  * either be stored or transmitted over an insecure channel.
- * </p>
+ * <p>
  * The wrapped object can later be decrypted (unsealed) using the corresponding
  * key and then be deserialized to retrieve the original object.The sealed
  * object itself keeps track of the cipher and corresponding parameters.
- * 
- * @since Android 1.0
  */
 public class SealedObject implements Serializable {
 
-    // the value of this field was derived by using serialver utility
-    /**
-     * @com.intel.drl.spec_ref
-     */
     private static final long serialVersionUID = 4482838265551344752L;
 
     /**
@@ -76,8 +70,7 @@
      * and sealing it using the specified cipher.
      * <p>
      * The cipher must be fully initialized.
-     * </p>
-     * 
+     *
      * @param object
      *            the object to seal, can be {@code null}.
      * @param c
@@ -90,7 +83,6 @@
      *             size.
      * @throws NullPointerException
      *             if the cipher is {@code null}.
-     * @since Android 1.0
      */
     public SealedObject(Serializable object, Cipher c)
                 throws IOException, IllegalBlockSizeException {
@@ -117,10 +109,9 @@
     /**
      * Creates a new {@code SealedObject} instance by copying the data from
      * the specified object.
-     * 
+     *
      * @param so
      *            the object to copy.
-     * @since Android 1.0
      */
     protected SealedObject(SealedObject so) {
         if (so == null) {
@@ -134,9 +125,8 @@
 
     /**
      * Returns the algorithm this object was sealed with.
-     * 
+     *
      * @return the algorithm this object was sealed with.
-     * @since Android 1.0
      */
     public final String getAlgorithm() {
         return sealAlg;
@@ -144,7 +134,7 @@
 
     /**
      * Returns the wrapped object, decrypting it using the specified key.
-     * 
+     *
      * @param key
      *            the key to decrypt the data with.
      * @return the encapsulated object.
@@ -156,7 +146,6 @@
      *             if the algorithm to decrypt the data is not available.
      * @throws InvalidKeyException
      *             if the specified key cannot be used to decrypt the data.
-     * @since Android 1.0
      */
     public final Object getObject(Key key)
                 throws IOException, ClassNotFoundException,
@@ -207,7 +196,7 @@
     /**
      * Returns the wrapped object, decrypting it using the specified
      * cipher.
-     * 
+     *
      * @param c
      *            the cipher to decrypt the data.
      * @return the encapsulated object.
@@ -221,7 +210,6 @@
      *             size.
      * @throws BadPaddingException
      *             if the padding of the data does not match the padding scheme.
-     * @since Android 1.0
      */
     public final Object getObject(Cipher c)
                 throws IOException, ClassNotFoundException,
@@ -239,7 +227,7 @@
     /**
      * Returns the wrapped object, decrypting it using the specified key. The
      * specified provider is used to retrieve the cipher algorithm.
-     * 
+     *
      * @param key
      *            the key to decrypt the data.
      * @param provider
@@ -255,7 +243,6 @@
      *             if the specified provider is not available.
      * @throws InvalidKeyException
      *             if the specified key cannot be used to decrypt the data.
-     * @since Android 1.0
      */
     public final Object getObject(Key key, String provider)
                 throws IOException, ClassNotFoundException,
diff --git a/libcore/crypto/src/main/java/javax/crypto/SecretKey.java b/libcore/crypto/src/main/java/javax/crypto/SecretKey.java
index 102f888..ac61074 100644
--- a/libcore/crypto/src/main/java/javax/crypto/SecretKey.java
+++ b/libcore/crypto/src/main/java/javax/crypto/SecretKey.java
@@ -24,21 +24,18 @@
  * <p>
  * This interface is a <i>marker interface</i> to group secret keys and to
  * provide type safety for.
- * </p>
+ * <p>
  * Implementations of this interface have to overwrite the
  * {@link Object#equals(Object) equals} and {@link Object#hashCode() hashCode}
  * from {@link java.lang.Object} so comparison is done using the actual key data
  * and not the object reference.
- * 
- * @since Android 1.0
  */
 public interface SecretKey extends Key {
 
     /**
      * The serialization version identifier.
-     * 
+     *
      * @serial
-     * @since Android 1.0
      */
     public static final long serialVersionUID = -4795878709595146952L;
 }
\ No newline at end of file
diff --git a/libcore/crypto/src/main/java/javax/crypto/SecretKeyFactory.java b/libcore/crypto/src/main/java/javax/crypto/SecretKeyFactory.java
index a420dab..57bca3e 100644
--- a/libcore/crypto/src/main/java/javax/crypto/SecretKeyFactory.java
+++ b/libcore/crypto/src/main/java/javax/crypto/SecretKeyFactory.java
@@ -40,9 +40,6 @@
  * </ul>
  * Which key specifications are supported by the {@link #generateSecret} and
  * {@link #getKeySpec} is provider dependent.
- * </p>
- * 
- * @since Android 1.0
  */
 public class SecretKeyFactory {
 
@@ -60,14 +57,13 @@
 
     /**
      * Creates a new {@code SecretKeyFactory}
-     * 
+     *
      * @param keyFacSpi
      *            the SPI delegate.
      * @param provider
      *            the provider providing this key factory.
      * @param algorithm
      *            the algorithm name for the secret key.
-     * @since Android 1.0
      */
     protected SecretKeyFactory(SecretKeyFactorySpi keyFacSpi,
             Provider provider, String algorithm) {
@@ -78,9 +74,8 @@
 
     /**
      * Returns the name of the secret key algorithm.
-     * 
+     *
      * @return the name of the secret key algorithm.
-     * @since Android 1.0
      */
     public final String getAlgorithm() {
         return algorithm;
@@ -88,9 +83,8 @@
 
     /**
      * Returns the provider for this {@code SecretKeyFactory} instance.
-     * 
+     *
      * @return the provider for this {@code SecretKeyFactory} instance.
-     * @since Android 1.0
      */
     public final Provider getProvider() {
         return provider;
@@ -99,7 +93,7 @@
     /**
      * Creates a new {@code SecretKeyFactory} instance for the specified key
      * algorithm.
-     * 
+     *
      * @param algorithm
      *            the name of the key algorithm.
      * @return a secret key factory for the specified key algorithm.
@@ -107,7 +101,6 @@
      *             if no installed provider can provide the requested algorithm.
      * @throws NullPointerException
      *             if the specified algorithm is {@code null}.
-     * @since Android 1.0
      */
     public static final SecretKeyFactory getInstance(String algorithm)
             throws NoSuchAlgorithmException {
@@ -124,7 +117,7 @@
     /**
      * Creates a new {@code SecretKeyFactory} instance for the specified key
      * algorithm from the specified {@code provider}.
-     * 
+     *
      * @param algorithm
      *            the name of the key algorithm.
      * @param provider
@@ -139,7 +132,6 @@
      *             if the specified provider does not exist.
      * @throws IllegalArgumentException
      *             if the specified provider name is {@code null} or empty.
-     * @since Android 1.0
      */
     public static final SecretKeyFactory getInstance(String algorithm,
             String provider) throws NoSuchAlgorithmException,
@@ -157,7 +149,7 @@
     /**
      * Creates a new {@code SecretKeyFactory} instance for the specified key
      * algorithm from the specified provider.
-     * 
+     *
      * @param algorithm
      *            the name of the key algorithm.
      * @param provider
@@ -171,7 +163,6 @@
      *             if the specified provider is {@code null}.
      * @throws NullPointerException
      *             is the specified algorithm name is {@code null}.
-     * @since Android 1.0
      */
     public static final SecretKeyFactory getInstance(String algorithm,
             Provider provider) throws NoSuchAlgorithmException {
@@ -190,14 +181,13 @@
 
     /**
      * Generate a secret key from the specified key specification.
-     * 
+     *
      * @param keySpec
      *            the key specification.
      * @return a secret key.
      * @throws InvalidKeySpecException
      *             if the specified key specification cannot be used to generate
      *             a secret key.
-     * @since Android 1.0
      */
     public final SecretKey generateSecret(KeySpec keySpec)
             throws InvalidKeySpecException {
@@ -206,7 +196,7 @@
 
     /**
      * Returns the key specification of the specified secret key.
-     * 
+     *
      * @param key
      *            the secret key to get the specification from.
      * @param keySpec
@@ -215,7 +205,6 @@
      * @throws InvalidKeySpecException
      *             if the specified secret key cannot be transformed into the
      *             requested key specification.
-     * @since Android 1.0
      */
     @SuppressWarnings("unchecked")
     public final KeySpec getKeySpec(SecretKey key, Class keySpec)
@@ -226,14 +215,13 @@
     /**
      * Translates the specified secret key into an instance of the corresponding
      * key from the provider of this key factory.
-     * 
+     *
      * @param key
      *            the secret key to translate.
      * @return the corresponding translated key.
      * @throws InvalidKeyException
      *             if the specified key cannot be translated using this key
      *             factory.
-     * @since Android 1.0
      */
     public final SecretKey translateKey(SecretKey key)
             throws InvalidKeyException {
diff --git a/libcore/crypto/src/main/java/javax/crypto/SecretKeyFactorySpi.java b/libcore/crypto/src/main/java/javax/crypto/SecretKeyFactorySpi.java
index f834dbb..5d7764e 100644
--- a/libcore/crypto/src/main/java/javax/crypto/SecretKeyFactorySpi.java
+++ b/libcore/crypto/src/main/java/javax/crypto/SecretKeyFactorySpi.java
@@ -24,35 +24,31 @@
 /**
  * The <i>Service Provider Interface</i> (<b>SPI</b>) definition for the {@code
  * SecretKeyFactory} class.
- * 
- * @since Android 1.0
  */
 public abstract class SecretKeyFactorySpi {
 
     /**
      * Creates a new {@code SecretKeyFactorySpi} instance.
-     * @since Android 1.0
      */
     public SecretKeyFactorySpi() {
     }
 
     /**
      * Generate a secret key from the specified key specification.
-     * 
+     *
      * @param keySpec
      *            the key specification.
      * @return a secret key.
      * @throws InvalidKeySpecException
      *             if the specified key specification cannot be used to generate
      *             a secret key.
-     * @since Android 1.0
      */
     protected abstract SecretKey engineGenerateSecret(KeySpec keySpec)
             throws InvalidKeySpecException;
 
     /**
      * Returns the key specification of the specified secret key.
-     * 
+     *
      * @param key
      *            the secret key to get the specification from.
      * @param keySpec
@@ -61,7 +57,6 @@
      * @throws InvalidKeySpecException
      *             if the specified secret key cannot be transformed into the
      *             requested key specification.
-     * @since Android 1.0
      */
     @SuppressWarnings("unchecked")
     protected abstract KeySpec engineGetKeySpec(SecretKey key, Class keySpec)
@@ -70,14 +65,13 @@
     /**
      * Translates the specified secret key into an instance of the corresponding
      * key from the provider of this key factory.
-     * 
+     *
      * @param key
      *            the secret key to translate.
      * @return the corresponding translated key.
      * @throws InvalidKeyException
      *             if the specified key cannot be translated using this key
      *             factory.
-     * @since Android 1.0
      */
     protected abstract SecretKey engineTranslateKey(SecretKey key)
             throws InvalidKeyException;
diff --git a/libcore/crypto/src/main/java/javax/crypto/ShortBufferException.java b/libcore/crypto/src/main/java/javax/crypto/ShortBufferException.java
index 593a31e..56480a8 100644
--- a/libcore/crypto/src/main/java/javax/crypto/ShortBufferException.java
+++ b/libcore/crypto/src/main/java/javax/crypto/ShortBufferException.java
@@ -27,8 +27,6 @@
 /**
  * The exception that is thrown when the result of an operation is attempted to
  * store in a user provided buffer that is too small.
- * 
- * @since Android 1.0
  */
 public class ShortBufferException extends GeneralSecurityException {
 
@@ -43,7 +41,6 @@
      * 
      * @param msg
      *            the exception message.
-     * @since Android 1.0
      */
     public ShortBufferException(String msg) {
         super(msg);
@@ -51,8 +48,6 @@
 
     /**
      * Creates a new instance of {@code ShortBufferException}.
-     * 
-     * @since Android 1.0
      */
     public ShortBufferException() {
     }
diff --git a/libcore/crypto/src/main/java/javax/crypto/interfaces/DHKey.java b/libcore/crypto/src/main/java/javax/crypto/interfaces/DHKey.java
index f686844..6ef17d4 100644
--- a/libcore/crypto/src/main/java/javax/crypto/interfaces/DHKey.java
+++ b/libcore/crypto/src/main/java/javax/crypto/interfaces/DHKey.java
@@ -21,14 +21,12 @@
 
 /**
  * The interface for a Diffie-Hellman key.
- * 
- * @since Android 1.0
  */
 public interface DHKey {
 
     /**
      * Returns the parameters for this key.
-     * 
+     *
      * @return the parameters for this key.
      */
     public DHParameterSpec getParams();
diff --git a/libcore/crypto/src/main/java/javax/crypto/interfaces/DHPrivateKey.java b/libcore/crypto/src/main/java/javax/crypto/interfaces/DHPrivateKey.java
index d39268b..f63e0cb 100644
--- a/libcore/crypto/src/main/java/javax/crypto/interfaces/DHPrivateKey.java
+++ b/libcore/crypto/src/main/java/javax/crypto/interfaces/DHPrivateKey.java
@@ -22,8 +22,6 @@
 
 /**
  * The interface for a private key in the Diffie-Hellman key exchange protocol.
- * 
- * @since Android 1.0
  */
 public interface DHPrivateKey extends DHKey, PrivateKey {
 
diff --git a/libcore/crypto/src/main/java/javax/crypto/interfaces/DHPublicKey.java b/libcore/crypto/src/main/java/javax/crypto/interfaces/DHPublicKey.java
index 75201a7..92e8f10 100644
--- a/libcore/crypto/src/main/java/javax/crypto/interfaces/DHPublicKey.java
+++ b/libcore/crypto/src/main/java/javax/crypto/interfaces/DHPublicKey.java
@@ -21,9 +21,7 @@
 import java.security.PublicKey;
 
 /**
- * The interface for a public key in the Diffie-Hellman key exchange protocol. 
- * 
- * @since Android 1.0
+ * The interface for a public key in the Diffie-Hellman key exchange protocol.
  */
 public interface DHPublicKey extends DHKey, PublicKey {
 
diff --git a/libcore/crypto/src/main/java/javax/crypto/interfaces/PBEKey.java b/libcore/crypto/src/main/java/javax/crypto/interfaces/PBEKey.java
index 4612ad2..c718715 100644
--- a/libcore/crypto/src/main/java/javax/crypto/interfaces/PBEKey.java
+++ b/libcore/crypto/src/main/java/javax/crypto/interfaces/PBEKey.java
@@ -21,8 +21,6 @@
 
 /**
  * The interface to a <i>password-based-encryption</i>  key.
- * 
- * @since Android 1.0
  */
 public interface PBEKey extends SecretKey {
 
@@ -33,21 +31,21 @@
 
     /**
      * Returns the iteration count, 0 if not specified.
-     * 
+     *
      * @return the iteration count, 0 if not specified.
      */
     public int getIterationCount();
 
     /**
      * Returns a copy of the salt data or null if not specified.
-     * 
+     *
      * @return a copy of the salt data or null if not specified.
      */
     public byte[] getSalt();
 
     /**
      * Returns a copy to the password.
-     * 
+     *
      * @return a copy to the password.
      */
     public char[] getPassword();
diff --git a/libcore/crypto/src/main/java/javax/crypto/spec/DESKeySpec.java b/libcore/crypto/src/main/java/javax/crypto/spec/DESKeySpec.java
index 2a994d5..372a68d 100644
--- a/libcore/crypto/src/main/java/javax/crypto/spec/DESKeySpec.java
+++ b/libcore/crypto/src/main/java/javax/crypto/spec/DESKeySpec.java
@@ -24,8 +24,6 @@
 
 /**
  * The key specification for a DES key.
- * 
- * @since Android 1.0
  */
 public class DESKeySpec implements KeySpec {
 
@@ -96,7 +94,7 @@
     /**
      * Creates a new <code>DESKeySpec</code> from the first 8 bytes of the
      * specified key data.
-     * 
+     *
      * @param key
      *            the key data.
      * @throws InvalidKeyException
@@ -109,7 +107,7 @@
     /**
      * Creates a new <code>DESKeySpec</code> from the first 8 bytes of the
      * specified key data starting at <code>offset</code>.
-     * 
+     *
      * @param key
      *            the key data
      * @param offset
@@ -133,7 +131,7 @@
 
     /**
      * Returns a copy of the key.
-     * 
+     *
      * @return a copy of the key.
      */
     public byte[] getKey() {
@@ -145,7 +143,7 @@
     /**
      * Returns whether the specified key data starting at <code>offset</code> is
      * <i>parity-adjusted</i>.
-     * 
+     *
      * @param key
      *            the key data.
      * @param offset
@@ -185,7 +183,7 @@
     /**
      * Returns whether the specified key data starting at <code>offset</code> is
      * weak or semi-weak.
-     * 
+     *
      * @param key
      *            the key data.
      * @param offset
diff --git a/libcore/crypto/src/main/java/javax/crypto/spec/DESedeKeySpec.java b/libcore/crypto/src/main/java/javax/crypto/spec/DESedeKeySpec.java
index 186f07d..199eba6 100644
--- a/libcore/crypto/src/main/java/javax/crypto/spec/DESedeKeySpec.java
+++ b/libcore/crypto/src/main/java/javax/crypto/spec/DESedeKeySpec.java
@@ -24,8 +24,6 @@
 
 /**
  * The key specification for a triple-DES (DES-EDE) key.
- * 
- * @since Android 1.0
  */
 public class DESedeKeySpec implements KeySpec {
 
@@ -39,7 +37,7 @@
     /**
      * Creates a new <code>DESedeKeySpec</code> instance from the first 24 (
      * {@link #DES_EDE_KEY_LEN}) bytes of the specified key data.
-     * 
+     *
      * @param key
      *            the key data.
      * @throws InvalidKeyException
@@ -64,7 +62,7 @@
      * Creates a new <code>DESedeKeySpec</code> instance from the first 24 (
      * {@link #DES_EDE_KEY_LEN} ) bytes of the specified key data starting at
      * <code>offset</code>.
-     * 
+     *
      * @param key
      *            the key data
      * @param offset
@@ -90,7 +88,7 @@
 
     /**
      * Returns a copy of the key.
-     * 
+     *
      * @return a copy of the key.
      */
     public byte[] getKey() {
@@ -102,7 +100,7 @@
     /**
      * Returns whether the specified key data starting at <code>offset</code> is
      * <i>parity-adjusted</i>.
-     * 
+     *
      * @param key
      *            the key data.
      * @param offset
diff --git a/libcore/crypto/src/main/java/javax/crypto/spec/DHGenParameterSpec.java b/libcore/crypto/src/main/java/javax/crypto/spec/DHGenParameterSpec.java
index a149318..f6ddc03 100644
--- a/libcore/crypto/src/main/java/javax/crypto/spec/DHGenParameterSpec.java
+++ b/libcore/crypto/src/main/java/javax/crypto/spec/DHGenParameterSpec.java
@@ -22,8 +22,6 @@
 /**
  * The algorithm parameter specification for generating Diffie-Hellman
  * parameters used in Diffie-Hellman key agreement.
- * 
- * @since Android 1.0
  */
 public class DHGenParameterSpec implements AlgorithmParameterSpec {
 
@@ -33,7 +31,7 @@
     /**
      * Creates a new <code>DHGenParameterSpec</code> instance with the specified
      * parameters.
-     * 
+     *
      * @param primeSize
      *            the size of the <i>prime modulus</i> in bits.
      * @param exponentSize
@@ -46,7 +44,7 @@
 
     /**
      * Returns the size of the <i>prime modulus</i> in bits.
-     * 
+     *
      * @return the size of the prime modulus in bits.
      */
     public int getPrimeSize() {
@@ -55,7 +53,7 @@
 
     /**
      * Returns the size of the <i>random exponent</i> in bits.
-     * 
+     *
      * @return the size of the random exponent in bits.
      */
     public int getExponentSize() {
diff --git a/libcore/crypto/src/main/java/javax/crypto/spec/DHParameterSpec.java b/libcore/crypto/src/main/java/javax/crypto/spec/DHParameterSpec.java
index 9bb94b5..6030b40 100644
--- a/libcore/crypto/src/main/java/javax/crypto/spec/DHParameterSpec.java
+++ b/libcore/crypto/src/main/java/javax/crypto/spec/DHParameterSpec.java
@@ -22,8 +22,6 @@
 
 /**
  * The algorithm parameter specification for the Diffie-Hellman algorithm.
- * 
- * @since Android 1.0
  */
 public class DHParameterSpec implements AlgorithmParameterSpec {
 
@@ -34,7 +32,7 @@
     /**
      * Creates a new <code>DHParameterSpec</code> instance with the specified
      * <i>prime modulus</i> and <i>base generator</i>.
-     * 
+     *
      * @param p
      *            the prime modulus.
      * @param g
@@ -50,7 +48,7 @@
      * Creates a new <code>DHParameterSpec</code> instance with the specified
      * <i>prime modulus</i>, <i>base generator</i> and size (in bits) of the
      * <i>random exponent</i>.
-     * 
+     *
      * @param p
      *            the prime modulus.
      * @param g
@@ -66,7 +64,7 @@
 
     /**
      * Returns the <i>prime modulus</i> of this parameter specification.
-     * 
+     *
      * @return the prime modulus.
      */
     public BigInteger getP() {
@@ -75,7 +73,7 @@
 
     /**
      * Returns the <i>base generator</i> of this parameter specification.
-     * 
+     *
      * @return the base generator.
      */
     public BigInteger getG() {
@@ -84,7 +82,7 @@
 
     /**
      * Returns the size (in bits) of the <i>random exponent</i>.
-     * 
+     *
      * @return the size (in bits) of the random exponent.
      */
     public int getL() {
diff --git a/libcore/crypto/src/main/java/javax/crypto/spec/DHPrivateKeySpec.java b/libcore/crypto/src/main/java/javax/crypto/spec/DHPrivateKeySpec.java
index 6652de8..925a003 100644
--- a/libcore/crypto/src/main/java/javax/crypto/spec/DHPrivateKeySpec.java
+++ b/libcore/crypto/src/main/java/javax/crypto/spec/DHPrivateKeySpec.java
@@ -22,8 +22,6 @@
 
 /**
  * The key specification for a Diffie-Hellman private key.
- * 
- * @since Android 1.0
  */
 public class DHPrivateKeySpec implements KeySpec {
 
@@ -35,7 +33,7 @@
      * Creates a new <code>DHPrivateKeySpec</code> with the specified <i>private
      * value</i> <code>x</code>. <i>prime modulus</i> <code>p</code> and <i>base
      * generator</i> <code>g</code>.
-     * 
+     *
      * @param x
      *            the private value.
      * @param p
@@ -51,7 +49,7 @@
 
     /**
      * Returns the <i>private value</i> <code>x</code>.
-     * 
+     *
      * @return the private value <code>x</code>.
      */
     public BigInteger getX() {
@@ -60,7 +58,7 @@
 
     /**
      * Returns the <i>prime modulus</i> <code>p</code>.
-     * 
+     *
      * @return the prime modulus <code>p</code>.
      */
     public BigInteger getP() {
@@ -69,10 +67,11 @@
 
     /**
      * Returns the <i>base generator</i> <code>g</code>.
-     * 
+     *
      * @return the base generator <code>g</code>.
      */
     public BigInteger getG() {
         return g;
     }
 }
+
diff --git a/libcore/crypto/src/main/java/javax/crypto/spec/DHPublicKeySpec.java b/libcore/crypto/src/main/java/javax/crypto/spec/DHPublicKeySpec.java
index 68d3267..a5d4461 100644
--- a/libcore/crypto/src/main/java/javax/crypto/spec/DHPublicKeySpec.java
+++ b/libcore/crypto/src/main/java/javax/crypto/spec/DHPublicKeySpec.java
@@ -22,8 +22,6 @@
 
 /**
  * The key specification for a Diffie-Hellman public key.
- * 
- * @since Android 1.0
  */
 public class DHPublicKeySpec implements KeySpec {
 
@@ -35,7 +33,7 @@
      * Creates a new <code>DHPublicKeySpec</code> instance with the specified
      * <i>public value</i> <code>y</code>, the <i>prime modulus</i>
      * <code>p</code> and the <i>base generator</i> <code>g</code>.
-     * 
+     *
      * @param y
      *            the public value.
      * @param p
@@ -51,7 +49,7 @@
 
     /**
      * Returns the <i>public value</i> <code>y</code>.
-     * 
+     *
      * @return the public value <code>y</code>.
      */
     public BigInteger getY() {
@@ -60,7 +58,7 @@
 
     /**
      * Returns the <i>prime modulus</i> <code>p</code>.
-     * 
+     *
      * @return the prime modulus <code>p</code>.
      */
     public BigInteger getP() {
@@ -69,7 +67,7 @@
 
     /**
      * Returns the <i>base generator</i> <code>g</code>;
-     * 
+     *
      * @return the base generator <code>g</code>;
      */
     public BigInteger getG() {
diff --git a/libcore/crypto/src/main/java/javax/crypto/spec/IvParameterSpec.java b/libcore/crypto/src/main/java/javax/crypto/spec/IvParameterSpec.java
index 2f532a8..ce7f9d3 100644
--- a/libcore/crypto/src/main/java/javax/crypto/spec/IvParameterSpec.java
+++ b/libcore/crypto/src/main/java/javax/crypto/spec/IvParameterSpec.java
@@ -35,7 +35,7 @@
     /**
      * Creates a new <code>IvParameterSpec</code> instance with the bytes from
      * the specified buffer <i>iv</i> used as <i>initialization vector</i>.
-     * 
+     *
      * @param iv
      *            the buffer used as initialization vector.
      * @throws NullPointerException
@@ -53,7 +53,7 @@
      * Creates a new <code>IvParameterSpec</code> instance with <code>len</code>
      * bytes from the specified buffer <code>iv</code> starting at
      * <code>offset</code>.
-     * 
+     *
      * @param iv
      *            the buffer used as initialization vector.
      * @param offset
@@ -81,7 +81,7 @@
 
     /**
      * Returns a copy of the <i>initialization vector</i> data.
-     * 
+     *
      * @return a copy of the initialization vector data.
      */
     public byte[] getIV() {
diff --git a/libcore/crypto/src/main/java/javax/crypto/spec/OAEPParameterSpec.java b/libcore/crypto/src/main/java/javax/crypto/spec/OAEPParameterSpec.java
index ebb6cce..29b572d 100644
--- a/libcore/crypto/src/main/java/javax/crypto/spec/OAEPParameterSpec.java
+++ b/libcore/crypto/src/main/java/javax/crypto/spec/OAEPParameterSpec.java
@@ -26,8 +26,6 @@
  * <p>
  * This padding algorithm is defined in the <a
  * href="http://www.ietf.org/rfc/rfc3447.txt">PKCS #1</a> standard.
- * 
- * @since Android 1.0
  */
 public class OAEPParameterSpec implements AlgorithmParameterSpec {
 
@@ -60,7 +58,7 @@
      * <i>message digest</i> algorithm name, <i>mask generation function</i>
      * (<i>mgf</i>) algorithm name, <i>parameters</i> for the <i>mgf</i>
      * algorithm and the <i>source of the label <code>L</code></i>.
-     * 
+     *
      * @param mdName
      *            the message digest algorithm name.
      * @param mgfName
@@ -87,7 +85,7 @@
 
     /**
      * Returns the algorithm name of the <i>message digest</i>.
-     * 
+     *
      * @return the algorithm name of the message digest.
      */
     public String getDigestAlgorithm() {
@@ -96,7 +94,7 @@
 
     /**
      * Returns the algorithm name of the <i>mask generation function</i>.
-     * 
+     *
      * @return the algorithm name of the mask generation function.
      */
     public String getMGFAlgorithm() {
@@ -106,7 +104,7 @@
     /**
      * Returns the algorithm parameter specification for the mask generation
      * function algorithm.
-     * 
+     *
      * @return the algorithm parameter specification for the mask generation
      *         function algorithm.
      */
@@ -116,7 +114,7 @@
 
     /**
      * Returns the source of the label <code>L</code>.
-     * 
+     *
      * @return the source of the label <code>L</code>.
      */
     public PSource getPSource() {
diff --git a/libcore/crypto/src/main/java/javax/crypto/spec/PBEKeySpec.java b/libcore/crypto/src/main/java/javax/crypto/spec/PBEKeySpec.java
index c46617e..d79fd3c 100644
--- a/libcore/crypto/src/main/java/javax/crypto/spec/PBEKeySpec.java
+++ b/libcore/crypto/src/main/java/javax/crypto/spec/PBEKeySpec.java
@@ -27,8 +27,6 @@
  * <p>
  * Password based encryption is described in <a
  * href="http://www.ietf.org/rfc/rfc2898.txt">PKCS #5</a>.
- * 
- * @since Android 1.0
  */
 public class PBEKeySpec implements KeySpec {
 
@@ -39,7 +37,7 @@
 
     /**
      * Creates a new <code>PBEKeySpec</code> with the specified password.
-     * 
+     *
      * @param password
      *            the password.
      */
@@ -58,7 +56,7 @@
     /**
      * Creates a new <code>PBEKeySpec</code> with the specified password, salt,
      * iteration count and the desired length of the derived key.
-     * 
+     *
      * @param password
      *            the password.
      * @param salt
@@ -104,7 +102,7 @@
     /**
      * Creates a new <code>PBEKeySpec</code> with the specified password, salt
      * and iteration count.
-     * 
+     *
      * @param password
      *            the password.
      * @param salt
@@ -150,7 +148,7 @@
 
     /**
      * Returns a copy of the password of this key specification.
-     * 
+     *
      * @return a copy of the password of this key specification.
      * @throws IllegalStateException
      *             if the password has been cleared before.
@@ -166,7 +164,7 @@
 
     /**
      * Returns a copy of the salt of this key specification.
-     * 
+     *
      * @return a copy of the salt of this key specification or null if none is
      *         specified.
      */
@@ -181,7 +179,7 @@
 
     /**
      * Returns the iteration count of this key specification.
-     * 
+     *
      * @return the iteration count of this key specification.
      */
     public final int getIterationCount() {
@@ -190,7 +188,7 @@
 
     /**
      * Returns the desired key length of the derived key.
-     * 
+     *
      * @return the desired key length of the derived key.
      */
     public final int getKeyLength() {
diff --git a/libcore/crypto/src/main/java/javax/crypto/spec/PBEParameterSpec.java b/libcore/crypto/src/main/java/javax/crypto/spec/PBEParameterSpec.java
index 190986e..cce3832 100644
--- a/libcore/crypto/src/main/java/javax/crypto/spec/PBEParameterSpec.java
+++ b/libcore/crypto/src/main/java/javax/crypto/spec/PBEParameterSpec.java
@@ -23,12 +23,10 @@
 
 /**
  * The algorithm parameter specification for a <i>password based encryption</i>
- * algorithm. 
+ * algorithm.
  * <p>
  * Password based encryption is described in <a
  * href="http://www.ietf.org/rfc/rfc2898.txt">PKCS #5</a>.
- * 
- * @since Android 1.0
  *
  */
 public class PBEParameterSpec implements AlgorithmParameterSpec {
@@ -39,7 +37,7 @@
     /**
      * Creates a new <code>PBEParameterSpec</code> with the specified salt and
      * iteration count.
-     * 
+     *
      * @param salt
      *            the salt.
      * @param iterationCount
@@ -58,7 +56,7 @@
 
     /**
      * Returns a copy to the salt.
-     * 
+     *
      * @return a copy to the salt.
      */
     public byte[] getSalt() {
@@ -69,7 +67,7 @@
 
     /**
      * Returns the iteration count.
-     * 
+     *
      * @return the iteration count.
      */
     public int getIterationCount() {
diff --git a/libcore/crypto/src/main/java/javax/crypto/spec/PSource.java b/libcore/crypto/src/main/java/javax/crypto/spec/PSource.java
index d5bdf1b..30fd8af 100644
--- a/libcore/crypto/src/main/java/javax/crypto/spec/PSource.java
+++ b/libcore/crypto/src/main/java/javax/crypto/spec/PSource.java
@@ -22,8 +22,6 @@
 /**
  * The source of the label <code>L</code> as specified in <a
  * href="http://www.ietf.org/rfc/rfc3447.txt"> PKCS #1</a>.
- * 
- * @since Android 1.0
  */
 public class PSource {
 
@@ -34,7 +32,7 @@
     /**
      * Creates a new <code>PSource</code> instance with the specified source
      * algorithm identifier.
-     * 
+     *
      * @param pSrcName
      *            the source algorithm identifier.
      * @throws NullPointerException
@@ -49,7 +47,7 @@
 
     /**
      * Returns the source algorithm identifier.
-     * 
+     *
      * @return the source algorithm identifier.
      */
     public String getAlgorithm() {
@@ -59,15 +57,14 @@
     /**
      * The explicit specification of the parameter <code>P</code> used in the
      * source algorithm.
-     * 
-     * @since Android 1.0
      */
     public static final class PSpecified extends PSource {
 
         private final byte[] p;
 
         /**
-         * The instance of <code>PSpecified</code> with the default value <code>byte[0]</code> for <code>P</code>
+         * The instance of <code>PSpecified</code> with the default value
+         * <code>byte[0]</code> for <code>P</code>
          */
         public static final PSpecified DEFAULT = new PSpecified();
 
@@ -79,7 +76,7 @@
         /**
          * Creates a new instance of <code>PSpecified</code> with the specified
          * parameter <code>P</code>.
-         * 
+         *
          * @param p
          *            the parameter <code>P</code>.
          * @throws NullPointerException
@@ -98,7 +95,7 @@
 
         /**
          * Returns a copy of the value of the parameter <code>P</code>.
-         * 
+         *
          * @return a copy of the value of the parameter <code>P</code>
          */
         public byte[] getValue() {
diff --git a/libcore/crypto/src/main/java/javax/crypto/spec/RC2ParameterSpec.java b/libcore/crypto/src/main/java/javax/crypto/spec/RC2ParameterSpec.java
index bd76cf4..bc7a39c 100644
--- a/libcore/crypto/src/main/java/javax/crypto/spec/RC2ParameterSpec.java
+++ b/libcore/crypto/src/main/java/javax/crypto/spec/RC2ParameterSpec.java
@@ -25,8 +25,6 @@
 /**
  * The algorithm parameter specification for the <a
  * href="http://www.ietf.org/rfc/rfc2268.txt">RC2</a> algorithm.
- * 
- * @since Android 1.0
  */
 public class RC2ParameterSpec implements AlgorithmParameterSpec {
 
@@ -36,7 +34,7 @@
     /**
      * Creates a new <code>RC2ParameterSpec</code> instance with the specified
      * effective key length (in bits),
-     * 
+     *
      * @param effectiveKeyBits
      *            the effective key length (in bits).
      */
@@ -51,7 +49,7 @@
      * <p>
      * The size of the <i>initialization vector</i> must be at least 8 bytes
      * which are copied to protect them against modification.
-     * 
+     *
      * @param effectiveKeyBits
      *            the effective key length (in bits).
      * @param iv
@@ -78,7 +76,7 @@
      * The size of the <i>initialization vector</i> starting at
      * <code>offset</code> must be at least 8 bytes which are copied to protect
      * them against modification.
-     * 
+     *
      * @param effectiveKeyBits
      *            the effective key length (in bits).
      * @param iv
@@ -103,7 +101,7 @@
 
     /**
      * Returns the effective key length (in bits).
-     * 
+     *
      * @return the effective key length (in bits).
      */
     public int getEffectiveKeyBits() {
@@ -112,7 +110,7 @@
 
     /**
      * Returns a copy of the initialization vector.
-     * 
+     *
      * @return a copy of the initialization vector, or null if none specified.
      */
     public byte[] getIV() {
@@ -127,7 +125,7 @@
     /**
      * Compares the specified object to this <code>RC2ParameterSpec</code>
      * instance.
-     * 
+     *
      * @param obj
      *            the object to compare.
      * @return true if the effective key length and the initialization vector of
@@ -148,7 +146,7 @@
 
     /**
      * Returns the hash code of this <code>RC2ParameterSpec</code> instance.
-     * 
+     *
      * @return the hash code.
      */
     @Override
diff --git a/libcore/crypto/src/main/java/javax/crypto/spec/RC5ParameterSpec.java b/libcore/crypto/src/main/java/javax/crypto/spec/RC5ParameterSpec.java
index f711f41..57010f7 100644
--- a/libcore/crypto/src/main/java/javax/crypto/spec/RC5ParameterSpec.java
+++ b/libcore/crypto/src/main/java/javax/crypto/spec/RC5ParameterSpec.java
@@ -25,8 +25,6 @@
 /**
  * The algorithm parameter specification for the <a
  * href="http://www.ietf.org/rfc/rfc2040.txt">RC5</a> algorithm.
- * 
- * @since Android 1.0
  */
 public class RC5ParameterSpec implements AlgorithmParameterSpec {
 
@@ -38,7 +36,7 @@
     /**
      * Creates a new <code>RC5ParameterSpec</code> instance with the specified
      * version, round count an word size (in bits).
-     * 
+     *
      * @param version
      *            the version.
      * @param rounds
@@ -61,7 +59,7 @@
      * The size of the <i>initialization vector</i> must be at least
      * <code>2 * (wordSize / 8)</code> bytes which are copied to protect them
      * against modification.
-     * 
+     *
      * @param version
      *            the version.
      * @param rounds
@@ -97,7 +95,7 @@
      * The size of the <i>initialization vector</i> must be at least
      * <code>offset + (2 * (wordSize / 8))</code> bytes. The bytes starting at
      * <code>offset</code> are copied to protect them against modification.
-     * 
+     *
      * @param version
      *            the version.
      * @param rounds
@@ -135,7 +133,7 @@
 
     /**
      * Returns the version.
-     * 
+     *
      * @return the version.
      */
     public int getVersion() {
@@ -144,7 +142,7 @@
 
     /**
      * Returns the round count.
-     * 
+     *
      * @return the round count.
      */
     public int getRounds() {
@@ -153,7 +151,7 @@
 
     /**
      * Returns the word size (in bits).
-     * 
+     *
      * @return the word size (in bits).
      */
     public int getWordSize() {
@@ -162,7 +160,7 @@
 
     /**
      * Returns a copy of the initialization vector.
-     * 
+     *
      * @return a copy of the initialization vector, or null if none specified.
      */
     public byte[] getIV() {
@@ -177,7 +175,7 @@
     /**
      * Compares the specified object with this <code>RC5ParameterSpec</code>
      * instance.
-     * 
+     *
      * @param obj
      *            the object to compare.
      * @return true if version, round count, word size and initializaion vector
@@ -200,7 +198,7 @@
 
     /**
      * Returns the hash code of this <code>RC5ParameterSpec</code> instance.
-     * 
+     *
      * @return the hash code.
      */
     @Override
diff --git a/libcore/crypto/src/main/java/javax/crypto/spec/SecretKeySpec.java b/libcore/crypto/src/main/java/javax/crypto/spec/SecretKeySpec.java
index 897948c..d1eba47 100644
--- a/libcore/crypto/src/main/java/javax/crypto/spec/SecretKeySpec.java
+++ b/libcore/crypto/src/main/java/javax/crypto/spec/SecretKeySpec.java
@@ -33,8 +33,6 @@
  * A key specification for a <code>SecretKey</code> and also a secret key
  * implementation that is provider-independent. It can be used for raw secret
  * keys that can be specified as <code>byte[]</code>.
- * 
- * @since Android 1.0
  */
 public class SecretKeySpec implements SecretKey, KeySpec, Serializable {
 
@@ -50,7 +48,7 @@
     /**
      * Creates a new <code>SecretKeySpec</code> for the specified key data and
      * algorithm name.
-     * 
+     *
      * @param key
      *            the key data.
      * @param algorithm
@@ -79,7 +77,7 @@
      * Creates a new <code>SecretKeySpec</code> for the key data from the
      * specified buffer <code>key</code> starting at <code>offset</code> with
      * length <code>len</code> and the specified <code>algorithm</code> name.
-     * 
+     *
      * @param key
      *            the key data.
      * @param offset
@@ -120,7 +118,7 @@
 
     /**
      * Returns the algorithm name.
-     * 
+     *
      * @return the algorithm name.
      */
     public String getAlgorithm() {
@@ -129,7 +127,7 @@
 
     /**
      * Returns the name of the format used to encode the key.
-     * 
+     *
      * @return the format name "RAW".
      */
     public String getFormat() {
@@ -138,7 +136,7 @@
 
     /**
      * Returns the encoded form of this secret key.
-     * 
+     *
      * @return the encoded form of this secret key.
      */
     public byte[] getEncoded() {
@@ -149,7 +147,7 @@
 
     /**
      * Returns the hash code of this <code>SecretKeySpec</code> object.
-     * 
+     *
      * @return the hash code.
      */
     @Override
@@ -164,7 +162,7 @@
     /**
      * Compares the specified object with this <code>SecretKeySpec</code>
      * instance.
-     * 
+     *
      * @param obj
      *            the object to compare.
      * @return true if the algorithm name and key of both object are equal,
diff --git a/libcore/dalvik/src/main/java/dalvik/system/SamplingProfiler.java b/libcore/dalvik/src/main/java/dalvik/system/SamplingProfiler.java
index 694df38..1d88dd1 100644
--- a/libcore/dalvik/src/main/java/dalvik/system/SamplingProfiler.java
+++ b/libcore/dalvik/src/main/java/dalvik/system/SamplingProfiler.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package dalvik.system;
 
 import java.util.logging.Logger;
@@ -15,62 +31,78 @@
     private static final Logger logger = Logger.getLogger(
             SamplingProfiler.class.getName());
 
+    static final boolean DEBUG = false;
+
+    enum State {
+        /** The sampling thread hasn't started or is waiting to resume. */
+        PAUSED,
+        /** The sampling thread is collecting samples. */
+        RUNNING,
+        /** The sampling thread is shutting down. */
+        SHUTTING_DOWN
+    }
+
     /** Pointer to native state. */
     int pointer = 0;
 
     /** The thread that collects samples. */
     Thread samplingThread;
 
-    /** Whether or not the profiler is running. */
-    boolean running = false;
-    int delayPerThread; // ms
+    /** Time between samples. */
+    volatile int delay; // ms
 
-    /** Number of samples taken. */
-    int sampleCount = 0;
+    /** Number of samples taken (~samples per second * number of threads). */
+    int totalThreadsSampled = 0;
 
     /** Total time spent collecting samples. */
     long totalSampleTime = 0;
 
+    /** The state of the profiler. */
+    volatile State state = State.PAUSED;
+
     private SamplingProfiler() {}
 
     /**
      * Returns true if the profiler is running.
      */
     public boolean isRunning() {
-        return running;
+        return state == State.RUNNING;
     }
 
     /**
      * Starts collecting samples.
      *
-     * @param threadsPerSecond number of threads to sample per second
+     * @param samplesPerSecond number of times to sample each thread per second
+     * @throws IllegalStateException if the profiler is
+     *  {@linkplain #shutDown()} shutting down}
      */
-    public synchronized void start(int threadsPerSecond) {
-        if (threadsPerSecond < 1) {
-            throw new IllegalArgumentException("threadsPerSecond < 1");
+    public synchronized void start(int samplesPerSecond) {
+        if (samplesPerSecond < 1) {
+            throw new IllegalArgumentException("samplesPerSecond < 1");
         }
-        if (!running) {
-            logger.info("Starting profiler.");
-            running = true;
+        ensureNotShuttingDown();
+        delay = 1000 / samplesPerSecond;
+        if (!isRunning()) {
+            if (DEBUG) logger.info("Starting profiler...");
+            state = State.RUNNING;
             if (samplingThread == null) {
                 // TODO: Priority?
-                samplingThread = new Thread(new Sampler());
+                samplingThread = new Thread(new Sampler(), "SamplingProfiler");
                 samplingThread.setDaemon(true);
                 samplingThread.start();
             } else {
                 notifyAll();
             }
         }
-        delayPerThread = 1000 / threadsPerSecond;
     }
 
     /**
-     * Stops sample collection.
+     * Pauses sample collection.
      */
-    public synchronized void stop() {
-        if (running) {
-            logger.info("Stopping profiler.");
-            running = false;
+    public synchronized void pause() {
+        if (isRunning()) {
+            if (DEBUG) logger.info("Pausing profiler...");
+            state = State.PAUSED;
         }
     }
 
@@ -80,49 +112,123 @@
      *
      * <p>Note: The exact format is not documented because it's not set in
      * stone yet.
+     *
+     * @throws IllegalStateException if the profiler is
+     *  {@linkplain #shutDown()} shutting down}
      */
     public synchronized byte[] snapshot() {
-        if (pointer == 0 || sampleCount == 0) {
+        ensureNotShuttingDown();
+        if (pointer == 0 || totalThreadsSampled == 0) {
             return null;
         }
 
-        int size = size(pointer);
-        int collisions = collisions(pointer);
+        if (DEBUG) {
+            int size = size(pointer);
+            int collisions = collisions(pointer);
 
-        long start = System.nanoTime();
-        byte[] bytes = snapshot(pointer);
-        long elapsed = System.nanoTime() - start;
+            long start = System.nanoTime();
+            byte[] bytes = snapshot(pointer);
+            long elapsed = System.nanoTime() - start;
 
-        logger.info("Grabbed snapshot in " + (elapsed / 1000) + "us."
-                + " Samples collected: " + sampleCount
-                + ", Average sample time (per thread): "
-                    + (((totalSampleTime / sampleCount) << 10) / 1000) + "us"
-                + ", Set size: " + size
-                + ", Collisions: " + collisions);
-        sampleCount = 0;
-        totalSampleTime = 0;
+            /*
+             * We shifted the times by 10 bits in the sampling thread to avoid
+             * overflow. Undo the shift and then convert from ns to us.
+             */
+            long averageSampleTime = ((totalSampleTime / totalThreadsSampled)
+                    << 10) / 1000;
+            logger.info("Grabbed snapshot in " + (elapsed / 1000) + "us."
+                    + " Samples collected: " + totalThreadsSampled
+                    + ", Average sample time (per thread): "
+                            + averageSampleTime + "us"
+                    + ", Set size: " + size
+                    + ", Collisions: " + collisions);
+            totalThreadsSampled = 0;
+            totalSampleTime = 0;
 
-        return bytes;
+            return bytes;
+        } else {
+            totalThreadsSampled = 0;
+            return snapshot(pointer);
+        }
     }
 
     /**
      * Identifies the "event thread". For a user-facing application, this
      * might be the UI thread. For a background process, this might be the
      * thread that processes incoming requests.
+     *
+     * @throws IllegalStateException if the profiler is
+     *  {@linkplain #shutDown()} shutting down}
      */
     public synchronized void setEventThread(Thread eventThread) {
+        ensureNotShuttingDown();
         if (pointer == 0) {
             pointer = allocate();
         }
         setEventThread(pointer, eventThread);
     }
 
+    private void ensureNotShuttingDown() {
+        if (state == State.SHUTTING_DOWN) {
+            throw new IllegalStateException("Profiler is shutting down.");
+        }
+    }
+
+    /**
+     * Shuts down the profiler thread and frees native memory. The profiler
+     * will recreate the thread the next time {@link #start(int)} is called.
+     *
+     * @throws IllegalStateException if the profiler is already shutting down
+     *  or if it hasn't started yet
+     *
+     */
+    public void shutDown() {
+        Thread toStop;
+        synchronized (this) {
+            ensureNotShuttingDown();
+
+            toStop = samplingThread;
+            if (toStop == null) {
+                throw new IllegalStateException(
+                        "The profiler was never started.");
+            }
+
+            state = State.SHUTTING_DOWN;
+            samplingThread = null;
+            notifyAll();
+        }
+
+        // Release lock to 'this' so background thread can grab it and stop.
+        // Interrupt the thread in case it's sleeping.
+        toStop.interrupt();
+        while (true) {
+            try {
+                toStop.join();
+                break;
+            } catch (InterruptedException e) { /* ignore */ }
+        }
+
+        synchronized (this) {
+            if (pointer != 0) {
+                free(pointer);
+                pointer = 0;
+            }
+
+            totalThreadsSampled = 0;
+            totalSampleTime = 0;
+            state = State.PAUSED;
+        }
+    }
+
     /** Collects some data. Returns number of threads sampled. */
     private static native int sample(int pointer);
 
     /** Allocates native state. */
     private static native int allocate();
 
+    /** Frees native state. */
+    private static native void free(int pointer);
+
     /** Gets the number of methods in the sample set. */
     private static native int size(int pointer);
 
@@ -142,11 +248,15 @@
         public void run() {
             boolean firstSample = true;
             while (true) {
-                int threadsSampled;
                 synchronized (SamplingProfiler.this) {
-                    if (!running) {
-                        logger.info("Stopped profiler.");
-                        while (!running) {
+                    if (!isRunning()) {
+                        if (DEBUG) logger.info("Paused profiler.");
+                        while (!isRunning()) {
+                            if (state == State.SHUTTING_DOWN) {
+                                // Stop thread.
+                                return;
+                            }
+
                             try {
                                 SamplingProfiler.this.wait();
                             } catch (InterruptedException e) { /* ignore */ }
@@ -159,20 +269,24 @@
                     }
 
                     if (firstSample) {
-                        logger.info("Started profiler.");
+                        if (DEBUG) logger.info("Started profiler.");
                         firstSample = false;
                     }
 
-                    long start = System.nanoTime();
-                    threadsSampled = sample(pointer);
-                    long elapsed = System.nanoTime() - start;
+                    if (DEBUG) {
+                        long start = System.nanoTime();
+                        int threadsSampled = sample(pointer);
+                        long elapsed = System.nanoTime() - start;
 
-                    sampleCount += threadsSampled;
-                    totalSampleTime += elapsed >> 10; // shift avoids overflow.
+                        totalThreadsSampled += threadsSampled;
+                        totalSampleTime += elapsed >> 10; // avoids overflow.
+                    } else {
+                        totalThreadsSampled += sample(pointer);
+                    }
                 }
 
                 try {
-                    Thread.sleep(delayPerThread * threadsSampled);
+                    Thread.sleep(delay);
                 } catch (InterruptedException e) { /* ignore */ }
             }
         }
@@ -211,9 +325,12 @@
 
     private static void appendCounts(DataInputStream in, StringBuilder sb)
             throws IOException {
-        sb.append("      running: ").append(in.readShort()).append('\n');
-        sb.append("      native: ").append(in.readShort()).append('\n');
-        sb.append("      suspended: ").append(in.readShort()).append('\n');
+        sb.append("      running:\n");
+        sb.append("        caller: ").append(in.readShort()).append('\n');
+        sb.append("        leaf: ").append(in.readShort()).append('\n');
+        sb.append("      suspended:\n");
+        sb.append("        caller: ").append(in.readShort()).append('\n');
+        sb.append("        leaf: ").append(in.readShort()).append('\n');
     }
 
     /** This will be allocated when the user calls getInstance(). */
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java b/libcore/icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java
index 206f0c8..919d865 100644
--- a/libcore/icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java
@@ -344,18 +344,11 @@
 
         // ok was there input held in the previous invocation of decodeLoop 
         // that resulted in output in this invocation?
-        if(data[OUTPUT_OFFSET]>0 && savedInputHeldLen >0){
-            int len = in.position() + data[INPUT_OFFSET] + savedInputHeldLen;
-            in.position(len);   
-            savedInputHeldLen = data[INPUT_HELD];
-        }else{
-            in.position(in.position() + data[INPUT_OFFSET] + savedInputHeldLen);
-            savedInputHeldLen = data[INPUT_HELD];
-            in.position(in.position() - savedInputHeldLen);
-        }       
-        // BEGIN android-added
+        // BEGIN android-changed
+        in.position(in.position() + data[INPUT_OFFSET] + savedInputHeldLen - data[INPUT_HELD]);
+        savedInputHeldLen = data[INPUT_HELD];
         // release reference to input array, which may not be ours
         input = null;
-        // END android-added
+        // END android-changed
     }
 }
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/util/Resources.java b/libcore/icu/src/main/java/com/ibm/icu4jni/util/Resources.java
index 85530ac..0460fde 100644
--- a/libcore/icu/src/main/java/com/ibm/icu4jni/util/Resources.java
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/util/Resources.java
@@ -179,20 +179,28 @@
     private static String getDefaultLocaleName() {
         return java.util.Locale.getDefault().toString();
     }
-    
-    /**
-     * Name of default locale at the time this class was initialized.
-     */
-    private static final String initialLocale = getDefaultLocaleName();
 
     /**
-     * Names of time zones for the default locale.
+     * Initialization holder for default time zone names. This class will
+     * be preloaded by the zygote to share the time and space costs of setting
+     * up the list of time zone names, so although it looks like the lazy
+     * initialization idiom, it's actually the opposite.
      */
-    private static String[][] defaultTimezoneNames = null;
+    private static class DefaultTimeZones {
+        /**
+         * Name of default locale at the time this class was initialized.
+         */
+        private static final String locale = getDefaultLocaleName();
+
+        /**
+         * Names of time zones for the default locale.
+         */
+        private static final String[][] names = createTimeZoneNamesFor(locale);
+    }
 
     /**
      * Creates array of time zone names for the given locale. This method takes
-     * about 2s to run on a 400mhz ARM11.
+     * about 2s to run on a 400MHz ARM11.
      */
     private static String[][] createTimeZoneNamesFor(String locale) {
         long start = System.currentTimeMillis();
@@ -252,22 +260,16 @@
      *         the TomeZone class.
      */
     public static String[][] getDisplayTimeZones(String locale) {
-        // Note: Defer loading DefaultTimeZones as long as possible.
-
-        String defaultLocaleName = getDefaultLocaleName();
+        String defaultLocale = getDefaultLocaleName();
         if (locale == null) {
-            locale = defaultLocaleName;
+            locale = defaultLocale;
         }
 
         // If locale == default and the default locale hasn't changed since
         // DefaultTimeZones loaded, return the cached names.
         // TODO: We should force a reboot if the default locale changes.
-        if (defaultLocaleName.equals(locale)
-                && initialLocale.equals(defaultLocaleName)) {
-            if (defaultTimezoneNames == null) {
-                defaultTimezoneNames = createTimeZoneNamesFor(locale);
-            }
-            return defaultTimezoneNames;
+        if (defaultLocale.equals(locale) && DefaultTimeZones.locale.equals(defaultLocale)) {
+            return DefaultTimeZones.names;
         }
         
         return createTimeZoneNamesFor(locale);
diff --git a/libcore/luni-kernel/src/main/java/java/lang/Class.java b/libcore/luni-kernel/src/main/java/java/lang/Class.java
index 6adf4db..b8e3903 100644
--- a/libcore/luni-kernel/src/main/java/java/lang/Class.java
+++ b/libcore/luni-kernel/src/main/java/java/lang/Class.java
@@ -469,6 +469,7 @@
      * 
      * @param parameterTypes
      *            the parameter types of the requested constructor.
+     *            {@code (Class[]) null} is equivalent to the empty array.
      * @return the constructor described by {@code parameterTypes}.
      * @throws NoSuchMethodException
      *             if the constructor can not be found.
@@ -587,6 +588,7 @@
      * 
      * @param parameterTypes
      *            the parameter types of the requested constructor.
+     *            {@code (Class[]) null} is equivalent to the empty array.
      * @return the constructor described by {@code parameterTypes}.
      * @throws NoSuchMethodException
      *             if the requested constructor can not be found.
@@ -659,12 +661,14 @@
         sb.append(getSimpleName());
         sb.append('(');
         boolean first = true;
-        for (Class<?> p : parameterTypes) {
-            if (!first) {
-                sb.append(',');
+        if (parameterTypes != null) {
+            for (Class<?> p : parameterTypes) {
+                if (!first) {
+                    sb.append(',');
+                }
+                first = false;
+                sb.append(p.getSimpleName());
             }
-            first = false;
-            sb.append(p.getSimpleName());
         }
         sb.append(')');
         throw new NoSuchMethodException(sb.toString());
@@ -741,6 +745,7 @@
      *            the requested method's name.
      * @param parameterTypes
      *            the parameter types of the requested method.
+     *            {@code (Class[]) null} is equivalent to the empty array.
      * @return the method described by {@code name} and {@code parameterTypes}.
      * @throws NoSuchMethodException
      *             if the requested constructor can not be found.
@@ -991,6 +996,7 @@
      *            the requested method's name.
      * @param parameterTypes
      *            the parameter types of the requested method.
+     *            {@code (Class[]) null} is equivalent to the empty array.
      * @return the public field specified by {@code name}.
      * @throws NoSuchMethodException
      *             if the method can not be found.
diff --git a/libcore/luni-kernel/src/main/java/java/lang/Thread.java b/libcore/luni-kernel/src/main/java/java/lang/Thread.java
index 484c258..4f9f988 100644
--- a/libcore/luni-kernel/src/main/java/java/lang/Thread.java
+++ b/libcore/luni-kernel/src/main/java/java/lang/Thread.java
@@ -922,9 +922,7 @@
      * @since Android 1.0
      */
     public final boolean isAlive() {
-        Thread.State state = getState();
-
-        return (state != Thread.State.TERMINATED && state != Thread.State.NEW);
+        return (vmThread != null);
     }
 
     /**
diff --git a/libcore/luni/src/main/java/java/net/DatagramSocket.java b/libcore/luni/src/main/java/java/net/DatagramSocket.java
index 6b3b6cc..ba5e207 100644
--- a/libcore/luni/src/main/java/java/net/DatagramSocket.java
+++ b/libcore/luni/src/main/java/java/net/DatagramSocket.java
@@ -81,7 +81,7 @@
     public DatagramSocket(int aPort) throws SocketException {
         super();
         checkListen(aPort);
-        createSocket(aPort, InetAddress.ANY);
+        createSocket(aPort, Inet4Address.ANY);
     }
 
     /**
@@ -99,7 +99,7 @@
     public DatagramSocket(int aPort, InetAddress addr) throws SocketException {
         super();
         checkListen(aPort);
-        createSocket(aPort, null == addr ? InetAddress.ANY : addr);
+        createSocket(aPort, null == addr ? Inet4Address.ANY : addr);
     }
 
     /**
@@ -228,7 +228,7 @@
             return null;
         }
         if (!isBound()) {
-            return InetAddress.ANY;
+            return Inet4Address.ANY;
         }
         InetAddress anAddr = impl.getLocalAddress();
         try {
@@ -237,7 +237,7 @@
                 security.checkConnect(anAddr.getHostName(), -1);
             }
         } catch (SecurityException e) {
-            return InetAddress.ANY;
+            return Inet4Address.ANY;
         }
         return anAddr;
     }
@@ -603,7 +603,7 @@
         }
         if (bind && !isBound()) {
             checkListen(0);
-            impl.bind(0, InetAddress.ANY);
+            impl.bind(0, Inet4Address.ANY);
             isBound = true;
         }
     }
@@ -624,7 +624,7 @@
     public void bind(SocketAddress localAddr) throws SocketException {
         checkClosedAndBind(false);
         int localPort = 0;
-        InetAddress addr = InetAddress.ANY;
+        InetAddress addr = Inet4Address.ANY;
         if (localAddr != null) {
             if (!(localAddr instanceof InetSocketAddress)) {
                 throw new IllegalArgumentException(Msg.getString(
diff --git a/libcore/luni/src/main/java/java/net/Inet4Address.java b/libcore/luni/src/main/java/java/net/Inet4Address.java
index 23efa5e..5e1a420 100644
--- a/libcore/luni/src/main/java/java/net/Inet4Address.java
+++ b/libcore/luni/src/main/java/java/net/Inet4Address.java
@@ -33,11 +33,17 @@
 
     private static final long serialVersionUID = 3286316764910316507L;
 
+    final static InetAddress ANY = new Inet4Address(new byte[] { 0, 0, 0, 0 });
+    final static InetAddress LOOPBACK = new Inet4Address(
+            new byte[] { 127, 0, 0, 1 }, "localhost"); //$NON-NLS-1$
+
     Inet4Address(byte[] address) {
+        family = AF_INET;
         ipaddress = address;
     }
 
     Inet4Address(byte[] address, String name) {
+        family = AF_INET;
         ipaddress = address;
         hostName = name;
     }
@@ -228,31 +234,17 @@
         return hostAddress;
     }
 
-    /**
-     * Gets the hashcode of the represented IP address.
-     * 
-     * @return the appropriate hashcode value.
-     */
-    @Override
-    public int hashCode() {
-        return InetAddress.bytesToInt(ipaddress, 0);
-    }
+    // BEGIN android-removed
+    // public int hashCode() {
+    // }
+    // END android-removed
 
-    /**
-     * Compares this instance with the IP address in the object {@code obj} and
-     * returns {@code true} if they are of the same type and represent the same
-     * IP address, {@code false} otherwise.
-     * 
-     * @param obj
-     *            the object to be tested for equality.
-     * @return {@code true} if the addresses are equal, {@code false} otherwise.
-     */
-    @Override
-    public boolean equals(Object obj) {
-        return super.equals(obj);
-    }
+    // BEGIN android-removed
+    // public boolean equals(Object obj) {
+    // }
+    // END android-removed
 
     private Object writeReplace() throws ObjectStreamException {
-        return new InetAddress(ipaddress, hostName);
+        return new Inet4Address(ipaddress, hostName);
     }
 }
diff --git a/libcore/luni/src/main/java/java/net/Inet6Address.java b/libcore/luni/src/main/java/java/net/Inet6Address.java
index 5c19663..91ec48e 100644
--- a/libcore/luni/src/main/java/java/net/Inet6Address.java
+++ b/libcore/luni/src/main/java/java/net/Inet6Address.java
@@ -21,7 +21,6 @@
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.io.ObjectStreamField;
-import java.util.Arrays;
 import java.util.Enumeration;
 
 import org.apache.harmony.luni.util.Inet6Util;
@@ -34,16 +33,10 @@
 
     private static final long serialVersionUID = 6880410070516793377L;
 
-    static final byte[] any_bytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0 };
-
-    static final byte[] localhost_bytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 1 };
-
-    static final InetAddress ANY = new Inet6Address(any_bytes);
-
-    static final InetAddress LOOPBACK = new Inet6Address(localhost_bytes,
-            "localhost"); //$NON-NLS-1$
+    static final InetAddress ANY = new Inet6Address(new byte[]
+            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 });
+    static final InetAddress LOOPBACK = new Inet6Address(new byte[]
+            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, "localhost"); //$NON-NLS-1$
 
     int scope_id;
 
@@ -59,11 +52,13 @@
     transient NetworkInterface scopedIf;
 
     Inet6Address(byte address[]) {
+        family = AF_INET6;
         ipaddress = address;
         scope_id = 0;
     }
 
     Inet6Address(byte address[], String name) {
+        family = AF_INET6;
         hostName = name;
         ipaddress = address;
         scope_id = 0;
@@ -81,6 +76,7 @@
      *            the scope id for link- or site-local addresses.
      */
     Inet6Address(byte address[], String name, int scope_id) {
+        family = AF_INET6;
         hostName = name;
         ipaddress = address;
         this.scope_id = scope_id;
@@ -403,30 +399,13 @@
         return null;
     }
 
-    /**
-     * Gets the hashcode of the represented IP address.
-     * 
-     * @return the appropriate hashcode value.
-     */
-    @Override
-    public int hashCode() {
-        return Arrays.hashCode(ipaddress);
-    }
+    // BEGIN android-removed
+    // public int hashCode() {}
+    // END android-removed
 
-    /**
-     * Compares this instance with the IP address in the object {@code obj} and
-     * returns {@code true} if they are of the same type and represent the same
-     * IP address, {@code false} otherwise. The scope id does not seem to be
-     * part of the comparison.
-     * 
-     * @param obj
-     *            the object to be tested for equality.
-     * @return {@code true} if the addresses are equal, {@code false} otherwise.
-     */
-    @Override
-    public boolean equals(Object obj) {
-        return super.equals(obj);
-    }
+    // BEGIN android-removed
+    // public boolean equals(Object obj) {}
+    // END android-removed
 
     /**
      * Returns whether this address is IPv4 compatible or not. An IPv4
diff --git a/libcore/luni/src/main/java/java/net/InetAddress.java b/libcore/luni/src/main/java/java/net/InetAddress.java
index eec153f..a7ea3f6 100644
--- a/libcore/luni/src/main/java/java/net/InetAddress.java
+++ b/libcore/luni/src/main/java/java/net/InetAddress.java
@@ -46,17 +46,8 @@
  */
 public class InetAddress extends Object implements Serializable {
 
-    final static byte[] any_bytes = { 0, 0, 0, 0 };
-
-    final static byte[] localhost_bytes = { 127, 0, 0, 1 };
-
-    static InetAddress ANY = new Inet4Address(any_bytes);
-
     private final static INetworkSystem NETIMPL = Platform.getNetworkSystem();
 
-    final static InetAddress LOOPBACK = new Inet4Address(localhost_bytes,
-            "localhost"); //$NON-NLS-1$
-
     private static final String ERRMSG_CONNECTION_REFUSED = "Connection refused"; //$NON-NLS-1$
 
     private static final long serialVersionUID = 3286316764910316507L;
@@ -79,7 +70,9 @@
 
     private int addrCount;
 
-    int family = 2;
+    int family = 0;
+    static final int AF_INET = 2;
+    static final int AF_INET6 = 10;
 
     byte[] ipaddress;
 
@@ -93,12 +86,22 @@
     // END android-removed
 
     /**
-     * Constructs an InetAddress.
+     * Constructs an {@code InetAddress}.
+     *
+     * Note: this constructor should not be used. Creating an InetAddress
+     * without specifying whether it's an IPv4 or IPv6 address does not make
+     * sense, because subsequent code cannot know which of of the subclasses'
+     * methods need to be called to implement a given InetAddress method. The
+     * proper way to create an InetAddress is to call new Inet4Address or
+     * Inet6Address or to use one of the static methods that return
+     * InetAddresses (e.g., getByAddress). That is why the API does not have
+     * public constructors for any of these classes.
      */
     InetAddress() {
         super();
     }
 
+    // BEGIN android-removed
     /**
      * Constructs an {@code InetAddress}, representing the {@code address} and
      * {@code hostName}.
@@ -106,23 +109,27 @@
      * @param address
      *            the network address.
      */
-    InetAddress(byte[] address) {
-        super();
-        this.ipaddress = address;
-    }
+    // InetAddress(byte[] address) {
+    //     super();
+    //     this.ipaddress = address;
+    // }
+    // END android-removed
 
+    // BEGIN android-removed
     /**
      * Constructs an {@code InetAddress}, representing the {@code address} and
      * {@code hostName}.
      *
      * @param address
      *            the network address.
+     *
      */
-    InetAddress(byte[] address, String hostName) {
-        super();
-        this.ipaddress = address;
-        this.hostName = hostName;
-    }
+    // InetAddress(byte[] address, String hostName) {
+    //     super();
+    //     this.ipaddress = address;
+    //     this.hostName = hostName;
+    // }
+    // END android-removed
 
     // BEGIN android-removed
     // CacheElement cacheElement() {
@@ -145,21 +152,8 @@
         if (!(obj instanceof InetAddress)) {
             return false;
         }
+        return Arrays.equals(this.ipaddress, ((InetAddress) obj).ipaddress);
         // END android-changed
-
-        // now check if their byte arrays match...
-        byte[] objIPaddress = ((InetAddress) obj).ipaddress;
-        // BEGIN android-added
-        if (objIPaddress.length != ipaddress.length) {
-            return false;
-        }
-        // END android-added
-        for (int i = 0; i < objIPaddress.length; i++) {
-            if (objIPaddress[i] != this.ipaddress[i]) {
-                return false;
-            }
-        }
-        return true;
     }
 
     /**
@@ -253,15 +247,17 @@
             throws UnknownHostException {
         if (host == null || 0 == host.length()) {
             if (preferIPv6Addresses()) {
-                return new InetAddress[] { Inet6Address.LOOPBACK, LOOPBACK };
+                return new InetAddress[] { Inet6Address.LOOPBACK,
+                                           Inet4Address.LOOPBACK };
             } else {
-                return new InetAddress[] { LOOPBACK, Inet6Address.LOOPBACK };
+                return new InetAddress[] { Inet4Address.LOOPBACK,
+                                           Inet6Address.LOOPBACK };
             }
         }
 
         // Special-case "0" for legacy IPv4 applications.
         if (host.equals("0")) { //$NON-NLS-1$
-            return new InetAddress[] { InetAddress.ANY };
+            return new InetAddress[] { Inet4Address.ANY };
         }
 
         if (isHostName(host)) {
@@ -281,8 +277,10 @@
             return (new InetAddress[] { new Inet4Address(hBytes) });
         } else if (hBytes.length == 16) {
             return (new InetAddress[] { new Inet6Address(hBytes) });
+        } else {
+            throw new UnknownHostException(
+                    Msg.getString("K0339")); //$NON-NLS-1$
         }
-        return (new InetAddress[] { new InetAddress(hBytes) });
     }
     // END android-added
 
@@ -403,7 +401,7 @@
                 security.checkConnect(host, -1);
             }
         } catch (SecurityException e) {
-            return InetAddress.LOOPBACK;
+            return Inet4Address.LOOPBACK;
         }
         return lookupHostByName(host)[0];
     }
@@ -415,18 +413,24 @@
      */
     @Override
     public int hashCode() {
-        return bytesToInt(ipaddress, 0);
+        // BEGIN android-changed
+        return Arrays.hashCode(ipaddress);
+        // END android-changed
     }
 
-    /**
-     * Returns whether this address is an IP multicast address or not.
+    // BEGIN android-changed
+    /*
+     * Returns whether this address is an IP multicast address or not. This
+     * implementation returns always {@code false}.
      *
      * @return {@code true} if this address is in the multicast group, {@code
      *         false} otherwise.
      */
     public boolean isMulticastAddress() {
-        return ((ipaddress[0] & 255) >>> 4) == 0xE;
+        return false;
     }
+    // END android-changed
+
 
     /**
      * Resolves a hostname to its IP addresses using a cache for faster lookups.
@@ -530,7 +534,14 @@
     //    throws UnknownHostException;
     static InetAddress getHostByAddrImpl(byte[] addr)
             throws UnknownHostException {
-        return new InetAddress(addr, gethostbyaddr(addr));
+        if (addr.length == 4) {
+            return new Inet4Address(addr, gethostbyaddr(addr));
+        } else if (addr.length == 16) {
+            return new Inet6Address(addr, gethostbyaddr(addr));
+        } else {
+            throw new UnknownHostException(Msg.getString(
+                    "K0339")); //$NON-NLS-1$
+        }
     }
 
     /**
@@ -618,7 +629,7 @@
 
     static String getHostNameInternal(String host) throws UnknownHostException {
         if (host == null || 0 == host.length()) {
-            return InetAddress.LOOPBACK.getHostAddress();
+            return Inet4Address.LOOPBACK.getHostAddress();
         }
         if (isHostName(host)) {
             return lookupHostByName(host)[0].getHostAddress();
@@ -1113,7 +1124,7 @@
             throws UnknownHostException {
         // simply call the method by the same name specifying the default scope
         // id of 0
-        return getByAddress(ipAddress, 0);
+        return getByAddressInternal(null, ipAddress, 0);
     }
 
     /**
@@ -1133,51 +1144,35 @@
      */
     static InetAddress getByAddress(byte[] ipAddress, int scope_id)
             throws UnknownHostException {
-        byte[] copy_address;
-        if (ipAddress != null && ipAddress.length == 4) {
-            copy_address = new byte[4];
-            for (int i = 0; i < 4; i++) {
-                copy_address[i] = ipAddress[i];
-            }
-            return new Inet4Address(copy_address);
-        }
-
-        if (ipAddress != null && ipAddress.length == 16) {
-            // First check to see if the address is an IPv6-mapped
-            // IPv4 address. If it is, then we can make it a IPv4
-            // address, otherwise, we'll create an IPv6 address.
-            if (isIPv4MappedAddress(ipAddress)) {
-                copy_address = new byte[4];
-                for (int i = 0; i < 4; i++) {
-                    copy_address[i] = ipAddress[12 + i];
-                }
-                return new Inet4Address(copy_address);
-            }
-            copy_address = ipAddress.clone();
-            return new Inet6Address(copy_address, scope_id);
-        }
-
-        // K0339=Invalid IP Address is neither 4 or 16 bytes
-        throw new UnknownHostException(Msg.getString("K0339")); //$NON-NLS-1$
+        return getByAddressInternal(null, ipAddress, scope_id);
     }
 
     private static boolean isIPv4MappedAddress(byte ipAddress[]) {
         // Check if the address matches ::FFFF:d.d.d.d
         // The first 10 bytes are 0. The next to are -1 (FF).
         // The last 4 bytes are varied.
+        if (ipAddress == null || ipAddress.length != 16) {
+            return false;
+        }
         for (int i = 0; i < 10; i++) {
             if (ipAddress[i] != 0) {
                 return false;
             }
         }
-
         if (ipAddress[10] != -1 || ipAddress[11] != -1) {
             return false;
         }
-
         return true;
     }
 
+    private static byte[] ipv4MappedToIPv4(byte[] mappedAddress) {
+        byte[] ipv4Address = new byte[4];
+        for(int i = 0; i < 4; i++) {
+            ipv4Address[i] = mappedAddress[12 + i];
+        }
+        return ipv4Address;
+    }
+
     /**
      * Returns the {@code InetAddress} corresponding to the array of bytes, and
      * the given hostname. In the case of an IPv4 address there must be exactly
@@ -1227,36 +1222,32 @@
      */
     static InetAddress getByAddressInternal(String hostName, byte[] ipAddress,
             int scope_id) throws UnknownHostException {
-        byte[] copy_address;
-        if (ipAddress != null && ipAddress.length == 4) {
-            copy_address = new byte[4];
-            for (int i = 0; i < 4; i++) {
-                copy_address[i] = ipAddress[i];
-            }
-            return new Inet4Address(ipAddress, hostName);
+        if (ipAddress == null) {
+            throw new NullPointerException();
         }
-
-        if (ipAddress != null && ipAddress.length == 16) {
-            // First check to see if the address is an IPv6-mapped
-            // IPv4 address. If it is, then we can make it a IPv4
-            // address, otherwise, we'll create an IPv6 address.
-            if (isIPv4MappedAddress(ipAddress)) {
-                copy_address = new byte[4];
-                for (int i = 0; i < 4; i++) {
-                    copy_address[i] = ipAddress[12 + i];
+        switch (ipAddress.length) {
+            case 4:
+                return new Inet4Address(ipAddress.clone());
+            case 16:
+                // First check to see if the address is an IPv6-mapped
+                // IPv4 address. If it is, then we can make it a IPv4
+                // address, otherwise, we'll create an IPv6 address.
+                if (isIPv4MappedAddress(ipAddress)) {
+                    return new Inet4Address(ipv4MappedToIPv4(ipAddress));
+                } else {
+                    return new Inet6Address(ipAddress.clone(), scope_id);
                 }
-                return new Inet4Address(ipAddress, hostName);
-            }
-
-            copy_address = new byte[16];
-            for (int i = 0; i < 16; i++) {
-                copy_address[i] = ipAddress[i];
-            }
-
-            return new Inet6Address(ipAddress, hostName, scope_id);
+            default:
+                if (hostName != null) {
+                    // "Invalid IP Address is neither 4 or 16 bytes: <hostName>"
+                    throw new UnknownHostException(
+                            Msg.getString("K0332", hostName)); //$NON-NLS-1$
+                } else {
+                    // "Invalid IP Address is neither 4 or 16 bytes"
+                    throw new UnknownHostException(
+                            Msg.getString("K0339")); //$NON-NLS-1$
+                }
         }
-
-        throw new UnknownHostException(Msg.getString("K0332", hostName)); //$NON-NLS-1$
     }
 
     /**
diff --git a/libcore/luni/src/main/java/java/net/InetSocketAddress.java b/libcore/luni/src/main/java/java/net/InetSocketAddress.java
index 13c10f2..08e75a9 100644
--- a/libcore/luni/src/main/java/java/net/InetSocketAddress.java
+++ b/libcore/luni/src/main/java/java/net/InetSocketAddress.java
@@ -35,9 +35,9 @@
     private int port;
 
     /**
-     * Creates a socket endpoint with the given port number {@code port} and the
-     * wildcard address {@code InetAddress.ANY}. The range for valid port numbers
-     * is between 0 and 65535 inclusive.
+     * Creates a socket endpoint with the given port number {@code port} and
+     * no specified address. The range for valid port numbers is between 0 and
+     * 65535 inclusive.
      *
      * @param port
      *            the specified port number to which this socket is bound.
@@ -50,7 +50,7 @@
      * Creates a socket endpoint with the given port number {@code port} and
      * {@code address}. The range for valid port numbers is between 0 and 65535
      * inclusive. If {@code address} is {@code null} this socket is bound to the
-     * wildcard address {@code InetAddress.ANY}.
+     * IPv4 wildcard address.
      *
      * @param port
      *            the specified port number to which this socket is bound.
@@ -62,7 +62,7 @@
             throw new IllegalArgumentException();
         }
         if (address == null) {
-            addr = InetAddress.ANY;
+            addr = Inet4Address.ANY;
         } else {
             addr = address;
         }
diff --git a/libcore/luni/src/main/java/java/net/MulticastSocket.java b/libcore/luni/src/main/java/java/net/MulticastSocket.java
index 0b1c99b..60d967b 100644
--- a/libcore/luni/src/main/java/java/net/MulticastSocket.java
+++ b/libcore/luni/src/main/java/java/net/MulticastSocket.java
@@ -146,7 +146,7 @@
                     && (InetAddress.preferIPv6Addresses() == true)) {
                 theAddresses[0] = Inet6Address.ANY;
             } else {
-                theAddresses[0] = InetAddress.ANY;
+                theAddresses[0] = Inet4Address.ANY;
             }
             return new NetworkInterface(null, null, theAddresses,
                     NetworkInterface.UNSET_INTERFACE_INDEX);
@@ -385,7 +385,7 @@
             throw new NullPointerException();
         }
         if (addr.isAnyLocalAddress()) {
-            impl.setOption(SocketOptions.IP_MULTICAST_IF, InetAddress.ANY);
+            impl.setOption(SocketOptions.IP_MULTICAST_IF, Inet4Address.ANY);
         } else if (addr instanceof Inet4Address) {
             impl.setOption(SocketOptions.IP_MULTICAST_IF, addr);
             // keep the address used to do the set as we must return the same
@@ -449,7 +449,7 @@
         if (netInterface.getIndex() == NetworkInterface.UNSET_INTERFACE_INDEX) {
             // set the address using IP_MULTICAST_IF to make sure this
             // works for both IPV4 and IPV6
-            impl.setOption(SocketOptions.IP_MULTICAST_IF, InetAddress.ANY);
+            impl.setOption(SocketOptions.IP_MULTICAST_IF, Inet4Address.ANY);
 
             try {
                 // we have the index so now we pass set the interface
diff --git a/libcore/luni/src/main/java/java/net/ServerSocket.java b/libcore/luni/src/main/java/java/net/ServerSocket.java
index 99fad3f..f9d5b22 100644
--- a/libcore/luni/src/main/java/java/net/ServerSocket.java
+++ b/libcore/luni/src/main/java/java/net/ServerSocket.java
@@ -84,7 +84,7 @@
      *             if an error occurs while creating the server socket.
      */
     public ServerSocket(int aport) throws IOException {
-        this(aport, defaultBacklog(), InetAddress.ANY);
+        this(aport, defaultBacklog(), Inet4Address.ANY);
     }
 
     /**
@@ -102,7 +102,7 @@
      *             if an error occurs while creating the server socket.
      */
     public ServerSocket(int aport, int backlog) throws IOException {
-        this(aport, backlog, InetAddress.ANY);
+        this(aport, backlog, Inet4Address.ANY);
     }
 
     /**
@@ -127,7 +127,7 @@
         checkListen(aport);
         impl = factory != null ? factory.createSocketImpl()
                 : new PlainServerSocketImpl();
-        InetAddress addr = localAddr == null ? InetAddress.ANY : localAddr;
+        InetAddress addr = localAddr == null ? Inet4Address.ANY : localAddr;
 
         synchronized (this) {
             impl.create(true);
@@ -391,7 +391,7 @@
             throw new BindException(Msg.getString("K0315")); //$NON-NLS-1$
         }
         int port = 0;
-        InetAddress addr = InetAddress.ANY;
+        InetAddress addr = Inet4Address.ANY;
         if (localAddr != null) {
             if (!(localAddr instanceof InetSocketAddress)) {
                 throw new IllegalArgumentException(Msg.getString(
diff --git a/libcore/luni/src/main/java/java/net/Socket.java b/libcore/luni/src/main/java/java/net/Socket.java
index 71a1bf2..5289566 100644
--- a/libcore/luni/src/main/java/java/net/Socket.java
+++ b/libcore/luni/src/main/java/java/net/Socket.java
@@ -479,7 +479,7 @@
      */
     public InetAddress getLocalAddress() {
         if (!isBound()) {
-            return InetAddress.ANY;
+            return Inet4Address.ANY;
         }
         return Platform.getNetworkSystem().getSocketLocalAddress(impl.fd,
                 InetAddress.preferIPv6Addresses());
@@ -767,7 +767,7 @@
             throw new IllegalArgumentException(Msg.getString("K0046")); //$NON-NLS-1$
         }
 
-        InetAddress addr = localAddress == null ? InetAddress.ANY
+        InetAddress addr = localAddress == null ? Inet4Address.ANY
                 : localAddress;
         synchronized (this) {
             impl.create(streaming);
@@ -955,7 +955,7 @@
         }
 
         int port = 0;
-        InetAddress addr = InetAddress.ANY;
+        InetAddress addr = Inet4Address.ANY;
         if (localAddr != null) {
             if (!(localAddr instanceof InetSocketAddress)) {
                 throw new IllegalArgumentException(Msg.getString(
@@ -1047,7 +1047,7 @@
                     // options on create
                     // impl.create(true);
                     if (!NetUtil.usingSocks(proxy)) {
-                        impl.bind(InetAddress.ANY, 0);
+                        impl.bind(Inet4Address.ANY, 0);
                     }
                     isBound = true;
                 }
diff --git a/libcore/luni/src/main/java/java/util/HashMap.java b/libcore/luni/src/main/java/java/util/HashMap.java
index 999063d..af24d86 100644
--- a/libcore/luni/src/main/java/java/util/HashMap.java
+++ b/libcore/luni/src/main/java/java/util/HashMap.java
@@ -1,10 +1,10 @@
 /*
  *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
+ *  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
+ *  the License. You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
@@ -15,279 +15,102 @@
  *  limitations under the License.
  */
 
+// BEGIN android-note
+// Completely different implementation from harmony.  Runs much faster.
+// BEGIN android-note
+
 package java.util;
 
 import java.io.IOException;
+import java.io.InvalidObjectException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
 import java.io.Serializable;
 
 /**
  * HashMap is an implementation of Map. All optional operations (adding and
  * removing) are supported. Keys and values can be any objects.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
  */
-public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>,
-        Cloneable, Serializable {
-
-    private static final long serialVersionUID = 362498820763181265L;
-
-    /*
-     * Actual count of entries
+public class HashMap<K, V> extends AbstractMap<K, V>
+        implements Cloneable, Serializable, Map<K, V> {
+    /**
+     * Min capacity (other than zero) for a HashMap. Must be a power of two
+     * greater than 1 (and less than 1 << 30).
      */
-    transient int elementCount;
-
-    /*
-     * The internal data structure to hold Entries
-     */
-    transient Entry<K, V>[] elementData;
-
-    /*
-     * modification count, to keep track of structural modifications between the
-     * HashMap and the iterator
-     */
-    transient int modCount = 0;
-
-    /*
-     * default size that an HashMap created using the default constructor would
-     * have.
-     */
-    private static final int DEFAULT_SIZE = 16;
-
-    /*
-     * maximum ratio of (stored elements)/(storage size) which does not lead to
-     * rehash
-     */
-    final float loadFactor;
-
-    /*
-     * maximum number of elements that can be put in this map before having to
-     * rehash
-     */
-    int threshold;
-
-    static class Entry<K, V> extends MapEntry<K, V> {
-        final int origKeyHash;
-
-        Entry<K, V> next;
-
-        Entry(K theKey, int hash) {
-            super(theKey, null);
-            this.origKeyHash = hash;
-        }
-
-        Entry(K theKey, V theValue) {
-            super(theKey, theValue);
-            origKeyHash = (theKey == null ? 0 : computeHashCode(theKey));
-        }
-
-        @Override
-        @SuppressWarnings("unchecked")
-        public Object clone() {
-            Entry<K, V> entry = (Entry<K, V>) super.clone();
-            if (next != null) {
-                entry.next = (Entry<K, V>) next.clone();
-            }
-            return entry;
-        }
-    }
-
-    private static class AbstractMapIterator<K, V>  {
-        private int position = 0;
-        int expectedModCount;
-        Entry<K, V> futureEntry;
-        Entry<K, V> currentEntry;
-        Entry<K, V> prevEntry;
-
-        final HashMap<K, V> associatedMap;
-
-        AbstractMapIterator(HashMap<K, V> hm) {
-            associatedMap = hm;
-            expectedModCount = hm.modCount;
-            futureEntry = null;
-        }
-
-        public boolean hasNext() {
-            if (futureEntry != null) {
-                return true;
-            }
-            // BEGIN android-changed
-            Entry<K, V>[] elementData = associatedMap.elementData;
-            int length = elementData.length;
-            int newPosition = position;
-            boolean result = false;
-
-            while (newPosition < length) {
-                if (elementData[newPosition] == null) {
-                    newPosition++;
-                } else {
-                    result = true;
-                    break;
-                }
-            }
-
-            position = newPosition;
-            return result;
-            // END android-changed
-        }
-
-        final void checkConcurrentMod() throws ConcurrentModificationException {
-            if (expectedModCount != associatedMap.modCount) {
-                throw new ConcurrentModificationException();
-            }
-        }
-
-        final void makeNext() {
-            // BEGIN android-changed
-            // inline checkConcurrentMod()
-            if (expectedModCount != associatedMap.modCount) {
-                throw new ConcurrentModificationException();
-            }
-            // END android-changed
-            if (!hasNext()) {
-                throw new NoSuchElementException();
-            }
-            if (futureEntry == null) {
-                currentEntry = associatedMap.elementData[position++];
-                futureEntry = currentEntry.next;
-                prevEntry = null;
-            } else {
-                if(currentEntry!=null){
-                    prevEntry = currentEntry;
-                }
-                currentEntry = futureEntry;
-                futureEntry = futureEntry.next;
-            }
-        }
-
-        public final void remove() {
-            checkConcurrentMod();
-            if (currentEntry==null) {
-                throw new IllegalStateException();
-            }
-            if(prevEntry==null){
-                int index = currentEntry.origKeyHash & (associatedMap.elementData.length - 1);
-                associatedMap.elementData[index] = associatedMap.elementData[index].next;
-            } else {
-                prevEntry.next = currentEntry.next;
-            }
-            currentEntry = null;
-            expectedModCount++;
-            associatedMap.modCount++;
-            associatedMap.elementCount--;
-
-        }
-    }
-
-
-    private static class EntryIterator <K, V> extends AbstractMapIterator<K, V> implements Iterator<Map.Entry<K, V>> {
-
-        EntryIterator (HashMap<K, V> map) {
-            super(map);
-        }
-
-        public Map.Entry<K, V> next() {
-            makeNext();
-            return currentEntry;
-        }
-    }
-
-    private static class KeyIterator <K, V> extends AbstractMapIterator<K, V> implements Iterator<K> {
-
-        KeyIterator (HashMap<K, V> map) {
-            super(map);
-        }
-
-        public K next() {
-            makeNext();
-            return currentEntry.key;
-        }
-    }
-
-    private static class ValueIterator <K, V> extends AbstractMapIterator<K, V> implements Iterator<V> {
-
-        ValueIterator (HashMap<K, V> map) {
-            super(map);
-        }
-
-        public V next() {
-            makeNext();
-            return currentEntry.value;
-        }
-    }
-
-    static class HashMapEntrySet<KT, VT> extends AbstractSet<Map.Entry<KT, VT>> {
-        private final HashMap<KT, VT> associatedMap;
-
-        public HashMapEntrySet(HashMap<KT, VT> hm) {
-            associatedMap = hm;
-        }
-
-        HashMap<KT, VT> hashMap() {
-            return associatedMap;
-        }
-
-        @Override
-        public int size() {
-            return associatedMap.elementCount;
-        }
-
-        @Override
-        public void clear() {
-            associatedMap.clear();
-        }
-
-        @Override
-        public boolean remove(Object object) {
-            if (object instanceof Map.Entry) {
-                Map.Entry<?, ?> oEntry = (Map.Entry<?, ?>) object;
-                Entry<KT,VT> entry = associatedMap.getEntry(oEntry.getKey());
-                if(valuesEq(entry, oEntry)) {
-                    associatedMap.removeEntry(entry);
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        @Override
-        public boolean contains(Object object) {
-            if (object instanceof Map.Entry) {
-                Map.Entry<?, ?> oEntry = (Map.Entry<?, ?>) object;
-                Entry<KT, VT> entry = associatedMap.getEntry(oEntry.getKey());
-                return valuesEq(entry, oEntry);
-            }
-            return false;
-        }
-
-        private static boolean valuesEq(Entry entry, Map.Entry<?, ?> oEntry) {
-            return (entry != null) &&
-                                   ((entry.value == null) ?
-                                    (oEntry.getValue() == null) :
-                                    (areEqualValues(entry.value, oEntry.getValue())));
-        }
-
-        @Override
-        public Iterator<Map.Entry<KT, VT>> iterator() {
-            return new EntryIterator<KT,VT> (associatedMap);
-        }
-    }
+    private static final int MINIMUM_CAPACITY = 4;
 
     /**
-     * Create a new element array
-     *
-     * @param s
-     * @return Reference to the element array
+     * Max capacity for a HashMap. Must be a power of two >= MINIMUM_CAPACITY.
      */
-    @SuppressWarnings("unchecked")
-    Entry<K, V>[] newElementArray(int s) {
-        return new Entry[s];
-    }
+    private static final int MAXIMUM_CAPACITY = 1 << 30;
+
+    /**
+     * An empty table shared by all zero-capacity maps (typically from default
+     * constructor). It is never written to, and replaced on first put. Its size
+     * is set to half the minimum, so that the first resize will create a
+     * minimum-sized table.
+     */
+    private static final Entry[] EMPTY_TABLE
+            = new HashMapEntry[MINIMUM_CAPACITY >>> 1];
+
+    /**
+     * The default load factor. Note that this implementation ignores the
+     * load factor, but cannot do away with it entirely because it's
+     * metioned in the API.
+     *
+     * <p>Note that this constant has no impact on the behavior of the program,
+     * but it is emitted as part of the serialized form. The load factor of
+     * .75 is hardwired into the program, which uses cheap shifts in place of
+     * expensive division.
+     */
+    static final float DEFAULT_LOAD_FACTOR = .75F;
+
+    /**
+     * The hash table. If this hash map contains a mapping for null, it is
+     * not represented this hash table.
+     */
+    transient HashMapEntry<K, V>[] table;
+
+    /**
+     * The entry representing the null key, or null if there's no such mapping.
+     */
+    transient HashMapEntry<K, V> entryForNullKey;
+
+    /**
+     * The number of mappings in this hash map.
+     */
+    transient int size;
+
+    /**
+     * Incremented by "structural modifications" to allow (best effort)
+     * detection of concurrent modification.
+     */
+    transient int modCount;
+
+    /**
+     * The table is rehashed when its size exceeds this threshold.
+     * The value of this field is generally .75 * capacity, except when
+     * the capacity is zero, as described in the EMPTY_TABLE declaration
+     * above.
+     */
+    private transient int threshold;
+
+    // Views - lazily initialized
+    private transient Set<K> keySet;
+    private transient Set<Entry<K, V>> entrySet;
+    private transient Collection<V> values;
 
     /**
      * Constructs a new empty {@code HashMap} instance.
      */
+    @SuppressWarnings("unchecked")
     public HashMap() {
-        this(DEFAULT_SIZE);
+        table = (HashMapEntry<K, V>[]) EMPTY_TABLE;
+        threshold = -1; // Forces first put invocation to replace EMPTY_TABLE
     }
 
     /**
@@ -299,34 +122,26 @@
      *                when the capacity is less than zero.
      */
     public HashMap(int capacity) {
-        this(capacity, 0.75f);  // default load factor of 0.75
+        if (capacity < 0) {
+            throw new IllegalArgumentException("Capacity: " + capacity);
         }
 
-    /**
-     * Calculates the capacity of storage required for storing given number of
-     * elements
-     *
-     * @param x
-     *            number of elements
-     * @return storage size
-     */
-    private static final int calculateCapacity(int x) {
-        if(x >= 1 << 30){
-            return 1 << 30;
+        if (capacity == 0) {
+            @SuppressWarnings("unchecked")
+            HashMapEntry<K, V>[] tab = (HashMapEntry<K, V>[]) EMPTY_TABLE;
+            table = tab;
+            threshold = -1; // Forces first put() to replace EMPTY_TABLE
+            return;
         }
-        if(x == 0){
-            return 16;
+
+        if (capacity < MINIMUM_CAPACITY) {
+            capacity = MINIMUM_CAPACITY;
+        } else if (capacity > MAXIMUM_CAPACITY) {
+            capacity = MAXIMUM_CAPACITY;
+        } else {
+            capacity = roundUpToPowerOfTwo(capacity);
         }
-        // BEGIN android-note
-        // this may be better optimized as Integer.highestOneBit(x)
-        // END android-note
-        x = x -1;
-        x |= x >> 1;
-        x |= x >> 2;
-        x |= x >> 4;
-        x |= x >> 8;
-        x |= x >> 16;
-        return x + 1;
+        makeTable(capacity);
     }
 
     /**
@@ -339,18 +154,20 @@
      *            the initial load factor.
      * @throws IllegalArgumentException
      *                when the capacity is less than zero or the load factor is
-     *                less or equal to zero.
+     *                less or equal to zero or NaN.
      */
     public HashMap(int capacity, float loadFactor) {
-        if (capacity >= 0 && loadFactor > 0) {
-            capacity = calculateCapacity(capacity);
-            elementCount = 0;
-            elementData = newElementArray(capacity);
-            this.loadFactor = loadFactor;
-            computeThreshold();
-        } else {
-            throw new IllegalArgumentException();
+        this(capacity);
+
+        if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
+            throw new IllegalArgumentException("Load factor: " + loadFactor);
         }
+
+        /*
+         * Note that this implementation ignores loadFactor; it always uses
+         * a load facator of 3/4. This simplifies the code and generally
+         * improves performance.
+         */
     }
 
     /**
@@ -361,118 +178,92 @@
      *            the mappings to add.
      */
     public HashMap(Map<? extends K, ? extends V> map) {
-        this(calculateCapacity(map.size()));
-        putAllImpl(map);
+        this(capacityForInitSize(map.size()));
+        constructorPutAll(map);
     }
 
     /**
-     * Removes all mappings from this hash map, leaving it empty.
-     *
-     * @see #isEmpty
-     * @see #size
+     * Inserts all of the elements of map into this HashMap in a manner
+     * suitable for use by constructors and pseudocostructors (i.e., clone,
+     * readObject). Also used by LinkedHashMap.
      */
-    @Override
-    public void clear() {
-        // BEGIN android-changed
-        internalClear();
-        // END android-changed
-    }
-
-    // BEGIN android-added
-    void internalClear() {
-        if (elementCount > 0) {
-            elementCount = 0;
-            Arrays.fill(elementData, null);
-            modCount++;
+    final void constructorPutAll(Map<? extends K, ? extends V> map) {
+        for (Entry<? extends K, ? extends V> e : map.entrySet()) {
+            constructorPut(e.getKey(), e.getValue());
         }
     }
-    // END android-added
+
+    /**
+     * Returns an appropriate capacity for the specified initial size. Does
+     * not round the result up to a power of two; the caller must do this!
+     * The returned value will be between 0 and MAXIMUM_CAPACITY (inclusive).
+     */
+    static int capacityForInitSize(int size) {
+        int result = (size >> 1) + size; // Multiply by 3/2 to allow for growth
+
+        // boolean expr is equivalent to result >= 0 && result<MAXIMUM_CAPACITY
+        return (result & ~(MAXIMUM_CAPACITY-1))==0 ? result : MAXIMUM_CAPACITY;
+    }
 
     /**
      * Returns a shallow copy of this map.
      *
      * @return a shallow copy of this map.
      */
-    @Override
     @SuppressWarnings("unchecked")
-    public Object clone() {
+    @Override public Object clone() {
+        /*
+         * This could be made more efficient. It unnecessarily hashes all of
+         * the elements in the map.
+         */
+        HashMap<K, V> result;
         try {
-            HashMap<K, V> map = (HashMap<K, V>) super.clone();
-            map.elementCount = 0;
-            map.elementData = newElementArray(elementData.length);
-            map.putAll(this);
-
-            return map;
+            result = (HashMap<K, V>) super.clone();
         } catch (CloneNotSupportedException e) {
-            return null;
+            throw new AssertionError(e);
         }
+
+        // Restore clone to empty state, retaining our capacity and threshold
+        result.makeTable(table.length);
+        result.entryForNullKey = null;
+        result.size = 0;
+        result.keySet = null;
+        result.entrySet = null;
+        result.values = null;
+
+        result.init(); // Give subclass a chance to initialize itself
+        result.constructorPutAll(this); // Calls method overridden in subclass!!
+        return result;
     }
 
     /**
-     * Computes the threshold for rehashing
+     * This method is called from the pseudo-constructors (clone and readObject)
+     * prior to invoking constructorPut/constructorPutAll, which invoke the
+     * overriden constructorNewEntry method. Normally it is a VERY bad idea to
+     * invoke an overridden method from a pseudo-constructor (Effective Java
+     * Item 17). In this cases it is unavoidable, and the init method provides a
+     * workaround.
      */
-    private void computeThreshold() {
-        threshold = (int) (elementData.length * loadFactor);
-    }
+    void init() { }
 
     /**
-     * Returns whether this map contains the specified key.
+     * Returns whether this map is empty.
      *
-     * @param key
-     *            the key to search for.
-     * @return {@code true} if this map contains the specified key,
-     *         {@code false} otherwise.
+     * @return {@code true} if this map has no elements, {@code false}
+     *         otherwise.
+     * @see #size()
      */
-    @Override
-    public boolean containsKey(Object key) {
-        Entry<K, V> m = getEntry(key);
-        return m != null;
+    @Override public boolean isEmpty() {
+        return size == 0;
     }
 
     /**
-     * Returns whether this map contains the specified value.
+     * Returns the number of elements in this map.
      *
-     * @param value
-     *            the value to search for.
-     * @return {@code true} if this map contains the specified value,
-     *         {@code false} otherwise.
+     * @return the number of elements in this map.
      */
-    @Override
-    public boolean containsValue(Object value) {
-        if (value != null) {
-            for (int i = 0; i < elementData.length; i++) {
-                Entry<K, V> entry = elementData[i];
-                while (entry != null) {
-                    if (areEqualValues(value, entry.value)) {
-                        return true;
-                    }
-                    entry = entry.next;
-                }
-            }
-        } else {
-            for (int i = 0; i < elementData.length; i++) {
-                Entry<K, V> entry = elementData[i];
-                while (entry != null) {
-                    if (entry.value == null) {
-                        return true;
-                    }
-                    entry = entry.next;
-                }
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Returns a set containing all of the mappings in this map. Each mapping is
-     * an instance of {@link Map.Entry}. As the set is backed by this map,
-     * changes in one will be reflected in the other.
-     *
-     * @return a set of the mappings.
-     */
-    @Override
-    public Set<Map.Entry<K, V>> entrySet() {
-        return new HashMapEntrySet<K, V>(this);
+    @Override public int size() {
+        return size;
     }
 
     /**
@@ -483,104 +274,88 @@
      * @return the value of the mapping with the specified key, or {@code null}
      *         if no mapping for the specified key is found.
      */
-    @Override
     public V get(Object key) {
-        Entry<K, V> m = getEntry(key);
-        if (m != null) {
-            return m.value;
+        if (key == null) {
+            HashMapEntry<K, V> e = entryForNullKey;
+            return e == null ? null : e.value;
+        }
+
+        // Doug Lea's supplemental secondaryHash function (inlined)
+        int hash = key.hashCode();
+        hash ^= (hash >>> 20) ^ (hash >>> 12);
+        hash ^= (hash >>> 7) ^ (hash >>> 4);
+
+        HashMapEntry<K, V>[] tab = table;
+        for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)];
+                e != null; e = e.next) {
+            K eKey = e.key;
+            if (eKey == key || (e.hash == hash && key.equals(eKey))) {
+                return e.value;
+            }
         }
         return null;
     }
 
-    final Entry<K, V> getEntry(Object key) {
-        Entry<K, V> m;
+    /**
+     * Returns whether this map contains the specified key.
+     *
+     * @param key
+     *            the key to search for.
+     * @return {@code true} if this map contains the specified key,
+     *         {@code false} otherwise.
+     */
+    @Override public boolean containsKey(Object key) {
         if (key == null) {
-            m = findNullKeyEntry();
-        } else {
-            int hash = computeHashCode(key);
-            int index = hash & (elementData.length - 1);
-            m = findNonNullKeyEntry(key, index, hash);
+            return entryForNullKey != null;
         }
-        return m;
-    }
 
-    final Entry<K,V> findNonNullKeyEntry(Object key, int index, int keyHash) {
-        Entry<K,V> m = elementData[index];
+        // Doug Lea's supplemental secondaryHash function (inlined)
+        int hash = key.hashCode();
+        hash ^= (hash >>> 20) ^ (hash >>> 12);
+        hash ^= (hash >>> 7) ^ (hash >>> 4);
 
-        // BEGIN android-changed
-        // The VM can optimize String.equals but not Object.equals
-        if (key instanceof String) {
-            String keyString = (String) key;
-            while (m != null && (m.origKeyHash != keyHash || !keyString.equals(m.key))) {
-                m = m.next;
-            }
-        } else {
-            while (m != null && (m.origKeyHash != keyHash || !areEqualKeys(key, m.key))) {
-                m = m.next;
+        HashMapEntry<K, V>[] tab = table;
+        for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)];
+                e != null; e = e.next) {
+            K eKey = e.key;
+            if (eKey == key || (e.hash == hash && key.equals(eKey))) {
+                return true;
             }
         }
-        return m;
-        // END android-changed
-    }
-
-    final Entry<K,V> findNullKeyEntry() {
-        Entry<K,V> m = elementData[0];
-        while (m != null && m.key != null)
-            m = m.next;
-        return m;
+        return false;
     }
 
     /**
-     * Returns whether this map is empty.
+     * Returns whether this map contains the specified value.
      *
-     * @return {@code true} if this map has no elements, {@code false}
-     *         otherwise.
-     * @see #size()
+     * @param value
+     *            the value to search for.
+     * @return {@code true} if this map contains the specified value,
+     *         {@code false} otherwise.
      */
-    @Override
-    public boolean isEmpty() {
-        return elementCount == 0;
-    }
-
-    /**
-     * Returns a set of the keys contained in this map. The set is backed by
-     * this map so changes to one are reflected by the other. The set does not
-     * support adding.
-     *
-     * @return a set of the keys.
-     */
-    @Override
-    public Set<K> keySet() {
-        if (keySet == null) {
-            keySet = new AbstractSet<K>() {
-                @Override
-                public boolean contains(Object object) {
-                    return containsKey(object);
+    @Override public boolean containsValue(Object value) {
+        HashMapEntry[] tab = table;
+        int len = tab.length;
+        if (value == null) {
+            for (int i = 0; i < len; i++) {
+                for (HashMapEntry e = tab[i]; e != null; e = e.next) {
+                    if (e.value == null) {
+                        return true;
+                    }
                 }
-
-                @Override
-                public int size() {
-                    return HashMap.this.size();
-                }
-
-                @Override
-                public void clear() {
-                    HashMap.this.clear();
-                }
-
-                @Override
-                public boolean remove(Object key) {
-                    Entry<K, V> entry = HashMap.this.removeEntry(key);
-                    return entry != null;
-                }
-
-                @Override
-                public Iterator<K> iterator() {
-                    return new KeyIterator<K,V> (HashMap.this);
-                }
-            };
+            }
+            return entryForNullKey != null && entryForNullKey.value == null;
         }
-        return keySet;
+
+        // value is non-null
+        for (int i = 0; i < len; i++) {
+            for (HashMapEntry e = tab[i]; e != null; e = e.next) {
+                if (value.equals(e.value)) {
+                    return true;
+                }
+            }
+        }
+        return entryForNullKey != null && value.equals(entryForNullKey.value);
     }
 
     /**
@@ -593,53 +368,110 @@
      * @return the value of any previous mapping with the specified key or
      *         {@code null} if there was no such mapping.
      */
-    @Override
-    public V put(K key, V value) {
-        return putImpl(key, value);
-    }
+    @Override public V put(K key, V value) {
+        if (key == null) {
+            return putValueForNullKey(value);
+        }
 
-    V putImpl(K key, V value) {
-        Entry<K,V> entry;
-        if(key == null) {
-            entry = findNullKeyEntry();
-            if (entry == null) {
-                modCount++;
-                if (++elementCount > threshold) {
-                    rehash();
-                }
-                entry = createHashedEntry(null, 0, 0);
-            }
-        } else {
-            int hash = computeHashCode(key);
-            int index = hash & (elementData.length - 1);
-            entry = findNonNullKeyEntry(key, index, hash);
-            if (entry == null) {
-                modCount++;
-                if (++elementCount > threshold) {
-                    rehash();
-                    index = hash & (elementData.length - 1);
-                }
-                entry = createHashedEntry(key, index, hash);
+        int hash = secondaryHash(key.hashCode());
+        HashMapEntry<K, V>[] tab = table;
+        int index = hash & (tab.length - 1);
+        HashMapEntry<K, V> first = tab[index];
+        for (HashMapEntry<K, V> e = first; e != null; e = e.next) {
+            if (e.hash == hash && key.equals(e.key)) {
+                preModify(e);
+                V oldValue = e.value;
+                e.value = value;
+                return oldValue;
             }
         }
 
-        V result = entry.value;
-        entry.value = value;
-        return result;
+        // No entry for (non-null) key is present; create one
+        modCount++;
+        if (size++ > threshold) {
+            tab = doubleCapacity();
+            index = hash & (tab.length - 1);
+            first = tab[index];
+        }
+        tab[index] = newEntry(key, value, hash, first);
+        return null;
     }
 
-    Entry<K, V> createEntry(K key, int index, V value) {
-        Entry<K, V> entry = new Entry<K, V>(key, value);
-        entry.next = elementData[index];
-        elementData[index] = entry;
-        return entry;
+    private V putValueForNullKey(V value) {
+        HashMapEntry<K, V> entry = entryForNullKey;
+        if (entry == null) {
+            entryForNullKey = newEntry(null, value, 0, null);
+            size++;
+            modCount++;
+            return null;
+        } else {
+            preModify(entry);
+            V oldValue = entry.value;
+            entry.value = value;
+            return oldValue;
+        }
     }
 
-    Entry<K,V> createHashedEntry(K key, int index, int hash) {
-        Entry<K,V> entry = new Entry<K,V>(key,hash);
-        entry.next = elementData[index];
-        elementData[index] = entry;
-        return entry;
+    /**
+     * Give LinkedHashMap a chance to take action when we modify an exisitng
+     * entry.
+     *
+     * @param e the entry we're about to modify.
+     */
+    void preModify(HashMapEntry<K, V> e) { }
+
+    /**
+     * This method is just like put, except that it doesn't do things that
+     * are inappropriate or unnecessary for constructors and pseudo-constructors
+     * (i.e., clone, readObject). In particular, this method does not check to
+     * ensure that capacity is sufficient, and does not increment modCount.
+     */
+    private void constructorPut(K key, V value) {
+        if (key == null) {
+            HashMapEntry<K, V> entry = entryForNullKey;
+            if (entry == null) {
+                entryForNullKey = constructorNewEntry(null, value, 0, null);
+                size++;
+            } else {
+                entry.value = value;
+            }
+            return;
+        }
+
+        int hash = secondaryHash(key.hashCode());
+        HashMapEntry<K, V>[] tab = table;
+        int index = hash & (tab.length - 1);
+        HashMapEntry<K, V> first = tab[index];
+        for (HashMapEntry<K, V> e = first; e != null; e = e.next) {
+            if (e.hash == hash && key.equals(e.key)) {
+                e.value = value;
+                return;
+            }
+        }
+
+        // No entry for (non-null) key is present; create one
+        tab[index] = constructorNewEntry(key, value, hash, first);
+        size++;
+    }
+
+    /**
+     * Creates a new entry for the given key, value, hash, and successor entry.
+     * This method is called by put (and indirectly, putAll), and overridden by
+     * LinkedHashMap. The hash must incorporate the secondary hash function.
+     */
+    HashMapEntry<K, V> newEntry(
+            K key, V value, int hash, HashMapEntry<K, V> next) {
+        return new HashMapEntry<K, V>(key, value, hash, next);
+    }
+
+    /**
+     * Like newEntry, but does not perform any activity that would be
+     * unnecessary or inappropriate for constructors. In this class, the
+     * two methods behave identically; in LinkedHashMap, they differ.
+     */
+    HashMapEntry<K, V> constructorNewEntry(
+            K key, V value, int hash, HashMapEntry<K, V> first) {
+        return new HashMapEntry<K, V>(key, value, hash, first);
     }
 
     /**
@@ -649,46 +481,108 @@
      *
      * @param map
      *            the map to copy mappings from.
-     * @throws NullPointerException
-     *             if {@code map} is {@code null}.
      */
-    @Override
-    public void putAll(Map<? extends K, ? extends V> map) {
-        if (!map.isEmpty()) {
-            putAllImpl(map);
-        }
+    @Override public void putAll(Map<? extends K, ? extends V> map) {
+        ensureCapacity(map.size());
+        super.putAll(map);
     }
 
-    private void putAllImpl(Map<? extends K, ? extends V> map) {
-        int capacity = elementCount + map.size();
-        if (capacity > threshold) {
-            rehash(capacity);
+    /**
+     * Ensures that the hash table has sufficient capacity to store the
+     * specified number of mappings, with room to grow. If not, it increases the
+     * capacity as appropriate. Like doubleCapacity, this method moves existing
+     * entries to new buckets as appropriate. Unlike doubleCapacity, this method
+     * can grow the table by factors of 2^n for n > 1. Hopefully, a single call
+     * to this method will be faster than multiple calls to doubleCapacity.
+     *
+     *  <p>This method is called only by putAll.
+     */
+    private void ensureCapacity(int numMappings) {
+        int newCapacity = roundUpToPowerOfTwo(capacityForInitSize(numMappings));
+        HashMapEntry<K, V>[] oldTable = table;
+        int oldCapacity = oldTable.length;
+        if (newCapacity <= oldCapacity) {
+            return;
         }
-        for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
-            putImpl(entry.getKey(), entry.getValue());
+        if (newCapacity == oldCapacity << 1) {
+            doubleCapacity();
+            return;
         }
-    }
 
-    void rehash(int capacity) {
-        int length = calculateCapacity((capacity == 0 ? 1 : capacity << 1));
-
-        Entry<K, V>[] newData = newElementArray(length);
-        for (int i = 0; i < elementData.length; i++) {
-            Entry<K, V> entry = elementData[i];
-            while (entry != null) {
-                int index = entry.origKeyHash & (length - 1);
-                Entry<K, V> next = entry.next;
-                entry.next = newData[index];
-                newData[index] = entry;
-                entry = next;
+        // We're growing by at least 4x, rehash in the obvious way
+        HashMapEntry<K, V>[] newTable = makeTable(newCapacity);
+        if (size != 0) {
+            int newMask = newCapacity - 1;
+            for (int i = 0; i < oldCapacity; i++) {
+                for (HashMapEntry<K, V> e = oldTable[i]; e != null;) {
+                    HashMapEntry<K, V> oldNext = e.next;
+                    int newIndex = e.hash & newMask;
+                    HashMapEntry<K, V> newNext = newTable[newIndex];
+                    newTable[newIndex] = e;
+                    e.next = newNext;
+                    e = oldNext;
+                }
             }
         }
-        elementData = newData;
-        computeThreshold();
     }
 
-    void rehash() {
-        rehash(elementData.length);
+    /**
+     * Allocate a table of the given capacity and set the threshold accordingly.
+     * @param newCapacity must be a power of two
+     */
+    private HashMapEntry<K, V>[] makeTable(int newCapacity) {
+        @SuppressWarnings("unchecked") HashMapEntry<K, V>[] newTable
+                = (HashMapEntry<K, V>[]) new HashMapEntry[newCapacity];
+        table = newTable;
+        threshold = (newCapacity >> 1) + (newCapacity >> 2); // 3/4 capacity
+        return newTable;
+    }
+
+    /**
+     * Doubles the capacity of the hash table. Existing entries are placed in
+     * the correct bucket on the enlarged table. If the current capacity is,
+     * MAXIMUM_CAPACITY, this method is a no-op. Returns the table, which
+     * will be new unless we were already at MAXIMUM_CAPACITY.
+     */
+    private HashMapEntry<K, V>[] doubleCapacity() {
+        HashMapEntry<K, V>[] oldTable = table;
+        int oldCapacity = oldTable.length;
+        if (oldCapacity == MAXIMUM_CAPACITY) {
+            return oldTable;
+        }
+        int newCapacity = oldCapacity << 1;
+        HashMapEntry<K, V>[] newTable = makeTable(newCapacity);
+        if (size == 0) {
+            return newTable;
+        }
+
+        for (int j = 0; j < oldCapacity; j++) {
+            /*
+             * Rehash the bucket using the minimum number of field writes.
+             * This is the most subtle and delicate code in the class.
+             */
+            HashMapEntry<K, V> e = oldTable[j];
+            if (e == null) {
+                continue;
+            }
+            int highBit = e.hash & oldCapacity;
+            HashMapEntry<K, V> broken = null;
+            newTable[j | highBit] = e;
+            for (HashMapEntry<K, V> n = e.next; n != null; e = n, n = n.next) {
+                int nextHighBit = n.hash & oldCapacity;
+                if (nextHighBit != highBit) {
+                    if (broken == null)
+                        newTable[j | nextHighBit] = n;
+                    else
+                        broken.next = n;
+                    broken = e;
+                    highBit = nextHighBit;
+                }
+            }
+            if (broken != null)
+                broken.next = null;
+        }
+        return newTable;
     }
 
     /**
@@ -699,75 +593,72 @@
      * @return the value of the removed mapping or {@code null} if no mapping
      *         for the specified key was found.
      */
-    @Override
-    public V remove(Object key) {
-        Entry<K, V> entry = removeEntry(key);
-        if (entry != null) {
-            return entry.value;
+    @Override public V remove(Object key) {
+        if (key == null) {
+            return removeNullKey();
+        }
+        int hash = secondaryHash(key.hashCode());
+        HashMapEntry<K, V>[] tab = table;
+        int index = hash & (tab.length - 1);
+        for (HashMapEntry<K, V> e = tab[index], prev = null;
+                e != null; prev = e, e = e.next) {
+            if (e.hash == hash && key.equals(e.key)) {
+                if (prev == null) {
+                    tab[index] = e.next;
+                } else {
+                    prev.next = e.next;
+                }
+                modCount++;
+                size--;
+                postRemove(e);
+                return e.value;
+            }
         }
         return null;
     }
 
-    /*
-     * Remove the given entry from the hashmap.
-     * Assumes that the entry is in the map.
-     */
-    final void removeEntry(Entry<K, V> entry) {
-        int index = entry.origKeyHash & (elementData.length - 1);
-        Entry<K, V> m = elementData[index];
-        if (m == entry) {
-            elementData[index] = entry.next;
-        } else {
-            while (m.next != entry) {
-                m = m.next;
-            }
-            m.next = entry.next;
-
-        }
-        modCount++;
-        elementCount--;
-    }
-
-    final Entry<K, V> removeEntry(Object key) {
-        int index = 0;
-        Entry<K, V> entry;
-        Entry<K, V> last = null;
-        if (key != null) {
-            int hash = computeHashCode(key);
-            index = hash & (elementData.length - 1);
-            entry = elementData[index];
-            while (entry != null && !(entry.origKeyHash == hash && areEqualKeys(key, entry.key))) {
-                last = entry;
-                entry = entry.next;
-            }
-        } else {
-            entry = elementData[0];
-            while (entry != null && entry.key != null) {
-                last = entry;
-                entry = entry.next;
-            }
-        }
-        if (entry == null) {
+    private V removeNullKey() {
+        HashMapEntry<K, V> e = entryForNullKey;
+        if (e == null) {
             return null;
         }
-        if (last == null) {
-            elementData[index] = entry.next;
-        } else {
-            last.next = entry.next;
-        }
+        entryForNullKey = null;
         modCount++;
-        elementCount--;
-        return entry;
+        size--;
+        postRemove(e);
+        return e.value;
     }
 
     /**
-     * Returns the number of elements in this map.
-     *
-     * @return the number of elements in this map.
+     * Subclass overrides this method to unlink entry.
      */
-    @Override
-    public int size() {
-        return elementCount;
+    void postRemove(HashMapEntry<K, V> e) { }
+
+    /**
+     * Removes all mappings from this hash map, leaving it empty.
+     *
+     * @see #isEmpty
+     * @see #size
+     */
+    @Override public void clear() {
+        if (size != 0) {
+            Arrays.fill(table, null);
+            entryForNullKey = null;
+            modCount++;
+            size = 0;
+        }
+    }
+
+    /**
+     * Returns a set of the keys contained in this map. The set is backed by
+     * this map so changes to one are reflected by the other. The set does not
+     * support adding.
+     *
+     * @return a set of the keys.
+     */
+    @Override public Set<K> keySet() {
+        Set<K> ks = keySet;
+        return (ks != null) ? ks : (keySet = new KeySet());
     }
 
     /**
@@ -781,83 +672,363 @@
      * "wrapper object" over the iterator of map's entrySet(). The {@code size}
      * method wraps the map's size method and the {@code contains} method wraps
      * the map's containsValue method.
+     * </p>
      * <p>
      * The collection is created when this method is called for the first time
      * and returned in response to all subsequent calls. This method may return
      * different collections when multiple concurrent calls occur, since no
      * synchronization is performed.
+     * </p>
      *
      * @return a collection of the values contained in this map.
      */
-    @Override
-    public Collection<V> values() {
-        if (valuesCollection == null) {
-            valuesCollection = new AbstractCollection<V>() {
-                @Override
-                public boolean contains(Object object) {
-                    return containsValue(object);
-                }
-
-                @Override
-                public int size() {
-                    return HashMap.this.size();
-                }
-
-                @Override
-                public void clear() {
-                    HashMap.this.clear();
-                }
-
-                @Override
-                public Iterator<V> iterator() {
-                    return new ValueIterator<K,V> (HashMap.this);
-                }
-            };
-        }
-        return valuesCollection;
+    @Override public Collection<V> values() {
+        Collection<V> vs = values;
+        return (vs != null) ? vs : (values = new Values());
     }
 
+    /**
+     * Returns a set containing all of the mappings in this map. Each mapping is
+     * an instance of {@link Map.Entry}. As the set is backed by this map,
+     * changes in one will be reflected in the other.
+     *
+     * @return a set of the mappings.
+     */
+    public Set<Entry<K, V>> entrySet() {
+        Set<Entry<K, V>> es = entrySet;
+        return (es != null) ? es : (entrySet = new EntrySet());
+    }
+
+    static class HashMapEntry<K, V> implements Entry<K, V> {
+        final K key;
+        V value;
+        final int hash;
+        HashMapEntry<K, V> next;
+
+        HashMapEntry(K key, V value, int hash, HashMapEntry<K, V> next) {
+            this.key = key;
+            this.value = value;
+            this.hash = hash;
+            this.next = next;
+        }
+
+        public final K getKey() {
+            return key;
+        }
+
+        public final V getValue() {
+            return value;
+        }
+
+        public final V setValue(V value) {
+            V oldValue = this.value;
+            this.value = value;
+            return oldValue;
+        }
+
+        @Override public final boolean equals(Object o) {
+            if (!(o instanceof Entry)) {
+                return false;
+            }
+            Entry<?, ?> e = (Entry<?, ?>) o;
+            return HashMap.equals(e.getKey(), key)
+                    && HashMap.equals(e.getValue(), value);
+        }
+
+        @Override public final int hashCode() {
+            return (key == null ? 0 : key.hashCode()) ^
+                    (value == null ? 0 : value.hashCode());
+        }
+
+        @Override public final String toString() {
+            return key + "=" + value;
+        }
+    }
+
+    private abstract class HashIterator {
+        int nextIndex;
+        HashMapEntry<K, V> nextEntry = entryForNullKey;
+        HashMapEntry<K, V> lastEntryReturned;
+        int expectedModCount = modCount;
+
+        HashIterator() {
+            if (nextEntry == null) {
+                HashMapEntry<K, V>[] tab = table;
+                HashMapEntry<K, V> next = null;
+                while (next == null && nextIndex < tab.length) {
+                    next = tab[nextIndex++];
+                }
+                nextEntry = next;
+            }
+        }
+
+        public boolean hasNext() {
+            return nextEntry != null;
+        }
+
+        HashMapEntry<K, V> nextEntry() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            if (nextEntry == null)
+                throw new NoSuchElementException();
+
+            HashMapEntry<K, V> entryToReturn = nextEntry;
+            HashMapEntry<K, V>[] tab = table;
+            HashMapEntry<K, V> next = entryToReturn.next;
+            while (next == null && nextIndex < tab.length) {
+                next = tab[nextIndex++];
+            }
+            nextEntry = next;
+            return lastEntryReturned = entryToReturn;
+        }
+
+        public void remove() {
+            if (lastEntryReturned == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            HashMap.this.remove(lastEntryReturned.key);
+            lastEntryReturned = null;
+            expectedModCount = modCount;
+        }
+    }
+
+    private final class KeyIterator extends HashIterator
+            implements Iterator<K> {
+        public K next() { return nextEntry().key; }
+    }
+
+    private final class ValueIterator extends HashIterator
+            implements Iterator<V> {
+        public V next() { return nextEntry().value; }
+    }
+
+    private final class EntryIterator extends HashIterator
+            implements Iterator<Entry<K, V>> {
+        public Entry<K, V> next() { return nextEntry(); }
+    }
+
+    /**
+     * Returns true if this map contains the specified mapping.
+     */
+    private boolean containsMapping(Object key, Object value) {
+        if (key == null) {
+            HashMapEntry<K, V> e = entryForNullKey;
+            return e != null && equals(value, e.value);
+        }
+
+        int hash = secondaryHash(key.hashCode());
+        HashMapEntry<K, V>[] tab = table;
+        int index = hash & (tab.length - 1);
+        for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {
+            if (e.hash == hash && key.equals(e.key)) {
+                return equals(value, e.value);
+            }
+        }
+        return false; // No entry for key
+    }
+
+    /**
+     * Removes the mapping from key to value and returns true if this mapping
+     * exists; otherwise, returns does nothing and returns false.
+     */
+    private boolean removeMapping(Object key, Object value) {
+        if (key == null) {
+            HashMapEntry<K, V> e = entryForNullKey;
+            if (e == null || !equals(value, e.value)) {
+                return false;
+            }
+            entryForNullKey = null;
+            modCount++;
+            size--;
+            postRemove(e);
+            return true;
+        }
+
+        int hash = secondaryHash(key.hashCode());
+        HashMapEntry<K, V>[] tab = table;
+        int index = hash & (tab.length - 1);
+        for (HashMapEntry<K, V> e = tab[index], prev = null;
+                e != null; prev = e, e = e.next) {
+            if (e.hash == hash && key.equals(e.key)) {
+                if (!equals(value, e.value)) {
+                    return false;  // Map has wrong value for key
+                }
+                if (prev == null) {
+                    tab[index] = e.next;
+                } else {
+                    prev.next = e.next;
+                }
+                modCount++;
+                size--;
+                postRemove(e);
+                return true;
+            }
+        }
+        return false; // No entry for key
+    }
+
+    private static boolean equals(Object o1, Object o2) {
+        return o1 == o2 || (o1 != null && o1.equals(o2));
+    }
+
+    // Subclass (LinkedHashMap) overrrides these for correct iteration order
+    Iterator<K> newKeyIterator() { return new KeyIterator();   }
+    Iterator<V> newValueIterator() { return new ValueIterator(); }
+    Iterator<Entry<K, V>> newEntryIterator() { return new EntryIterator(); }
+
+    private final class KeySet extends AbstractSet<K> {
+        public Iterator<K> iterator() {
+            return newKeyIterator();
+        }
+        public int size() {
+            return size;
+        }
+        public boolean isEmpty() {
+            return size == 0;
+        }
+        public boolean contains(Object o) {
+            return containsKey(o);
+        }
+        public boolean remove(Object o) {
+            int oldSize = size;
+            HashMap.this.remove(o);
+            return size != oldSize;
+        }
+        public void clear() {
+            HashMap.this.clear();
+        }
+    }
+
+    private final class Values extends AbstractCollection<V> {
+        public Iterator<V> iterator() {
+            return newValueIterator();
+        }
+        public int size() {
+            return size;
+        }
+        public boolean isEmpty() {
+            return size == 0;
+        }
+        public boolean contains(Object o) {
+            return containsValue(o);
+        }
+        public void clear() {
+            HashMap.this.clear();
+        }
+    }
+
+    private final class EntrySet extends AbstractSet<Entry<K, V>> {
+        public Iterator<Entry<K, V>> iterator() {
+            return newEntryIterator();
+        }
+        public boolean contains(Object o) {
+            if (!(o instanceof Entry))
+                return false;
+            Entry<?, ?> e = (Entry<?, ?>) o;
+            return containsMapping(e.getKey(), e.getValue());
+        }
+        public boolean remove(Object o) {
+            if (!(o instanceof Entry))
+                return false;
+            Entry<?, ?> e = (Entry<?, ?>)o;
+            return removeMapping(e.getKey(), e.getValue());
+        }
+        public int size() {
+            return size;
+        }
+        public boolean isEmpty() {
+            return size == 0;
+        }
+        public void clear() {
+            HashMap.this.clear();
+        }
+    }
+
+    /**
+     * Applies a supplemental hash function to a given hashCode, which defends
+     * against poor quality hash functions. This is critical because HashMap
+     * uses power-of-two length hash tables, that otherwise encounter collisions
+     * for hashCodes that do not differ in lower or upper bits.
+     */
+    private static int secondaryHash(int h) {
+        // Doug Lea's supplemental hash function
+        h ^= (h >>> 20) ^ (h >>> 12);
+        return h ^ (h >>> 7) ^ (h >>> 4);
+    }
+
+    /**
+     * Returns the smallest power of two >= its argument, with several caveats:
+     * If the argument is negative but not Integer.MIN_VALUE, the method returns
+     * zero. If the argument is > 2^30 or equal to Integer.MIN_VALUE, the method
+     * returns Integer.MIN_VALUE. If the argument is zero, the method returns
+     * zero.
+     */
+    private static int roundUpToPowerOfTwo(int i) {
+        i--; // If input is a power of two, shift its high-order bit right
+
+        // "Smear" the high-order bit all the way to the right
+        i |= i >>>  1;
+        i |= i >>>  2;
+        i |= i >>>  4;
+        i |= i >>>  8;
+        i |= i >>> 16;
+
+        return i + 1;
+    }
+
+    private static final long serialVersionUID = 362498820763181265L;
+
+    /**
+     * Serializable fields.
+     *
+     * @serialField loadFactor float
+     *              load factor for this HashMap
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("loadFactor", Float.TYPE)
+    };
+
     private void writeObject(ObjectOutputStream stream) throws IOException {
-        stream.defaultWriteObject();
-        stream.writeInt(elementData.length);
-        stream.writeInt(elementCount);
-        Iterator<?> iterator = entrySet().iterator();
-        while (iterator.hasNext()) {
-            Entry<?, ?> entry = (Entry<?, ?>) iterator.next();
-            stream.writeObject(entry.key);
-            stream.writeObject(entry.value);
-            entry = entry.next;
+        // Emulate loadFactor field for other implementations to read
+        ObjectOutputStream.PutField fields = stream.putFields();
+        fields.put("loadFactor", DEFAULT_LOAD_FACTOR);
+        stream.writeFields();
+
+        stream.writeInt(table.length); // Capacity
+        stream.writeInt(size);
+        for (Entry<K, V> e : entrySet()) {
+            stream.writeObject(e.getKey());
+            stream.writeObject(e.getValue());
         }
     }
 
-    @SuppressWarnings("unchecked")
     private void readObject(ObjectInputStream stream) throws IOException,
             ClassNotFoundException {
         stream.defaultReadObject();
-        int length = stream.readInt();
-        elementData = newElementArray(length);
-        elementCount = stream.readInt();
-        for (int i = elementCount; --i >= 0;) {
-            K key = (K) stream.readObject();
-            int index = (null == key) ? 0 : (computeHashCode(key) & (length - 1));
-            createEntry(key, index, (V) stream.readObject());
+        int capacity = stream.readInt();
+        if (capacity < 0) {
+            throw new InvalidObjectException("Capacity: " + capacity);
+        }
+        if (capacity < MINIMUM_CAPACITY) {
+            capacity = MINIMUM_CAPACITY;
+        } else if (capacity > MAXIMUM_CAPACITY) {
+            capacity = MAXIMUM_CAPACITY;
+        } else {
+            capacity = roundUpToPowerOfTwo(capacity);
+        }
+        makeTable(capacity);
+
+        int size = stream.readInt();
+        if (size < 0) {
+            throw new InvalidObjectException("Size: " + size);
+        }
+
+        init(); // Give subclass (LinkedHashMap) a chance to initialize itself
+        for (int i = 0; i < size; i++) {
+            @SuppressWarnings("unchecked") K key = (K) stream.readObject();
+            @SuppressWarnings("unchecked") V val = (V) stream.readObject();
+            constructorPut(key, val);
         }
     }
-
-    /*
-     * Contract-related functionality
-     */
-    static int computeHashCode(Object key) {
-        return key.hashCode();
-}
-
-    static boolean areEqualKeys(Object key1, Object key2) {
-        return (key1 == key2) || key1.equals(key2);
-    }
-
-    static boolean areEqualValues(Object value1, Object value2) {
-        return (value1 == value2) || value1.equals(value2);
-    }
-
-
 }
diff --git a/libcore/luni/src/main/java/java/util/HashSet.java b/libcore/luni/src/main/java/java/util/HashSet.java
index dca764f..4c97ca5 100644
--- a/libcore/luni/src/main/java/java/util/HashSet.java
+++ b/libcore/luni/src/main/java/java/util/HashSet.java
@@ -185,15 +185,11 @@
 
     private void writeObject(ObjectOutputStream stream) throws IOException {
         stream.defaultWriteObject();
-        stream.writeInt(backingMap.elementData.length);
-        stream.writeFloat(backingMap.loadFactor);
-        stream.writeInt(backingMap.elementCount);
-        for (int i = backingMap.elementData.length; --i >= 0;) {
-            HashMap.Entry<E, HashSet<E>> entry = backingMap.elementData[i];
-            while (entry != null) {
-                stream.writeObject(entry.key);
-                entry = entry.next;
-            }
+        stream.writeInt(backingMap.table.length);
+        stream.writeFloat(HashMap.DEFAULT_LOAD_FACTOR);
+        stream.writeInt(size());
+        for (E e : this) {
+            stream.writeObject(e);
         }
     }
 
diff --git a/libcore/luni/src/main/java/java/util/Hashtable.java b/libcore/luni/src/main/java/java/util/Hashtable.java
index b23364d..ead0db3 100644
--- a/libcore/luni/src/main/java/java/util/Hashtable.java
+++ b/libcore/luni/src/main/java/java/util/Hashtable.java
@@ -15,15 +15,19 @@
  *  limitations under the License.
  */
 
+// BEGIN android-note
+// Completely different implementation from harmony.  Runs much faster.
+// BEGIN android-note
+
 package java.util;
 
 import java.io.IOException;
+import java.io.InvalidObjectException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
 import java.io.Serializable;
 
-import org.apache.harmony.luni.internal.nls.Messages;
-
 /**
  * Hashtable associates keys with values. Both keys and values cannot be null.
  * The size of the Hashtable is the number of key/value pairs it contains. The
@@ -32,212 +36,86 @@
  * expanding the capacity. If the load factor of the Hashtable is exceeded, the
  * capacity is doubled.
  *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
  * @see Enumeration
  * @see java.io.Serializable
  * @see java.lang.Object#equals
  * @see java.lang.Object#hashCode
  */
 
-public class Hashtable<K, V> extends Dictionary<K, V> implements Map<K, V>,
-        Cloneable, Serializable {
+public class Hashtable<K, V> extends Dictionary<K, V>
+        implements Map<K, V>, Cloneable, Serializable {
+    /**
+     * Min capacity (other than zero) for a Hashtable. Must be a power of two
+     * greater than 1 (and less than 1 << 30).
+     */
+    private static final int MINIMUM_CAPACITY = 4;
 
-    private static final long serialVersionUID = 1421746759512286392L;
+    /**
+     * Max capacity for a Hashtable. Must be a power of two >= MINIMUM_CAPACITY.
+     */
+    private static final int MAXIMUM_CAPACITY = 1 << 30;
 
-    transient int elementCount;
+    /**
+     * An empty table shared by all zero-capacity maps (typically from default
+     * constructor). It is never written to, and replaced on first put. Its size
+     * is set to half the minimum, so that the first resize will create a
+     * minimum-sized table.
+     */
+    private static final Entry[] EMPTY_TABLE
+            = new HashtableEntry[MINIMUM_CAPACITY >>> 1];
 
-    transient Entry<K, V>[] elementData;
+    /**
+     * The default load factor. Note that this implementation ignores the
+     * load factor, but cannot do away with it entirely because it's
+     * metioned in the API.
+     *
+     * <p>Note that this constant has no impact on the behavior of the program,
+     * but it is emitted as part of the serialized form. The load factor of
+     * .75 is hardwired into the program, which uses cheap shifts in place of
+     * expensive division.
+     */
+    private static final float DEFAULT_LOAD_FACTOR = .75F;
 
-    private float loadFactor;
+    /**
+     * The hash table.
+     */
+    private transient HashtableEntry<K, V>[] table;
 
-    private int threshold;
+    /**
+     * The number of mappings in this hash map.
+     */
+    private transient int size;
 
-    transient int firstSlot;
+    /**
+     * Incremented by "structural modifications" to allow (best effort)
+     * detection of concurrent modification.
+     */
+    private transient int modCount;
 
-    transient int lastSlot = -1;
+    /**
+     * The table is rehashed when its size exceeds this threshold.
+     * The value of this field is generally .75 * capacity, except when
+     * the capacity is zero, as described in the EMPTY_TABLE declaration
+     * above.
+     */
+    private transient int threshold;
 
-    transient int modCount;
-
-    private static final Enumeration<?> EMPTY_ENUMERATION = new Enumeration<Object>() {
-        public boolean hasMoreElements() {
-            return false;
-        }
-
-        public Object nextElement() {
-            throw new NoSuchElementException();
-        }
-    };
-
-    private static final Iterator<?> EMPTY_ITERATOR = new Iterator<Object>() {
-
-        public boolean hasNext() {
-            return false;
-        }
-
-        public Object next() {
-            throw new NoSuchElementException();
-        }
-
-        public void remove() {
-            throw new IllegalStateException();
-        }
-    };
-
-    private static <K, V> Entry<K, V> newEntry(K key, V value, int hash) {
-        return new Entry<K, V>(key, value);
-    }
-
-    private static class Entry<K, V> extends MapEntry<K, V> {
-        Entry<K, V> next;
-
-        final int hashcode;
-
-        Entry(K theKey, V theValue) {
-            super(theKey, theValue);
-            hashcode = theKey.hashCode();
-        }
-
-        @Override
-        @SuppressWarnings("unchecked")
-        public Object clone() {
-            Entry<K, V> entry = (Entry<K, V>) super.clone();
-            if (next != null) {
-                entry.next = (Entry<K, V>) next.clone();
-            }
-            return entry;
-        }
-
-        @Override
-        public V setValue(V object) {
-            if (object == null) {
-                throw new NullPointerException();
-            }
-            V result = value;
-            value = object;
-            return result;
-        }
-
-        public int getKeyHash() {
-            return key.hashCode();
-        }
-
-        public boolean equalsKey(Object aKey, int hash) {
-            // BEGIN android-changed
-            // The VM can inline String.equals
-            return hashcode == aKey.hashCode()
-               && (key instanceof String
-                   ? ((String) key).equals(aKey) : key.equals(aKey));
-            // END android-changed
-        }
-
-        @Override
-        public String toString() {
-            return key + "=" + value; //$NON-NLS-1$
-        }
-    }
-
-    private class HashIterator<E> implements Iterator<E> {
-        int position, expectedModCount;
-
-        final MapEntry.Type<E, K, V> type;
-
-        Entry<K, V> lastEntry;
-
-        int lastPosition;
-
-        boolean canRemove = false;
-
-        HashIterator(MapEntry.Type<E, K, V> value) {
-            type = value;
-            position = lastSlot;
-            expectedModCount = modCount;
-        }
-
-        public boolean hasNext() {
-            if (lastEntry != null && lastEntry.next != null) {
-                return true;
-            }
-            while (position >= firstSlot) {
-                if (elementData[position] == null) {
-                    position--;
-                } else {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        public E next() {
-            if (expectedModCount == modCount) {
-                if (lastEntry != null) {
-                    lastEntry = lastEntry.next;
-                }
-                if (lastEntry == null) {
-                    while (position >= firstSlot
-                            && (lastEntry = elementData[position]) == null) {
-                        position--;
-                    }
-                    if (lastEntry != null) {
-                        lastPosition = position;
-                        // decrement the position so we don't find the same slot
-                        // next time
-                        position--;
-                    }
-                }
-                if (lastEntry != null) {
-                    canRemove = true;
-                    return type.get(lastEntry);
-                }
-                throw new NoSuchElementException();
-            }
-            throw new ConcurrentModificationException();
-        }
-
-        public void remove() {
-            if (expectedModCount == modCount) {
-                if (canRemove) {
-                    canRemove = false;
-                    synchronized (Hashtable.this) {
-                        boolean removed = false;
-                        Entry<K, V> entry = elementData[lastPosition];
-                        if (entry == lastEntry) {
-                            elementData[lastPosition] = entry.next;
-                            removed = true;
-                        } else {
-                            while (entry != null && entry.next != lastEntry) {
-                                entry = entry.next;
-                            }
-                            if (entry != null) {
-                                entry.next = lastEntry.next;
-                                removed = true;
-                            }
-                        }
-                        if (removed) {
-                            modCount++;
-                            elementCount--;
-                            expectedModCount++;
-                            return;
-                        }
-                        // the entry must have been (re)moved outside of the
-                        // iterator
-                        // but this condition wasn't caught by the modCount
-                        // check
-                        // throw ConcurrentModificationException() outside of
-                        // synchronized block
-                    }
-                } else {
-                    throw new IllegalStateException();
-                }
-            }
-            throw new ConcurrentModificationException();
-        }
-    }
+    // Views - lazily initialized
+    private transient Set<K> keySet;
+    private transient Set<Entry<K, V>> entrySet;
+    private transient Collection<V> values;
 
     /**
      * Constructs a new {@code Hashtable} using the default capacity and load
      * factor.
      */
+    @SuppressWarnings("unchecked")
     public Hashtable() {
-        this(11);
+        table = (HashtableEntry<K, V>[]) EMPTY_TABLE;
+        threshold = -1; // Forces first put invocation to replace EMPTY_TABLE
     }
 
     /**
@@ -248,15 +126,26 @@
      *            the initial capacity.
      */
     public Hashtable(int capacity) {
-        if (capacity >= 0) {
-            elementCount = 0;
-            elementData = newElementArray(capacity == 0 ? 1 : capacity);
-            firstSlot = elementData.length;
-            loadFactor = 0.75f;
-            computeMaxSize();
-        } else {
-            throw new IllegalArgumentException();
+        if (capacity < 0) {
+            throw new IllegalArgumentException("Capacity: " + capacity);
         }
+
+        if (capacity == 0) {
+            @SuppressWarnings("unchecked")
+            HashtableEntry<K, V>[] tab = (HashtableEntry<K, V>[]) EMPTY_TABLE;
+            table = tab;
+            threshold = -1; // Forces first put() to replace EMPTY_TABLE
+            return;
+        }
+
+        if (capacity < MINIMUM_CAPACITY) {
+            capacity = MINIMUM_CAPACITY;
+        } else if (capacity > MAXIMUM_CAPACITY) {
+            capacity = MAXIMUM_CAPACITY;
+        } else {
+            capacity = roundUpToPowerOfTwo(capacity);
+        }
+        makeTable(capacity);
     }
 
     /**
@@ -269,15 +158,17 @@
      *            the initial load factor.
      */
     public Hashtable(int capacity, float loadFactor) {
-        if (capacity >= 0 && loadFactor > 0) {
-            elementCount = 0;
-            firstSlot = capacity;
-            elementData = newElementArray(capacity == 0 ? 1 : capacity);
-            this.loadFactor = loadFactor;
-            computeMaxSize();
-        } else {
-            throw new IllegalArgumentException();
+        this(capacity);
+
+        if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
+            throw new IllegalArgumentException("Load factor: " + loadFactor);
         }
+
+        /*
+         * Note that this implementation ignores loadFactor; it always uses
+         * a load facator of 3/4. This simplifies the code and generally
+         * improves performance.
+         */
     }
 
     /**
@@ -288,26 +179,31 @@
      *            the mappings to add.
      */
     public Hashtable(Map<? extends K, ? extends V> map) {
-        this(map.size() < 6 ? 11 : (map.size() * 4 / 3) + 11);
-        putAll(map);
-    }
-
-    @SuppressWarnings("unchecked")
-    private Entry<K, V>[] newElementArray(int size) {
-        return new Entry[size];
+        this(capacityForInitSize(map.size()));
+        constructorPutAll(map);
     }
 
     /**
-     * Removes all key/value pairs from this {@code Hashtable}, leaving the
-     * size zero and the capacity unchanged.
-     *
-     * @see #isEmpty
-     * @see #size
+     * Inserts all of the elements of map into this Hashtable in a manner
+     * suitable for use by constructors and pseudocostructors (i.e., clone,
+     * readObject).
      */
-    public synchronized void clear() {
-        elementCount = 0;
-        Arrays.fill(elementData, null);
-        modCount++;
+    private void constructorPutAll(Map<? extends K, ? extends V> map) {
+        for (Entry<? extends K, ? extends V> e : map.entrySet()) {
+            constructorPut(e.getKey(), e.getValue());
+        }
+    }
+
+    /**
+     * Returns an appropriate capacity for the specified initial size. Does
+     * not round the result up to a power of two; the caller must do this!
+     * The returned value will be between 0 and MAXIMUM_CAPACITY (inclusive).
+     */
+    private static int capacityForInitSize(int size) {
+        int result = (size >> 1) + size; // Multiply by 3/2 to allow for growth
+
+        // boolean expr is equivalent to result >= 0 && result<MAXIMUM_CAPACITY
+        return (result & ~(MAXIMUM_CAPACITY-1))==0 ? result : MAXIMUM_CAPACITY;
     }
 
     /**
@@ -317,54 +213,77 @@
      * @return a shallow copy of this {@code Hashtable}.
      * @see java.lang.Cloneable
      */
-    @Override
     @SuppressWarnings("unchecked")
-    public synchronized Object clone() {
+    @Override public synchronized Object clone() {
+        /*
+         * This could be made more efficient. It unnecessarily hashes all of
+         * the elements in the map.
+         */
+        Hashtable<K, V> result;
         try {
-            Hashtable<K, V> hashtable = (Hashtable<K, V>) super.clone();
-            hashtable.elementData = new Entry[elementData.length];
-            Entry<K, V> entry;
-            for (int i = elementData.length; --i >= 0;) {
-                if ((entry = elementData[i]) != null) {
-                    hashtable.elementData[i] = (Entry<K, V>) entry.clone();
-                }
-            }
-            return hashtable;
+            result = (Hashtable<K, V>) super.clone();
         } catch (CloneNotSupportedException e) {
-            return null;
+            throw new AssertionError(e);
         }
-    }
 
-    private void computeMaxSize() {
-        threshold = (int) (elementData.length * loadFactor);
+        // Restore clone to empty state, retaining our capacity and threshold
+        result.makeTable(table.length);
+        result.size = 0;
+        result.keySet = null;
+        result.entrySet = null;
+        result.values = null;
+
+        result.constructorPutAll(this);
+        return result;
     }
 
     /**
-     * Returns true if this {@code Hashtable} contains the specified object as
-     * the value of at least one of the key/value pairs.
+     * Returns true if this {@code Hashtable} has no key/value pairs.
      *
-     * @param value
-     *            the object to look for as a value in this {@code Hashtable}.
-     * @return {@code true} if object is a value in this {@code Hashtable},
+     * @return {@code true} if this {@code Hashtable} has no key/value pairs,
      *         {@code false} otherwise.
-     * @see #containsKey
-     * @see java.lang.Object#equals
+     * @see #size
      */
-    public synchronized boolean contains(Object value) {
-        if (value == null) {
-            throw new NullPointerException();
-        }
+    public synchronized boolean isEmpty() {
+        return size == 0;
+    }
 
-        for (int i = elementData.length; --i >= 0;) {
-            Entry<K, V> entry = elementData[i];
-            while (entry != null) {
-                if (entry.value.equals(value)) {
-                    return true;
-                }
-                entry = entry.next;
+    /**
+     * Returns the number of key/value pairs in this {@code Hashtable}.
+     *
+     * @return the number of key/value pairs in this {@code Hashtable}.
+     * @see #elements
+     * @see #keys
+     */
+    public synchronized int size() {
+        return size;
+    }
+
+    /**
+     * Returns the value associated with the specified key in this
+     * {@code Hashtable}.
+     *
+     * @param key
+     *            the key of the value returned.
+     * @return the value associated with the specified key, or {@code null} if
+     *         the specified key does not exist.
+     * @see #put
+     */
+    public synchronized V get(Object key) {
+        // Doug Lea's supplemental secondaryHash function (inlined)
+        int hash = key.hashCode();
+        hash ^= (hash >>> 20) ^ (hash >>> 12);
+        hash ^= (hash >>> 7) ^ (hash >>> 4);
+
+        HashtableEntry<K, V>[] tab = table;
+        for (HashtableEntry<K, V> e = tab[hash & (tab.length - 1)];
+                e != null; e = e.next) {
+            K eKey = e.key;
+            if (eKey == key || (e.hash == hash && key.equals(eKey))) {
+                return e.value;
             }
         }
-        return false;
+        return null;
     }
 
     /**
@@ -379,7 +298,20 @@
      * @see java.lang.Object#equals
      */
     public synchronized boolean containsKey(Object key) {
-        return getEntry(key) != null;
+        // Doug Lea's supplemental secondaryHash function (inlined)
+        int hash = key.hashCode();
+        hash ^= (hash >>> 20) ^ (hash >>> 12);
+        hash ^= (hash >>> 7) ^ (hash >>> 4);
+
+        HashtableEntry<K, V>[] tab = table;
+        for (HashtableEntry<K, V> e = tab[hash & (tab.length - 1)];
+                e != null; e = e.next) {
+            K eKey = e.key;
+            if (eKey == key || (e.hash == hash && key.equals(eKey))) {
+                return true;
+            }
+        }
+        return false;
     }
 
     /**
@@ -390,335 +322,37 @@
      * @return {@code true} if {@code value} is a value of this
      *         {@code Hashtable}, {@code false} otherwise.
      */
-    public boolean containsValue(Object value) {
-        return contains(value);
-    }
-
-    /**
-     * Returns an enumeration on the values of this {@code Hashtable}. The
-     * results of the Enumeration may be affected if the contents of this
-     * {@code Hashtable} are modified.
-     *
-     * @return an enumeration of the values of this {@code Hashtable}.
-     * @see #keys
-     * @see #size
-     * @see Enumeration
-     */
-    @Override
-    @SuppressWarnings("unchecked")
-    public synchronized Enumeration<V> elements() {
-        if (elementCount == 0) {
-            return (Enumeration<V>) EMPTY_ENUMERATION;
+    public synchronized boolean containsValue(Object value) {
+        if (value == null) {
+            throw new NullPointerException();
         }
-        return new HashEnumIterator<V>(new MapEntry.Type<V, K, V>() {
-            public V get(MapEntry<K, V> entry) {
-                return entry.value;
-            }
-        }, true);
-    }
 
-    /**
-     * Returns a set of the mappings contained in this {@code Hashtable}. Each
-     * element in the set is a {@link Map.Entry}. The set is backed by this
-     * {@code Hashtable} so changes to one are reflected by the other. The set
-     * does not support adding.
-     *
-     * @return a set of the mappings.
-     */
-    public Set<Map.Entry<K, V>> entrySet() {
-        return new Collections.SynchronizedSet<Map.Entry<K, V>>(
-                new AbstractSet<Map.Entry<K, V>>() {
-                    @Override
-                    public int size() {
-                        return elementCount;
-                    }
+        HashtableEntry[] tab = table;
+        int len = tab.length;
 
-                    @Override
-                    public void clear() {
-                        Hashtable.this.clear();
-                    }
-
-                    @Override
-                    @SuppressWarnings("unchecked")
-                    public boolean remove(Object object) {
-                        if (contains(object)) {
-                            Hashtable.this.remove(((Map.Entry<K, V>) object)
-                                    .getKey());
-                            return true;
-                        }
-                        return false;
-                    }
-
-                    @Override
-                    @SuppressWarnings("unchecked")
-                    public boolean contains(Object object) {
-                        Entry<K, V> entry = getEntry(((Map.Entry<K, V>) object)
-                                .getKey());
-                        return object.equals(entry);
-                    }
-
-                    @Override
-                    public Iterator<Map.Entry<K, V>> iterator() {
-                        return new HashIterator<Map.Entry<K, V>>(
-                                new MapEntry.Type<Map.Entry<K, V>, K, V>() {
-                                    public Map.Entry<K, V> get(
-                                            MapEntry<K, V> entry) {
-                                        return entry;
-                                    }
-                                });
-                    }
-                }, this);
-    }
-
-    /**
-     * Compares this {@code Hashtable} with the specified object and indicates
-     * if they are equal. In order to be equal, {@code object} must be an
-     * instance of Map and contain the same key/value pairs.
-     *
-     * @param object
-     *            the object to compare with this object.
-     * @return {@code true} if the specified object is equal to this Map,
-     *         {@code false} otherwise.
-     * @see #hashCode
-     */
-    @Override
-    public synchronized boolean equals(Object object) {
-        if (this == object) {
-            return true;
-        }
-        if (object instanceof Map) {
-            Map<?, ?> map = (Map<?, ?>) object;
-            if (size() != map.size()) {
-                return false;
-            }
-
-            Set<Map.Entry<K, V>> entries = entrySet();
-            for (Map.Entry<?, ?> e : map.entrySet()) {
-                if (!entries.contains(e)) {
-                    return false;
+        for (int i = 0; i < len; i++) {
+            for (HashtableEntry e = tab[i]; e != null; e = e.next) {
+                if (value.equals(e.value)) {
+                    return true;
                 }
             }
-            return true;
         }
         return false;
     }
 
     /**
-     * Returns the value associated with the specified key in this
-     * {@code Hashtable}.
+     * Returns true if this {@code Hashtable} contains the specified object as
+     * the value of at least one of the key/value pairs.
      *
-     * @param key
-     *            the key of the value returned.
-     * @return the value associated with the specified key, or {@code null} if
-     *         the specified key does not exist.
-     * @see #put
-     */
-    @Override
-    public synchronized V get(Object key) {
-        int hash = key.hashCode();
-        int index = (hash & 0x7FFFFFFF) % elementData.length;
-        Entry<K, V> entry = elementData[index];
-        while (entry != null) {
-            if (entry.equalsKey(key, hash)) {
-                return entry.value;
-            }
-            entry = entry.next;
-        }
-        return null;
-    }
-
-    Entry<K, V> getEntry(Object key) {
-        int hash = key.hashCode();
-        int index = (hash & 0x7FFFFFFF) % elementData.length;
-        Entry<K, V> entry = elementData[index];
-        while (entry != null) {
-            if (entry.equalsKey(key, hash)) {
-                return entry;
-            }
-            entry = entry.next;
-        }
-        return null;
-    }
-
-    @Override
-    public synchronized int hashCode() {
-        int result = 0;
-        Iterator<Map.Entry<K, V>> it = entrySet().iterator();
-        while (it.hasNext()) {
-            Map.Entry<K, V> entry = it.next();
-            Object key = entry.getKey();
-            if (key == this) {
-                continue;
-            }
-            Object value = entry.getValue();
-            if (value == this) {
-                continue;
-            }
-            int hash = (key != null ? key.hashCode() : 0)
-                    ^ (value != null ? value.hashCode() : 0);
-            result += hash;
-        }
-        return result;
-    }
-
-    /**
-     * Returns true if this {@code Hashtable} has no key/value pairs.
-     *
-     * @return {@code true} if this {@code Hashtable} has no key/value pairs,
+     * @param value
+     *            the object to look for as a value in this {@code Hashtable}.
+     * @return {@code true} if object is a value in this {@code Hashtable},
      *         {@code false} otherwise.
-     * @see #size
+     * @see #containsKey
+     * @see java.lang.Object#equals
      */
-    @Override
-    public synchronized boolean isEmpty() {
-        return elementCount == 0;
-    }
-
-    /**
-     * Returns an enumeration on the keys of this {@code Hashtable} instance.
-     * The results of the enumeration may be affected if the contents of this
-     * {@code Hashtable} are modified.
-     *
-     * @return an enumeration of the keys of this {@code Hashtable}.
-     * @see #elements
-     * @see #size
-     * @see Enumeration
-     */
-    @Override
-    @SuppressWarnings("unchecked")
-    public synchronized Enumeration<K> keys() {
-        if (elementCount == 0) {
-            return (Enumeration<K>) EMPTY_ENUMERATION;
-        }
-        return new HashEnumIterator<K>(new MapEntry.Type<K, K, V>() {
-            public K get(MapEntry<K, V> entry) {
-                return entry.key;
-            }
-        }, true);
-    }
-
-    /**
-     * Returns a set of the keys contained in this {@code Hashtable}. The set
-     * is backed by this {@code Hashtable} so changes to one are reflected by
-     * the other. The set does not support adding.
-     *
-     * @return a set of the keys.
-     */
-    public Set<K> keySet() {
-        return new Collections.SynchronizedSet<K>(new AbstractSet<K>() {
-            @Override
-            public boolean contains(Object object) {
-                return containsKey(object);
-            }
-
-            @Override
-            public int size() {
-                return elementCount;
-            }
-
-            @Override
-            public void clear() {
-                Hashtable.this.clear();
-            }
-
-            @Override
-            public boolean remove(Object key) {
-                if (containsKey(key)) {
-                    Hashtable.this.remove(key);
-                    return true;
-                }
-                return false;
-            }
-
-            @Override
-            public Iterator<K> iterator() {
-                if (this.size() == 0) {
-                    return (Iterator<K>) EMPTY_ITERATOR;
-                }
-                return new HashEnumIterator<K>(new MapEntry.Type<K, K, V>() {
-                    public K get(MapEntry<K, V> entry) {
-                        return entry.key;
-                    }
-                });
-            }
-        }, this);
-    }
-
-    class HashEnumIterator<E> extends HashIterator<E> implements Enumeration<E> {
-
-        private boolean isEnumeration = false;
-
-        int start;
-
-        Entry<K, V> entry;
-
-        HashEnumIterator(MapEntry.Type<E, K, V> value) {
-            super(value);
-        }
-
-        HashEnumIterator(MapEntry.Type<E, K, V> value, boolean isEnumeration) {
-            super(value);
-            this.isEnumeration = isEnumeration;
-            start = lastSlot + 1;
-        }
-
-        public boolean hasMoreElements() {
-            if (isEnumeration) {
-                if (entry != null) {
-                    return true;
-                }
-                while (start > firstSlot) {
-                    if (elementData[--start] != null) {
-                        entry = elementData[start];
-                        return true;
-                    }
-                }
-                return false;
-            }
-            // iterator
-            return super.hasNext();
-        }
-
-        public boolean hasNext() {
-            if (isEnumeration) {
-                return hasMoreElements();
-            }
-            // iterator
-            return super.hasNext();
-        }
-
-        public E next() {
-            if (isEnumeration) {
-                if (expectedModCount == modCount) {
-                    return nextElement();
-                } else {
-                    throw new ConcurrentModificationException();
-                }
-            }
-            // iterator
-            return super.next();
-        }
-
-        @SuppressWarnings("unchecked")
-        public E nextElement() {
-            if (isEnumeration) {
-                if (hasMoreElements()) {
-                    Object result = type.get(entry);
-                    entry = entry.next;
-                    return (E) result;
-                }
-                throw new NoSuchElementException();
-            }
-            // iterator
-            return super.next();
-        }
-
-        public void remove() {
-            if (isEnumeration) {
-                throw new UnsupportedOperationException();
-            } else {
-                super.remove();
-            }
-        }
+    public boolean contains(Object value) {
+        return containsValue(value);
     }
 
     /**
@@ -737,37 +371,58 @@
      * @see #keys
      * @see java.lang.Object#equals
      */
-    @Override
     public synchronized V put(K key, V value) {
-        if (key != null && value != null) {
-            int hash = key.hashCode();
-            int index = (hash & 0x7FFFFFFF) % elementData.length;
-            Entry<K, V> entry = elementData[index];
-            while (entry != null && !entry.equalsKey(key, hash)) {
-                entry = entry.next;
-            }
-            if (entry == null) {
-                modCount++;
-                if (++elementCount > threshold) {
-                    rehash();
-                    index = (hash & 0x7FFFFFFF) % elementData.length;
-                }
-                if (index < firstSlot) {
-                    firstSlot = index;
-                }
-                if (index > lastSlot) {
-                    lastSlot = index;
-                }
-                entry = newEntry(key, value, hash);
-                entry.next = elementData[index];
-                elementData[index] = entry;
-                return null;
-            }
-            V result = entry.value;
-            entry.value = value;
-            return result;
+        if (value == null) {
+            throw new NullPointerException();
         }
-        throw new NullPointerException();
+        int hash = secondaryHash(key.hashCode());
+        HashtableEntry<K, V>[] tab = table;
+        int index = hash & (tab.length - 1);
+        HashtableEntry<K, V> first = tab[index];
+        for (HashtableEntry<K, V> e = first; e != null; e = e.next) {
+            if (e.hash == hash && key.equals(e.key)) {
+                V oldValue = e.value;
+                e.value = value;
+                return oldValue;
+            }
+        }
+
+        // No entry for key is present; create one
+        modCount++;
+        if (size++ > threshold) {
+            rehash();  // Does nothing!!
+            tab = doubleCapacity();
+            index = hash & (tab.length - 1);
+            first = tab[index];
+        }
+        tab[index] = new HashtableEntry<K, V>(key, value, hash, first);
+        return null;
+    }
+
+    /**
+     * This method is just like put, except that it doesn't do things that
+     * are inappropriate or unnecessary for constructors and pseudo-constructors
+     * (i.e., clone, readObject). In particular, this method does not check to
+     * ensure that capacity is sufficient, and does not increment modCount.
+     */
+    private void constructorPut(K key, V value) {
+        if (value == null) {
+            throw new NullPointerException();
+        }
+        int hash = secondaryHash(key.hashCode());
+        HashtableEntry<K, V>[] tab = table;
+        int index = hash & (tab.length - 1);
+        HashtableEntry<K, V> first = tab[index];
+        for (HashtableEntry<K, V> e = first; e != null; e = e.next) {
+            if (e.hash == hash && key.equals(e.key)) {
+                e.value = value;
+                return;
+            }
+        }
+
+        // No entry for key is present; create one
+        tab[index] = new HashtableEntry<K, V>(key, value, hash, first);
+        size++;
     }
 
     /**
@@ -777,8 +432,51 @@
      *            the map to copy mappings from.
      */
     public synchronized void putAll(Map<? extends K, ? extends V> map) {
-        for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
-            put(entry.getKey(), entry.getValue());
+        ensureCapacity(map.size());
+        for (Entry<? extends K, ? extends V> e : map.entrySet()) {
+            put(e.getKey(), e.getValue());
+        }
+    }
+
+    /**
+     * Ensures that the hash table has sufficient capacity to store the
+     * specified number of mappings, with room to grow. If not, it increases the
+     * capacity as appropriate. Like doubleCapacity, this method moves existing
+     * entries to new buckets as appropriate. Unlike doubleCapacity, this method
+     * can grow the table by factors of 2^n for n > 1. Hopefully, a single call
+     * to this method will be faster than multiple calls to doubleCapacity.
+     *
+     *  <p>This method is called only by putAll.
+     */
+    private void ensureCapacity(int numMappings) {
+        int newCapacity = roundUpToPowerOfTwo(capacityForInitSize(numMappings));
+        HashtableEntry<K, V>[] oldTable = table;
+        int oldCapacity = oldTable.length;
+        if (newCapacity <= oldCapacity) {
+            return;
+        }
+
+        rehash();  // Does nothing!!
+
+        if (newCapacity == oldCapacity << 1) {
+            doubleCapacity();
+            return;
+        }
+
+        // We're growing by at least 4x, rehash in the obvious way
+        HashtableEntry<K, V>[] newTable = makeTable(newCapacity);
+        if (size != 0) {
+            int newMask = newCapacity - 1;
+            for (int i = 0; i < oldCapacity; i++) {
+                for (HashtableEntry<K, V> e = oldTable[i]; e != null;) {
+                    HashtableEntry<K, V> oldNext = e.next;
+                    int newIndex = e.hash & newMask;
+                    HashtableEntry<K, V> newNext = newTable[newIndex];
+                    newTable[newIndex] = e;
+                    e.next = newNext;
+                    e = oldNext;
+                }
+            }
         }
     }
 
@@ -787,33 +485,69 @@
      * when the size of this {@code Hashtable} exceeds the load factor.
      */
     protected void rehash() {
-        int length = (elementData.length << 1) + 1;
-        if (length == 0) {
-            length = 1;
+        /*
+         * This method has no testable semantics, other than that it gets
+         * called from time to time.
+         */
+    }
+
+    /**
+     * Allocate a table of the given capacity and set the threshold accordingly.
+     * @param newCapacity must be a power of two
+     */
+    private HashtableEntry<K, V>[] makeTable(int newCapacity) {
+        @SuppressWarnings("unchecked") HashtableEntry<K, V>[] newTable
+                = (HashtableEntry<K, V>[]) new HashtableEntry[newCapacity];
+        table = newTable;
+        threshold = (newCapacity >> 1) + (newCapacity >> 2); // 3/4 capacity
+        return newTable;
+    }
+
+    /**
+     * Doubles the capacity of the hash table. Existing entries are placed in
+     * the correct bucket on the enlarged table. If the current capacity is,
+     * MAXIMUM_CAPACITY, this method is a no-op. Returns the table, which
+     * will be new unless we were already at MAXIMUM_CAPACITY.
+     */
+    private HashtableEntry<K, V>[] doubleCapacity() {
+        HashtableEntry<K, V>[] oldTable = table;
+        int oldCapacity = oldTable.length;
+        if (oldCapacity == MAXIMUM_CAPACITY) {
+            return oldTable;
         }
-        int newFirst = length;
-        int newLast = -1;
-        Entry<K, V>[] newData = newElementArray(length);
-        for (int i = lastSlot + 1; --i >= firstSlot;) {
-            Entry<K, V> entry = elementData[i];
-            while (entry != null) {
-                int index = (entry.getKeyHash() & 0x7FFFFFFF) % length;
-                if (index < newFirst) {
-                    newFirst = index;
-                }
-                if (index > newLast) {
-                    newLast = index;
-                }
-                Entry<K, V> next = entry.next;
-                entry.next = newData[index];
-                newData[index] = entry;
-                entry = next;
+        int newCapacity = oldCapacity << 1;
+        HashtableEntry<K, V>[] newTable = makeTable(newCapacity);
+        if (size == 0) {
+            return newTable;
+        }
+
+        for (int j = 0; j < oldCapacity; j++) {
+            /*
+             * Rehash the bucket using the minimum number of field writes.
+             * This is the most subtle and delicate code in the class.
+             */
+            HashtableEntry<K, V> e = oldTable[j];
+            if (e == null) {
+                continue;
             }
+            int highBit = e.hash & oldCapacity;
+            HashtableEntry<K, V> broken = null;
+            newTable[j | highBit] = e;
+            for (HashtableEntry<K,V> n = e.next; n != null; e = n, n = n.next) {
+                int nextHighBit = n.hash & oldCapacity;
+                if (nextHighBit != highBit) {
+                    if (broken == null)
+                        newTable[j | nextHighBit] = n;
+                    else
+                        broken.next = n;
+                    broken = e;
+                    highBit = nextHighBit;
+                }
+            }
+            if (broken != null)
+                broken.next = null;
         }
-        firstSlot = newFirst;
-        lastSlot = newLast;
-        elementData = newData;
-        computeMaxSize();
+        return newTable;
     }
 
     /**
@@ -827,82 +561,51 @@
      * @see #get
      * @see #put
      */
-    @Override
     public synchronized V remove(Object key) {
-        int hash = key.hashCode();
-        int index = (hash & 0x7FFFFFFF) % elementData.length;
-        Entry<K, V> last = null;
-        Entry<K, V> entry = elementData[index];
-        while (entry != null && !entry.equalsKey(key, hash)) {
-            last = entry;
-            entry = entry.next;
-        }
-        if (entry != null) {
-            modCount++;
-            if (last == null) {
-                elementData[index] = entry.next;
-            } else {
-                last.next = entry.next;
+        int hash = secondaryHash(key.hashCode());
+        HashtableEntry<K, V>[] tab = table;
+        int index = hash & (tab.length - 1);
+        for (HashtableEntry<K, V> e = tab[index], prev = null;
+                e != null; prev = e, e = e.next) {
+            if (e.hash == hash && key.equals(e.key)) {
+                if (prev == null) {
+                    tab[index] = e.next;
+                } else {
+                    prev.next = e.next;
+                }
+                modCount++;
+                size--;
+                return e.value;
             }
-            elementCount--;
-            V result = entry.value;
-            entry.value = null;
-            return result;
         }
         return null;
     }
 
     /**
-     * Returns the number of key/value pairs in this {@code Hashtable}.
+     * Removes all key/value pairs from this {@code Hashtable}, leaving the
+     * size zero and the capacity unchanged.
      *
-     * @return the number of key/value pairs in this {@code Hashtable}.
-     * @see #elements
-     * @see #keys
+     * @see #isEmpty
+     * @see #size
      */
-    @Override
-    public synchronized int size() {
-        return elementCount;
+    public synchronized void clear() {
+        if (size != 0) {
+            Arrays.fill(table, null);
+            modCount++;
+            size = 0;
+        }
     }
 
     /**
-     * Returns the string representation of this {@code Hashtable}.
+     * Returns a set of the keys contained in this {@code Hashtable}. The set
+     * is backed by this {@code Hashtable} so changes to one are reflected by
+     * the other. The set does not support adding.
      *
-     * @return the string representation of this {@code Hashtable}.
+     * @return a set of the keys.
      */
-    @Override
-    public synchronized String toString() {
-        if (isEmpty()) {
-            return "{}"; //$NON-NLS-1$
-        }
-
-        StringBuilder buffer = new StringBuilder(size() * 28);
-        buffer.append('{');
-        for (int i = lastSlot; i >= firstSlot; i--) {
-            Entry<K, V> entry = elementData[i];
-            while (entry != null) {
-                if (entry.key != this) {
-                    buffer.append(entry.key);
-                } else {
-                    // luni.04=this Map
-                    buffer.append("(" + Messages.getString("luni.04") + ")"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
-                }
-                buffer.append('=');
-                if (entry.value != this) {
-                    buffer.append(entry.value);
-                } else {
-                    // luni.04=this Map
-                    buffer.append("(" + Messages.getString("luni.04") + ")"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
-                }
-                buffer.append(", "); //$NON-NLS-1$
-                entry = entry.next;
-            }
-        }
-        // Remove the last ", "
-        if (elementCount > 0) {
-            buffer.setLength(buffer.length() - 2);
-        }
-        buffer.append('}');
-        return buffer.toString();
+    public synchronized Set<K> keySet() {
+        Set<K> ks = keySet;
+        return (ks != null) ? ks : (keySet = new KeySet());
     }
 
     /**
@@ -912,71 +615,546 @@
      *
      * @return a collection of the values.
      */
-    public Collection<V> values() {
-        return new Collections.SynchronizedCollection<V>(
-                new AbstractCollection<V>() {
-                    @Override
-                    public boolean contains(Object object) {
-                        return Hashtable.this.contains(object);
-                    }
-
-                    @Override
-                    public int size() {
-                        return elementCount;
-                    }
-
-                    @Override
-                    public void clear() {
-                        Hashtable.this.clear();
-                    }
-
-                    @Override
-                    public Iterator<V> iterator() {
-                        return new HashIterator<V>(
-                                new MapEntry.Type<V, K, V>() {
-                                    public V get(MapEntry<K, V> entry) {
-                                        return entry.value;
-                                    }
-                                });
-                    }
-                }, this);
+    public synchronized Collection<V> values() {
+        Collection<V> vs = values;
+        return (vs != null) ? vs : (values = new Values());
     }
 
-    private synchronized void writeObject(ObjectOutputStream stream)
-            throws IOException {
-        stream.defaultWriteObject();
-        stream.writeInt(elementData.length);
-        stream.writeInt(elementCount);
-        for (int i = elementData.length; --i >= 0;) {
-            Entry<K, V> entry = elementData[i];
-            while (entry != null) {
-                stream.writeObject(entry.key);
-                stream.writeObject(entry.value);
-                entry = entry.next;
+    /**
+     * Returns a set of the mappings contained in this {@code Hashtable}. Each
+     * element in the set is a {@link Map.Entry}. The set is backed by this
+     * {@code Hashtable} so changes to one are reflected by the other. The set
+     * does not support adding.
+     *
+     * @return a set of the mappings.
+     */
+    public synchronized Set<Entry<K, V>> entrySet() {
+        Set<Entry<K, V>> es = entrySet;
+        return (es != null) ? es : (entrySet = new EntrySet());
+    }
+
+
+    /**
+     * Returns an enumeration on the keys of this {@code Hashtable} instance.
+     * The results of the enumeration may be affected if the contents of this
+     * {@code Hashtable} are modified.
+     *
+     * @return an enumeration of the keys of this {@code Hashtable}.
+     * @see #elements
+     * @see #size
+     * @see Enumeration
+     */
+    public synchronized Enumeration<K> keys() {
+        return new KeyEnumeration();
+    }
+
+    /**
+     * Returns an enumeration on the values of this {@code Hashtable}. The
+     * results of the Enumeration may be affected if the contents of this
+     * {@code Hashtable} are modified.
+     *
+     * @return an enumeration of the values of this {@code Hashtable}.
+     * @see #keys
+     * @see #size
+     * @see Enumeration
+     */
+    public synchronized Enumeration<V> elements() {
+        return new ValueEnumeration();
+    }
+
+    /**
+     * Note: technically the methods of this class should synchronize the
+     * backing map.  However, this would require them to have a reference
+     * to it, which would cause consiserable bloat.  Moreover, the RI
+     * behaves the same way.
+     */
+    private static class HashtableEntry<K, V> implements Entry<K, V> {
+        final K key;
+        V value;
+        final int hash;
+        HashtableEntry<K, V> next;
+
+        HashtableEntry(K key, V value, int hash, HashtableEntry<K, V> next) {
+            this.key = key;
+            this.value = value;
+            this.hash = hash;
+            this.next = next;
+        }
+
+        public final K getKey() {
+            return key;
+        }
+
+        public final V getValue() {
+            return value;
+        }
+
+        public final V setValue(V value) {
+            if (value == null) {
+                throw new NullPointerException();
+            }
+            V oldValue = this.value;
+            this.value = value;
+            return oldValue;
+        }
+
+        @Override public final boolean equals(Object o) {
+            if (!(o instanceof Entry)) {
+                return false;
+            }
+            Entry<?, ?> e = (Entry<?, ?>) o;
+            return key.equals(e.getKey()) && value.equals(e.getValue());
+        }
+
+        @Override public final int hashCode() {
+            return key.hashCode() ^ value.hashCode();
+        }
+
+        @Override public final String toString() {
+            return key + "=" + value;
+        }
+    }
+
+    private abstract class HashIterator {
+        int nextIndex;
+        HashtableEntry<K, V> nextEntry;
+        HashtableEntry<K, V> lastEntryReturned;
+        int expectedModCount = modCount;
+
+        HashIterator() {
+            HashtableEntry<K, V>[] tab = table;
+            HashtableEntry<K, V> next = null;
+            while (next == null && nextIndex < tab.length) {
+                next = tab[nextIndex++];
+            }
+            nextEntry = next;
+        }
+
+        public boolean hasNext() {
+            return nextEntry != null;
+        }
+
+        HashtableEntry<K, V> nextEntry() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            if (nextEntry == null)
+                throw new NoSuchElementException();
+
+            HashtableEntry<K, V> entryToReturn = nextEntry;
+            HashtableEntry<K, V>[] tab = table;
+            HashtableEntry<K, V> next = entryToReturn.next;
+            while (next == null && nextIndex < tab.length) {
+                next = tab[nextIndex++];
+            }
+            nextEntry = next;
+            return lastEntryReturned = entryToReturn;
+        }
+
+        HashtableEntry<K, V> nextEntryNotFailFast() {
+            if (nextEntry == null)
+                throw new NoSuchElementException();
+
+            HashtableEntry<K, V> entryToReturn = nextEntry;
+            HashtableEntry<K, V>[] tab = table;
+            HashtableEntry<K, V> next = entryToReturn.next;
+            while (next == null && nextIndex < tab.length) {
+                next = tab[nextIndex++];
+            }
+            nextEntry = next;
+            return lastEntryReturned = entryToReturn;
+        }
+
+        public void remove() {
+            if (lastEntryReturned == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            Hashtable.this.remove(lastEntryReturned.key);
+            lastEntryReturned = null;
+            expectedModCount = modCount;
+        }
+    }
+
+    private final class KeyIterator extends HashIterator
+            implements Iterator<K> {
+        public K next() { return nextEntry().key; }
+    }
+
+    private final class ValueIterator extends HashIterator
+            implements Iterator<V> {
+        public V next() { return nextEntry().value; }
+    }
+
+    private final class EntryIterator extends HashIterator
+            implements Iterator<Entry<K, V>> {
+        public Entry<K, V> next() { return nextEntry(); }
+    }
+
+    private final class KeyEnumeration extends HashIterator
+            implements Enumeration<K> {
+        public boolean hasMoreElements() { return hasNext(); }
+        public K nextElement() { return nextEntryNotFailFast().key; }
+    }
+
+    private final class ValueEnumeration extends HashIterator
+            implements Enumeration<V> {
+        public boolean hasMoreElements() { return hasNext(); }
+        public V nextElement() { return nextEntryNotFailFast().value; }
+    }
+
+    /**
+     * Returns true if this map contains the specified mapping.
+     */
+    private synchronized boolean containsMapping(Object key, Object value) {
+        int hash = secondaryHash(key.hashCode());
+        HashtableEntry<K, V>[] tab = table;
+        int index = hash & (tab.length - 1);
+        for (HashtableEntry<K, V> e = tab[index]; e != null; e = e.next) {
+            if (e.hash == hash && e.key.equals(key)) {
+                return e.value.equals(value);
+            }
+        }
+        return false; // No entry for key
+    }
+
+    /**
+     * Removes the mapping from key to value and returns true if this mapping
+     * exists; otherwise, returns does nothing and returns false.
+     */
+    private synchronized boolean removeMapping(Object key, Object value) {
+        int hash = secondaryHash(key.hashCode());
+        HashtableEntry<K, V>[] tab = table;
+        int index = hash & (tab.length - 1);
+        for (HashtableEntry<K, V> e = tab[index], prev = null;
+                e != null; prev = e, e = e.next) {
+            if (e.hash == hash && e.key.equals(key)) {
+                if (!e.value.equals(value)) {
+                    return false;  // Map has wrong value for key
+                }
+                if (prev == null) {
+                    tab[index] = e.next;
+                } else {
+                    prev.next = e.next;
+                }
+                modCount++;
+                size--;
+                return true;
+            }
+        }
+        return false; // No entry for key
+    }
+
+    /**
+     * Compares this {@code Hashtable} with the specified object and indicates
+     * if they are equal. In order to be equal, {@code object} must be an
+     * instance of Map and contain the same key/value pairs.
+     *
+     * @param object
+     *            the object to compare with this object.
+     * @return {@code true} if the specified object is equal to this Map,
+     *         {@code false} otherwise.
+     * @see #hashCode
+     */
+    @Override public synchronized boolean equals(Object object) {
+        return (object instanceof Map) &&
+                entrySet().equals(((Map<?, ?>)object).entrySet());
+    }
+
+    @Override public synchronized int hashCode() {
+        int result = 0;
+        for (Entry<K, V> e : entrySet()) {
+            K key = e.getKey();
+            V value = e.getValue();
+            if (key == this || value == this) {
+                continue;
+            }
+            result += (key != null ? key.hashCode() : 0)
+                    ^ (value != null ? value.hashCode() : 0);
+        }
+        return result;
+    }
+
+    /**
+     * A rough estimate of the number of characters per entry, for use
+     * when creating a string buffer in the toString method.
+     */
+    private static final int CHARS_PER_ENTRY = 15;
+
+    /**
+     * Returns the string representation of this {@code Hashtable}.
+     *
+     * @return the string representation of this {@code Hashtable}.
+     */
+    @Override public synchronized String toString() {
+        StringBuilder result = new StringBuilder(CHARS_PER_ENTRY * size);
+        result.append('{');
+        Iterator<Entry<K, V>> i = entrySet().iterator();
+        boolean hasMore = i.hasNext();
+        while (hasMore) {
+            Entry<K, V> entry = i.next();
+
+            K key = entry.getKey();
+            result.append(key == this ? "(this Map)" : key.toString());
+
+            result.append('=');
+
+            V value = entry.getValue();
+            result.append(value == this ? "(this Map)" : value.toString());
+
+            if (hasMore = i.hasNext()) {
+                result.append(", ");
+            }
+        }
+
+        result.append('}');
+        return result.toString();
+    }
+
+    private final class KeySet extends AbstractSet<K> {
+        public Iterator<K> iterator() {
+            return new KeyIterator();
+        }
+        public int size() {
+            return Hashtable.this.size();
+        }
+        public boolean contains(Object o) {
+            return containsKey(o);
+        }
+        public boolean remove(Object o) {
+            synchronized (Hashtable.this) {
+                int oldSize = size;
+                Hashtable.this.remove(o);
+                return size != oldSize;
+            }
+        }
+        public void clear() {
+            Hashtable.this.clear();
+        }
+        public boolean removeAll(Collection<?> collection) {
+            synchronized (Hashtable.this) {
+                return super.removeAll(collection);
+            }
+        }
+        public boolean retainAll(Collection<?> collection) {
+            synchronized (Hashtable.this) {
+                return super.retainAll(collection);
+            }
+        }
+        public boolean containsAll(Collection<?> collection) {
+            synchronized (Hashtable.this) {
+                return super.containsAll(collection);
+            }
+        }
+        public boolean equals(Object object) {
+            synchronized (Hashtable.this) {
+                return super.equals(object);
+            }
+        }
+        public int hashCode() {
+            synchronized (Hashtable.this) {
+                return super.hashCode();
+            }
+        }
+        public String toString() {
+            synchronized (Hashtable.this) {
+                return super.toString();
+            }
+        }
+        public Object[] toArray() {
+            synchronized (Hashtable.this) {
+                return super.toArray();
+            }
+        }
+        public <T> T[] toArray(T[] a) {
+            synchronized (Hashtable.this) {
+                return super.toArray(a);
             }
         }
     }
 
-    @SuppressWarnings("unchecked")
+    private final class Values extends AbstractCollection<V> {
+        public Iterator<V> iterator() {
+            return new ValueIterator();
+        }
+        public int size() {
+            return Hashtable.this.size();
+        }
+        public boolean contains(Object o) {
+            return containsValue(o);
+        }
+        public void clear() {
+            Hashtable.this.clear();
+        }
+        public boolean containsAll(Collection<?> collection) {
+            synchronized (Hashtable.this) {
+                return super.containsAll(collection);
+            }
+        }
+        public String toString() {
+            synchronized (Hashtable.this) {
+                return super.toString();
+            }
+        }
+        public Object[] toArray() {
+            synchronized (Hashtable.this) {
+                return super.toArray();
+            }
+        }
+        public <T> T[] toArray(T[] a) {
+            synchronized (Hashtable.this) {
+                return super.toArray(a);
+            }
+        }
+    }
+
+    private final class EntrySet extends AbstractSet<Entry<K, V>> {
+        public Iterator<Entry<K, V>> iterator() {
+            return new EntryIterator();
+        }
+        public boolean contains(Object o) {
+            if (!(o instanceof Entry))
+                return false;
+            Entry<?, ?> e = (Entry<?, ?>) o;
+            return containsMapping(e.getKey(), e.getValue());
+        }
+        public boolean remove(Object o) {
+            if (!(o instanceof Entry))
+                return false;
+            Entry<?, ?> e = (Entry<?, ?>)o;
+            return removeMapping(e.getKey(), e.getValue());
+        }
+        public int size() {
+            return Hashtable.this.size();
+        }
+        public void clear() {
+            Hashtable.this.clear();
+        }
+        public boolean removeAll(Collection<?> collection) {
+            synchronized (Hashtable.this) {
+                return super.removeAll(collection);
+            }
+        }
+        public boolean retainAll(Collection<?> collection) {
+            synchronized (Hashtable.this) {
+                return super.retainAll(collection);
+            }
+        }
+        public boolean containsAll(Collection<?> collection) {
+            synchronized (Hashtable.this) {
+                return super.containsAll(collection);
+            }
+        }
+        public boolean equals(Object object) {
+            synchronized (Hashtable.this) {
+                return super.equals(object);
+            }
+        }
+        public int hashCode() {
+            return Hashtable.this.hashCode();
+        }
+        public String toString() {
+            synchronized (Hashtable.this) {
+                return super.toString();
+            }
+        }
+        public Object[] toArray() {
+            synchronized (Hashtable.this) {
+                return super.toArray();
+            }
+        }
+        public <T> T[] toArray(T[] a) {
+            synchronized (Hashtable.this) {
+                return super.toArray(a);
+            }
+        }
+    }
+
+    /**
+     * Applies a supplemental hash function to a given hashCode, which defends
+     * against poor quality hash functions. This is critical because Hashtable
+     * uses power-of-two length hash tables, that otherwise encounter collisions
+     * for hashCodes that do not differ in lower or upper bits.
+     */
+    private static int secondaryHash(int h) {
+        // Doug Lea's supplemental hash function
+        h ^= (h >>> 20) ^ (h >>> 12);
+        return h ^ (h >>> 7) ^ (h >>> 4);
+    }
+
+    /**
+     * Returns the smallest power of two >= its argument, with several caveats:
+     * If the argument is negative but not Integer.MIN_VALUE, the method returns
+     * zero. If the argument is > 2^30 or equal to Integer.MIN_VALUE, the method
+     * returns Integer.MIN_VALUE. If the argument is zero, the method returns
+     * zero.
+     */
+    private static int roundUpToPowerOfTwo(int i) {
+        i--; // If input is a power of two, shift its high-order bit right
+
+        // "Smear" the high-order bit all the way to the right
+        i |= i >>>  1;
+        i |= i >>>  2;
+        i |= i >>>  4;
+        i |= i >>>  8;
+        i |= i >>> 16;
+
+        return i + 1;
+    }
+
+    private static final long serialVersionUID = 1421746759512286392L;
+
+    /**
+     * Serializable fields.
+     *
+     * @serialField loadFactor float
+     *              load factor for this Hashtable
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("threshold", Integer.TYPE),
+        new ObjectStreamField("loadFactor", Float.TYPE)
+    };
+
+    private synchronized void writeObject(ObjectOutputStream stream)
+            throws IOException {
+        // Emulate loadFactor field for other implementations to read
+        ObjectOutputStream.PutField fields = stream.putFields();
+        fields.put("threshold",  (int) (DEFAULT_LOAD_FACTOR * table.length));
+        fields.put("loadFactor", DEFAULT_LOAD_FACTOR);
+        stream.writeFields();
+
+        stream.writeInt(table.length); // Capacity
+        stream.writeInt(size);
+        for (Entry<K, V> e : entrySet()) {
+            stream.writeObject(e.getKey());
+            stream.writeObject(e.getValue());
+        }
+    }
+
     private void readObject(ObjectInputStream stream) throws IOException,
             ClassNotFoundException {
         stream.defaultReadObject();
-        int length = stream.readInt();
-        elementData = newElementArray(length);
-        elementCount = stream.readInt();
-        for (int i = elementCount; --i >= 0;) {
-            Object key = stream.readObject();
-            int hash = key.hashCode();
-            int index = (hash & 0x7FFFFFFF) % length;
-            if (index < firstSlot) {
-                firstSlot = index;
-            }
-            if (index > lastSlot) {
-                lastSlot = index;
-            }
-            Entry<K, V> entry = newEntry((K) key, (V) stream.readObject(), hash);
-            entry.next = elementData[index];
-            elementData[index] = entry;
+        int capacity = stream.readInt();
+        if (capacity < 0) {
+            throw new InvalidObjectException("Capacity: " + capacity);
+        }
+        if (capacity < MINIMUM_CAPACITY) {
+            capacity = MINIMUM_CAPACITY;
+        } else if (capacity > MAXIMUM_CAPACITY) {
+            capacity = MAXIMUM_CAPACITY;
+        } else {
+            capacity = roundUpToPowerOfTwo(capacity);
+        }
+        makeTable(capacity);
+
+        int size = stream.readInt();
+        if (size < 0) {
+            throw new InvalidObjectException("Size: " + size);
+        }
+
+        for (int i = 0; i < size; i++) {
+            @SuppressWarnings("unchecked") K key = (K) stream.readObject();
+            @SuppressWarnings("unchecked") V val = (V) stream.readObject();
+            constructorPut(key, val);
         }
     }
 }
diff --git a/libcore/luni/src/main/java/java/util/LinkedHashMap.java b/libcore/luni/src/main/java/java/util/LinkedHashMap.java
index ed526d8..4e2fb3c 100644
--- a/libcore/luni/src/main/java/java/util/LinkedHashMap.java
+++ b/libcore/luni/src/main/java/java/util/LinkedHashMap.java
@@ -1,10 +1,10 @@
 /*
  *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
+ *  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
+ *  the License. You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
@@ -15,6 +15,10 @@
  *  limitations under the License.
  */
 
+// BEGIN android-note
+// Completely different implementation from harmony.  Runs much faster.
+// BEGIN android-note
+
 package java.util;
 
 /**
@@ -45,69 +49,68 @@
  * elements during iteration. It is not possible to guarantee that this
  * mechanism works in all cases of unsynchronized concurrent modification. It
  * should only be used for debugging purposes.
- *
- * @since 1.4
  */
 public class LinkedHashMap<K, V> extends HashMap<K, V> {
 
-    private static final long serialVersionUID = 3801124242820219131L;
+    /**
+     * A dummy entry in the circular linked list of entries in the map.
+     * The first real entry is header.nxt, and the last is header.prv.
+     * If the map is empty, header.nxt == header && header.prv == header.
+     */
+    private transient LinkedEntry<K, V> header;
 
+    /**
+     * True if access ordered, false if insertion ordered.
+     */
     private final boolean accessOrder;
 
-    transient private LinkedHashMapEntry<K, V> head, tail;
-
     /**
      * Constructs a new empty {@code LinkedHashMap} instance.
      */
     public LinkedHashMap() {
         super();
+        init();
         accessOrder = false;
-        head = null;
     }
 
     /**
      * Constructs a new {@code LinkedHashMap} instance with the specified
      * capacity.
      *
-     * @param s
+     * @param initialCapacity
      *            the initial capacity of this map.
-     * @throws IllegalArgumentException
-     *                if the capacity is less than zero.
+     * @exception IllegalArgumentException
+     *                when the capacity is less than zero.
      */
-    public LinkedHashMap(int s) {
-        super(s);
-        accessOrder = false;
-        head = null;
+    public LinkedHashMap(int initialCapacity) {
+        this(initialCapacity, DEFAULT_LOAD_FACTOR);
     }
 
     /**
      * Constructs a new {@code LinkedHashMap} instance with the specified
      * capacity and load factor.
      *
-     * @param s
+     * @param initialCapacity
      *            the initial capacity of this map.
-     * @param lf
+     * @param loadFactor
      *            the initial load factor.
      * @throws IllegalArgumentException
      *             when the capacity is less than zero or the load factor is
      *             less or equal to zero.
      */
-    public LinkedHashMap(int s, float lf) {
-        super(s, lf);
-        accessOrder = false;
-        head = null;
-        tail = null;
+    public LinkedHashMap(int initialCapacity, float loadFactor) {
+        this(initialCapacity, loadFactor, false);
     }
 
     /**
      * Constructs a new {@code LinkedHashMap} instance with the specified
      * capacity, load factor and a flag specifying the ordering behavior.
      *
-     * @param s
+     * @param initialCapacity
      *            the initial capacity of this hash map.
-     * @param lf
+     * @param loadFactor
      *            the initial load factor.
-     * @param order
+     * @param accessOrder
      *            {@code true} if the ordering should be done based on the last
      *            access (from least-recently accessed to most-recently
      *            accessed), and {@code false} if the ordering should be the
@@ -116,197 +119,75 @@
      *             when the capacity is less than zero or the load factor is
      *             less or equal to zero.
      */
-    public LinkedHashMap(int s, float lf, boolean order) {
-        super(s, lf);
-        accessOrder = order;
-        head = null;
-        tail = null;
+    public LinkedHashMap(
+            int initialCapacity, float loadFactor, boolean accessOrder) {
+        super(initialCapacity, loadFactor);
+        init();
+        this.accessOrder = accessOrder;
     }
 
     /**
      * Constructs a new {@code LinkedHashMap} instance containing the mappings
      * from the specified map. The order of the elements is preserved.
      *
-     * @param m
+     * @param map
      *            the mappings to add.
      */
-    public LinkedHashMap(Map<? extends K, ? extends V> m) {
-        accessOrder = false;
-        head = null;
-        tail = null;
-        putAll(m);
+    public LinkedHashMap(Map<? extends K, ? extends V> map) {
+        this(capacityForInitSize(map.size()));
+        constructorPutAll(map);
     }
 
-    private static class AbstractMapIterator<K, V>  {
-        int expectedModCount;
-        LinkedHashMapEntry<K, V>  futureEntry;
-        LinkedHashMapEntry<K, V>  currentEntry;
-        final LinkedHashMap<K, V> associatedMap;
-
-        AbstractMapIterator(LinkedHashMap<K, V> map) {
-            expectedModCount = map.modCount;
-            futureEntry = map.head;
-            associatedMap = map;
-        }
-
-        public boolean hasNext() {
-            return (futureEntry != null);
-        }
-
-        final void checkConcurrentMod() throws ConcurrentModificationException {
-            if (expectedModCount != associatedMap.modCount) {
-                throw new ConcurrentModificationException();
-            }
-        }
-
-        final void makeNext() {
-            checkConcurrentMod();
-            if (!hasNext()) {
-                throw new NoSuchElementException();
-            }
-            currentEntry = futureEntry;
-            futureEntry = futureEntry.chainForward;
-        }
-
-        public void remove() {
-            checkConcurrentMod();
-            if (currentEntry==null) {
-                throw new IllegalStateException();
-            }
-            associatedMap.removeEntry(currentEntry);
-            LinkedHashMapEntry<K, V> lhme =  currentEntry;
-            LinkedHashMapEntry<K, V> p = lhme.chainBackward;
-            LinkedHashMapEntry<K, V> n = lhme.chainForward;
-            LinkedHashMap<K, V> lhm = associatedMap;
-            if (p != null) {
-                p.chainForward = n;
-                if (n != null) {
-                    n.chainBackward = p;
-                } else {
-                    lhm.tail = p;
-                }
-            } else {
-                lhm.head = n;
-                if (n != null) {
-                    n.chainBackward = null;
-                } else {
-                    lhm.tail = null;
-                }
-            }
-            currentEntry = null;
-            expectedModCount++;
-        }
-    }
-
-    private static class EntryIterator <K, V> extends AbstractMapIterator<K, V> implements Iterator<Map.Entry<K, V>> {
-
-        EntryIterator (LinkedHashMap<K, V> map) {
-            super(map);
-        }
-
-        public Map.Entry<K, V> next() {
-            makeNext();
-            return currentEntry;
-        }
-    }
-
-    private static class KeyIterator <K, V> extends AbstractMapIterator<K, V> implements Iterator<K> {
-
-        KeyIterator (LinkedHashMap<K, V> map) {
-            super(map);
-        }
-
-        public K next() {
-            makeNext();
-            return currentEntry.key;
-        }
-    }
-
-    private static class ValueIterator <K, V> extends AbstractMapIterator<K, V> implements Iterator<V> {
-
-        ValueIterator (LinkedHashMap<K, V> map) {
-            super(map);
-        }
-
-        public V next() {
-            makeNext();
-            return currentEntry.value;
-        }
-    }
-
-    static final class LinkedHashMapEntrySet<KT, VT> extends
-            HashMapEntrySet<KT, VT> {
-        public LinkedHashMapEntrySet(LinkedHashMap<KT, VT> lhm) {
-            super(lhm);
-        }
-
-        @Override
-        public Iterator<Map.Entry<KT, VT>> iterator() {
-            return new EntryIterator<KT,VT>((LinkedHashMap<KT, VT>) hashMap());
-        }
-    }
-
-    static final class LinkedHashMapEntry<K, V> extends Entry<K, V> {
-        LinkedHashMapEntry<K, V> chainForward, chainBackward;
-
-        LinkedHashMapEntry(K theKey, V theValue) {
-            super(theKey, theValue);
-            chainForward = null;
-            chainBackward = null;
-        }
-
-        LinkedHashMapEntry(K theKey, int hash) {
-            super(theKey, hash);
-            chainForward = null;
-            chainBackward = null;
-        }
-
-        @Override
-        @SuppressWarnings("unchecked")
-        public Object clone() {
-            LinkedHashMapEntry<K, V> entry = (LinkedHashMapEntry<K, V>) super
-                    .clone();
-            entry.chainBackward = chainBackward;
-            entry.chainForward = chainForward;
-            LinkedHashMapEntry<K, V> lnext = (LinkedHashMapEntry<K, V>) entry.next;
-            if (lnext != null) {
-                entry.next = (LinkedHashMapEntry<K, V>) lnext.clone();
-            }
-            return entry;
-        }
-    }
-
-    @Override
-    public boolean containsValue(Object value) {
-        LinkedHashMapEntry<K, V> entry = head;
-        if (null == value) {
-            while (null != entry) {
-                if (null == entry.value) {
-                    return true;
-                }
-                entry = entry.chainForward;
-            }
-        } else {
-            while (null != entry) {
-                if (value.equals(entry.value)) {
-                    return true;
-                }
-                entry = entry.chainForward;
-            }
-        }
-        return false;
+    @Override void init(){
+        header = new LinkedEntry<K, V>(null, null, 0, null, null, null);
+        header.nxt = header.prv = header;
     }
 
     /**
-     * Create a new element array
-     *
-     * @param s
-     * @return Reference to the element array
+     * LinkedEntry adds nxt/prv double-links to plain HashMapEntry.
      */
-    @Override
-    @SuppressWarnings("unchecked")
-    Entry<K, V>[] newElementArray(int s) {
-        return new LinkedHashMapEntry[s];
+    static class LinkedEntry<K, V> extends HashMapEntry<K, V> {
+        LinkedEntry<K, V> nxt;
+        LinkedEntry<K, V> prv;
+
+        LinkedEntry(K key, V value, int hash, HashMapEntry<K, V> next,
+                    LinkedEntry<K, V> nxt, LinkedEntry<K, V> prv) {
+            super(key, value, hash, next);
+            this.nxt = nxt;
+            this.prv = prv;
+        }
+    }
+
+    /**
+     * Evicts eldest entry if instructed, creates a new entry and links it in
+     * as head of linked list. This method should call constructorNewEntry
+     * (instead of duplicating code) if the performance of your VM permits.
+     */
+    @Override LinkedEntry<K, V> newEntry(
+            K key, V value, int hash, HashMapEntry<K, V> next) {
+        // Remove eldest entry if instructed to do so.
+        LinkedEntry<K, V> eldest = header.nxt;
+        if (eldest != header && removeEldestEntry(eldest))
+            remove(eldest.key);
+
+        // Create new entry and link it on to list
+        LinkedEntry<K, V> header = this.header;
+        LinkedEntry<K, V> oldTail = header.prv;
+        LinkedEntry<K, V> newTail
+                = new LinkedEntry<K,V>(key, value, hash, next, header, oldTail);
+        return oldTail.nxt = header.prv = newTail;
+    }
+
+    /**
+     * As above, but without eviction.
+     */
+    @Override HashMapEntry<K, V> constructorNewEntry(
+            K key, V value, int hash, HashMapEntry<K, V> next) {
+        LinkedEntry<K, V> header = this.header;
+        LinkedEntry<K, V> oldTail = header.prv;
+        LinkedEntry<K, V> newTail
+                = new LinkedEntry<K,V>(key, value, hash, next, header, oldTail);
+        return oldTail.nxt = header.prv = newTail;
     }
 
     /**
@@ -317,338 +198,167 @@
      * @return the value of the mapping with the specified key, or {@code null}
      *         if no mapping for the specified key is found.
      */
-    @Override
-    public V get(Object key) {
-        LinkedHashMapEntry<K, V> m;
+    @Override public V get(Object key) {
+        /*
+         * This method is overridden to eliminate the need for a polymorphic
+         * invocation in superclass at the expense of code duplication.
+         */
         if (key == null) {
-            m = (LinkedHashMapEntry<K, V>) findNullKeyEntry();
-        } else {
-            int hash = key.hashCode();
-            int index = (hash & 0x7FFFFFFF) % elementData.length;
-            m = (LinkedHashMapEntry<K, V>) findNonNullKeyEntry(key, index, hash);
+            HashMapEntry<K, V> e = entryForNullKey;
+            if (e == null)
+                return null;
+            if (accessOrder)
+                makeTail((LinkedEntry<K, V>) e);
+            return e.value;
         }
-        if (m == null) {
-            return null;
-        }
-        if (accessOrder && tail != m) {
-            // BEGIN android-added
-            modCount++;
-            // END android-added
-            LinkedHashMapEntry<K, V> p = m.chainBackward;
-            LinkedHashMapEntry<K, V> n = m.chainForward;
-            n.chainBackward = p;
-            if (p != null) {
-                p.chainForward = n;
-            } else {
-                head = n;
+
+        // Doug Lea's supplemental secondaryHash function (inlined)
+        int hash = key.hashCode();
+        hash ^= (hash >>> 20) ^ (hash >>> 12);
+        hash ^= (hash >>> 7) ^ (hash >>> 4);
+
+        HashMapEntry<K, V>[] tab = table;
+        for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)];
+                e != null; e = e.next) {
+            K eKey = e.key;
+            if (eKey == key || (e.hash == hash && key.equals(eKey))) {
+                if (accessOrder)
+                    makeTail((LinkedEntry<K, V>) e);
+                return e.value;
             }
-            m.chainForward = null;
-            m.chainBackward = tail;
-            tail.chainForward = m;
-            tail = m;
         }
-        return m.value;
-    }
-
-    /*
-     * @param key @param index @return Entry
-     */
-    @Override
-    Entry<K, V> createEntry(K key, int index, V value) {
-        LinkedHashMapEntry<K, V> m = new LinkedHashMapEntry<K, V>(key, value);
-        m.next = elementData[index];
-        elementData[index] = m;
-        linkEntry(m);
-        return m;
-    }
-
-    Entry<K, V> createHashedEntry(K key, int index, int hash) {
-        LinkedHashMapEntry<K, V> m = new LinkedHashMapEntry<K, V>(key, hash);
-        m.next = elementData[index];
-        elementData[index] = m;
-        linkEntry(m);
-        return m;
+        return null;
     }
 
     /**
-     * Maps the specified key to the specified value.
-     *
-     * @param key
-     *            the key.
-     * @param value
-     *            the value.
-     * @return the value of any previous mapping with the specified key or
-     *         {@code null} if there was no such mapping.
+     * Relinks the given entry to the tail of the list. Under access ordering,
+     * this method is invoked whenever the value of a  pre-existing entry is
+     * read by Map.get or modified by Map.put.
      */
-    @Override
-    public V put(K key, V value) {
-        V result = putImpl(key, value);
+    private void makeTail(LinkedEntry<K, V> e) {
+        // Unlink e
+        e.prv.nxt = e.nxt;
+        e.nxt.prv = e.prv;
 
-        if (removeEldestEntry(head)) {
-            remove(head.key);
-        }
-
-        return result;
+        // Relink e as tail
+        LinkedEntry<K, V> header = this.header;
+        LinkedEntry<K, V> oldTail = header.prv;
+        e.nxt = header;
+        e.prv = oldTail;
+        oldTail.nxt = header.prv = e;
+        modCount++;
     }
 
-    V putImpl(K key, V value) {
-        LinkedHashMapEntry<K, V> m;
-        if (elementCount == 0) {
-            head = tail = null;
-        }
-        if (key == null) {
-            m = (LinkedHashMapEntry<K, V>) findNullKeyEntry();
-            if (m == null) {
-                modCount++;
-                // Check if we need to remove the oldest entry. The check
-                // includes accessOrder since an accessOrder LinkedHashMap does
-                // not record the oldest member in 'head'.
-                if (++elementCount > threshold) {
-                    rehash();
-                }
-                m = (LinkedHashMapEntry<K, V>) createHashedEntry(null, 0, 0);
-            } else {
-                linkEntry(m);
-            }
-        } else {
-            int hash = key.hashCode();
-            int index = (hash & 0x7FFFFFFF) % elementData.length;
-            m = (LinkedHashMapEntry<K, V>) findNonNullKeyEntry(key, index, hash);
-            if (m == null) {
-                modCount++;
-                if (++elementCount > threshold) {
-                    rehash();
-                    index = (hash & 0x7FFFFFFF) % elementData.length;
-                }
-                m = (LinkedHashMapEntry<K, V>) createHashedEntry(key, index,
-                        hash);
-            } else {
-                linkEntry(m);
-            }
-        }
-
-        V result = m.value;
-        m.value = value;
-        return result;
-    }
-
-    /*
-     * @param m
-     */
-    void linkEntry(LinkedHashMapEntry<K, V> m) {
-        if (tail == m) {
-            return;
-        }
-
-        if (head == null) {
-            // Check if the map is empty
-            head = tail = m;
-            return;
-        }
-
-        // we need to link the new entry into either the head or tail
-        // of the chain depending on if the LinkedHashMap is accessOrder or not
-        LinkedHashMapEntry<K, V> p = m.chainBackward;
-        LinkedHashMapEntry<K, V> n = m.chainForward;
-        if (p == null) {
-            if (n != null) {
-                // The entry must be the head but not the tail
-                if (accessOrder) {
-                    head = n;
-                    n.chainBackward = null;
-                    m.chainBackward = tail;
-                    m.chainForward = null;
-                    tail.chainForward = m;
-                    tail = m;
-                }
-            } else {
-                // This is a new entry
-                m.chainBackward = tail;
-                m.chainForward = null;
-                tail.chainForward = m;
-                tail = m;
-            }
-            return;
-        }
-
-        if (n == null) {
-            // The entry must be the tail so we can't get here
-            return;
-        }
-
-        // The entry is neither the head nor tail
+    @Override void preModify(HashMapEntry<K, V> e) {
         if (accessOrder) {
-            p.chainForward = n;
-            n.chainBackward = p;
-            m.chainForward = null;
-            m.chainBackward = tail;
-            tail.chainForward = m;
-            tail = m;
+            makeTail((LinkedEntry<K, V>) e);
         }
     }
 
-    /**
-     * Returns a set containing all of the mappings in this map. Each mapping is
-     * an instance of {@link Map.Entry}. As the set is backed by this map,
-     * changes in one will be reflected in the other.
-     *
-     * @return a set of the mappings.
-     */
-    @Override
-    public Set<Map.Entry<K, V>> entrySet() {
-        return new LinkedHashMapEntrySet<K, V>(this);
+    @Override void postRemove(HashMapEntry<K, V> e) {
+        LinkedEntry<K, V> le = (LinkedEntry<K, V>) e;
+        le.prv.nxt = le.nxt;
+        le.nxt.prv = le.prv;
+        le.nxt = le.prv = null; // Help the GC (for performance)
     }
 
     /**
-     * Returns a set of the keys contained in this map. The set is backed by
-     * this map so changes to one are reflected by the other. The set does not
-     * support adding.
-     *
-     * @return a set of the keys.
+     * This override is done for LinkedHashMap performance: iteration is cheaper
+     * via LinkedHashMap nxt links.
      */
-    @Override
-    public Set<K> keySet() {
-        if (keySet == null) {
-            keySet = new AbstractSet<K>() {
-                @Override
-                public boolean contains(Object object) {
-                    return containsKey(object);
+    @Override public boolean containsValue(Object value) {
+        if (value == null) {
+            for (LinkedEntry<K, V> header = this.header, e = header.nxt;
+                    e != header; e = e.nxt) {
+                if (e.value == null) {
+                    return true;
                 }
-
-                @Override
-                public int size() {
-                    return LinkedHashMap.this.size();
-                }
-
-                @Override
-                public void clear() {
-                    LinkedHashMap.this.clear();
-                }
-
-                @Override
-                public boolean remove(Object key) {
-                    if (containsKey(key)) {
-                        LinkedHashMap.this.remove(key);
-                        return true;
-                    }
-                    return false;
-                }
-
-                @Override
-                public Iterator<K> iterator() {
-                    return new KeyIterator<K,V>(LinkedHashMap.this);
-                }
-            };
+            }
+            return entryForNullKey != null && entryForNullKey.value == null;
         }
-        return keySet;
+
+        // value is non-null
+        for (LinkedEntry<K, V> header = this.header, e = header.nxt;
+                e != header; e = e.nxt) {
+            if (value.equals(e.value)) {
+                return true;
+            }
+        }
+        return entryForNullKey != null && value.equals(entryForNullKey.value);
+    }
+    
+    public void clear() {
+        super.clear();
+
+        // Clear all links to help GC
+        LinkedEntry<K, V> header = this.header;
+        LinkedEntry<K, V> e = header;
+        do {
+            LinkedEntry<K, V> nxt = e.nxt;
+            e.nxt = e.prv = null;
+            e = nxt;
+        } while(e != header);
+
+        header.nxt = header.prv = header;
     }
 
-    /**
-     * Returns a collection of the values contained in this map. The collection
-     * is backed by this map so changes to one are reflected by the other. The
-     * collection supports remove, removeAll, retainAll and clear operations,
-     * and it does not support add or addAll operations.
-     * <p>
-     * This method returns a collection which is the subclass of
-     * AbstractCollection. The iterator method of this subclass returns a
-     * "wrapper object" over the iterator of map's entrySet(). The size method
-     * wraps the map's size method and the contains method wraps the map's
-     * containsValue method.
-     * <p>
-     * The collection is created when this method is called for the first time
-     * and returned in response to all subsequent calls. This method may return
-     * different collections when multiple concurrent calls occur, since no
-     * synchronization is performed.
-     *
-     * @return a collection of the values contained in this map.
-     */
-    @Override
-    public Collection<V> values() {
-        if (valuesCollection == null) {
-            valuesCollection = new AbstractCollection<V>() {
-                @Override
-                public boolean contains(Object object) {
-                    return containsValue(object);
-                }
+    private abstract class LinkedHashIterator<T> implements Iterator<T> {
+        LinkedEntry<K, V> next = header.nxt;
+        LinkedEntry<K, V> lastReturned = null;
+        int expectedModCount = modCount;
 
-                @Override
-                public int size() {
-                    return LinkedHashMap.this.size();
-                }
-
-                @Override
-                public void clear() {
-                    LinkedHashMap.this.clear();
-                }
-
-                @Override
-                public Iterator<V> iterator() {
-                    return new ValueIterator<K,V>(LinkedHashMap.this);
-                }
-            };
+        public final boolean hasNext() {
+            return next != header;
         }
-        return valuesCollection;
+
+        final LinkedEntry<K, V> nextEntry() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            LinkedEntry<K, V> e = next;
+            if (e == header)
+                throw new NoSuchElementException();
+            next = e.nxt;
+            return lastReturned = e;
+        }
+
+        public final void remove() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            if (lastReturned == null)
+                throw new IllegalStateException();
+            LinkedHashMap.this.remove(lastReturned.key);
+            lastReturned = null;
+            expectedModCount = modCount;
+        }
     }
 
-    /**
-     * Removes the mapping with the specified key from this map.
-     *
-     * @param key
-     *            the key of the mapping to remove.
-     * @return the value of the removed mapping or {@code null} if no mapping
-     *         for the specified key was found.
-     */
-    @Override
-    public V remove(Object key) {
-        LinkedHashMapEntry<K, V> m = (LinkedHashMapEntry<K, V>) removeEntry(key);
-        if (m == null) {
-            return null;
-        }
-        LinkedHashMapEntry<K, V> p = m.chainBackward;
-        LinkedHashMapEntry<K, V> n = m.chainForward;
-        if (p != null) {
-            p.chainForward = n;
-        } else {
-            head = n;
-        }
-        if (n != null) {
-            n.chainBackward = p;
-        } else {
-            tail = p;
-        }
-        return m.value;
+    private final class KeyIterator extends LinkedHashIterator<K> {
+        public final K next() { return nextEntry().key; }
     }
 
-    /**
-     * This method is queried from the put and putAll methods to check if the
-     * eldest member of the map should be deleted before adding the new member.
-     * If this map was created with accessOrder = true, then the result of
-     * removeEldestEntry is assumed to be false.
-     *
-     * @param eldest
-     *            the entry to check if it should be removed.
-     * @return {@code true} if the eldest member should be removed.
-     */
+    private final class ValueIterator extends LinkedHashIterator<V> {
+        public final V next() { return nextEntry().value; }
+    }
+
+    private final class EntryIterator
+            extends LinkedHashIterator<Map.Entry<K, V>> {
+        public final Map.Entry<K, V> next() { return nextEntry(); }
+    }
+
+    // Override view iterator methods to generate correct iteration order
+    @Override Iterator<K> newKeyIterator() {
+        return new KeyIterator();
+    }
+    @Override Iterator<V> newValueIterator() {
+        return new ValueIterator();
+    }
+    @Override Iterator<Map.Entry<K, V>> newEntryIterator() {
+        return new EntryIterator();
+    }
+
     protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
         return false;
     }
 
-    // BEGIN android-changed
-    /**
-     * Removes all elements from this map, leaving it empty.
-     *
-     * @see #isEmpty()
-     * @see #size()
-     */
-    @Override
-    public void clear() {
-        internalClear();
-    }
-
-    @Override
-    void internalClear() {
-        super.internalClear();
-        head = tail = null;
-    }
-    // END android-changed
+    private static final long serialVersionUID = 3801124242820219131L;
 }
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java b/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java
index 104a981..2dea92b 100644
--- a/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java
@@ -1385,7 +1385,9 @@
             output.append("\r\n"); //$NON-NLS-1$
         }
         if (reqHeader.get("Accept") == null) { //$NON-NLS-1$
-            output.append("Accept: *; */*\r\n"); //$NON-NLS-1$
+            // BEGIN android-changed
+            output.append("Accept: *, */*\r\n"); //$NON-NLS-1$
+            // END android-changed
         }
         if (httpVersion > 0 && reqHeader.get("Connection") == null) { //$NON-NLS-1$
             output.append("Connection: Keep-Alive\r\n"); //$NON-NLS-1$
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java b/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
index 1ec6240..70432a6 100644
--- a/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
@@ -207,20 +207,33 @@
     static native void disconnectDatagramImpl(FileDescriptor aFD)
             throws SocketException;
 
-    public InetAddress getHostByAddr(byte[] addr)
+    public InetAddress getHostByAddr(byte[] ipAddress)
             throws UnknownHostException {
-        return getHostByAddrImpl(addr);
+        // BEGIN android-changed
+        // Wallpaper fix for http://b/1851257. This  is a layering violation,
+        // but at least the method has the right return type.
+        // TODO: Fix the socket code to remove this method altogether.
+        return InetAddress.getByAddress(ipAddress);
+        // END android-changed
     }
-    static native InetAddress getHostByAddrImpl(byte[] addr)
-            throws UnknownHostException;
+    // BEGIN android-removed
+    // static native InetAddress getHostByAddrImpl(byte[] addr)
+    //         throws UnknownHostException;
+    // END android-removed
 
-    public InetAddress getHostByName(String addr,
+    // BEGIN android-removed
+    public InetAddress getHostByName(String hostName,
             boolean preferIPv6Addresses) throws UnknownHostException {
-        return getHostByNameImpl(addr, preferIPv6Addresses);
+        // BEGIN android-changed
+        // Wallpaper fix for http://b/1851257.
+        return InetAddress.getByName(hostName);
+        // END android-changed
     }
 
-    static native InetAddress getHostByNameImpl(String addr,
-            boolean preferIPv6Addresses) throws UnknownHostException;
+    // BEGIN android-removed
+    // static native InetAddress getHostByNameImpl(String addr,
+    //         boolean preferIPv6Addresses) throws UnknownHostException;
+    // END android-removed
 
     public int getSocketFlags() {
         return getSocketFlagsImpl();
diff --git a/libcore/luni/src/main/native/java_net_InetAddress.cpp b/libcore/luni/src/main/native/java_net_InetAddress.cpp
index 8724817..d7b4931 100644
--- a/libcore/luni/src/main/native/java_net_InetAddress.cpp
+++ b/libcore/luni/src/main/native/java_net_InetAddress.cpp
@@ -100,7 +100,10 @@
             env->SetByteArrayRegion(byteArray, 0, 4, (jbyte*) &outaddr.s_addr);
             env->SetObjectArrayElement(addressArray, 1, byteArray);
         }
+    } else {
+        jniThrowException(env, "java/net/UnknownHostException", "adb error");
     }
+
     return addressArray;
 }
 
@@ -111,11 +114,6 @@
     jobjectArray addressArray = NULL;
 
     memset(&hints, 0, sizeof(hints));
-    /*
-     * IPv4 only for now until the socket code supports IPv6; otherwise, the
-     * resolver will create two separate requests, one for IPv4 and one,
-     * currently unnecessary, for IPv6.
-     */
     hints.ai_family = AF_UNSPEC;
     hints.ai_flags = AI_ADDRCONFIG;
     /*
@@ -194,8 +192,8 @@
             env, "java/lang/SecurityException",
             "Permission denied (maybe missing INTERNET permission)");
     } else {
-        // Do nothing. Return value will be null and the caller will throw an
-        // UnknownHostExeption.
+        jniThrowException(env, "java/net/UnknownHostException",
+                gai_strerror(result));
     }
 
     if (addressList) {
@@ -232,15 +230,19 @@
         out = getAllByNameUsingDns(env, name, preferIPv4Stack);
     }
 
-    if (!out) {
-        LOGI("Unknown host %s, throwing UnknownHostException", name);
-        jniThrowException(env, "java/net/UnknownHostException", name);
-    }
     env->ReleaseStringUTFChars(javaName, name);
     return out;
 }
 
 
+/**
+ * Looks up the name corresponding to an IP address.
+ *
+ * @param javaAddress: a byte array containing the raw IP address bytes. Must be
+ *         4 or 16 bytes long.
+ * @return the hostname.
+ * @throws UnknownHostException: the IP address has no associated hostname.
+ */
 static jstring InetAddress_gethostbyaddr(JNIEnv* env, jobject obj,
                                          jbyteArray javaAddress)
 {
@@ -257,57 +259,45 @@
     }
 
     // Convert the raw address bytes into a socket address structure.
+    int ret = 0;
     struct sockaddr_storage ss;
     struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
     struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &ss;
     size_t socklen;
+    memset(&ss, 0, sizeof(ss));
     switch (addrlen) {
         case 4:
             socklen = sizeof(struct sockaddr_in);
-            memset(sin, 0, sizeof(struct sockaddr_in));
             sin->sin_family = AF_INET;
-            memcpy(&sin->sin_addr.s_addr, rawAddress, 4);
+            memcpy(&sin->sin_addr.s_addr, rawAddress, addrlen);
             env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
             break;
         case 16:
             socklen = sizeof(struct sockaddr_in6);
-            memset(sin6, 0, sizeof(struct sockaddr_in6));
             sin6->sin6_family = AF_INET6;
-            memcpy(&sin6->sin6_addr.s6_addr, rawAddress, 16);
+            memcpy(&sin6->sin6_addr.s6_addr, rawAddress, addrlen);
             env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
             break;
         default:
+            // The caller already throws an exception in this case. Don't worry
+            // about it here.
             env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
-            jniThrowException(env, "java/net/UnknownHostException",
-                                   "Invalid address length");
             return NULL;
     }
 
-
-    // Convert the socket address structure to an IP string for logging.
-    int ret;
-    char ipstr[INET6_ADDRSTRLEN];
-    ret = getnameinfo((struct sockaddr *) &ss, socklen, ipstr, sizeof(ipstr),
-                      NULL, 0, NI_NUMERICHOST);
-    if (ret) {
-        LOGE("gethostbyaddr: getnameinfo: %s", gai_strerror(ret));
-        return NULL;
-    }
-
-    // Look up the IP address from the socket address structure.
-    jstring result = NULL;
+    // Look up the host name from the IP address.
     char name[NI_MAXHOST];
-    ret = getnameinfo((struct sockaddr *) &ss, socklen, name, sizeof(name),
-                      NULL, 0, 0);
     if (ret == 0) {
-        LOGI("gethostbyaddr: getnameinfo: %s = %s", ipstr, name);
-        result = env->NewStringUTF(name);
-    } else {
-        LOGE("gethostbyaddr: getnameinfo: unknown host %s: %s", ipstr,
-             gai_strerror(ret));
+        ret = getnameinfo((struct sockaddr *) &ss, socklen, name, sizeof(name),
+                          NULL, 0, NI_NAMEREQD);
     }
 
-    return result;
+    if (ret == 0) {
+        return env->NewStringUTF(name);
+    }
+
+    jniThrowException(env, "java/net/UnknownHostException", gai_strerror(ret));
+    return NULL;
 }
 
 /*
diff --git a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp
index 3e31743..2e814cc 100644
--- a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp
+++ b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp
@@ -172,12 +172,10 @@
 }
 
 static void
-swapShorts(jshort *shorts, int numBytes) {
+swapShorts(jshort *shorts, int count) {
     jbyte *src = (jbyte *) shorts;
     jbyte *dst = src;
-    int i;
-    
-    for (i = 0; i < numBytes; i+=2) {
+    for (int i = 0; i < count; ++i) {
         jbyte b0 = *src++;
         jbyte b1 = *src++;
         *dst++ = b1;
@@ -186,11 +184,10 @@
 }
 
 static void
-swapInts(jint *ints, int numBytes) {
+swapInts(jint *ints, int count) {
     jbyte *src = (jbyte *) ints;
     jbyte *dst = src;
-    int i;   
-    for (i = 0; i < numBytes; i+=4) {
+    for (int i = 0; i < count; ++i) {
         jbyte b0 = *src++;
         jbyte b1 = *src++;
         jbyte b2 = *src++;
@@ -204,48 +201,30 @@
 
 /*
  * Class:     org_apache_harmony_luni_platform_OSMemory
- * Method:    putShortsImpl
+ * Method:    setShortArrayImpl
  * Signature: (I[SIIZ)V
  */
-static void harmony_nio_putShortsImpl(JNIEnv *_env, jobject _this,
+static void harmony_nio_setShortArrayImpl(JNIEnv *_env, jobject _this,
        jint pointer, jshortArray src, jint offset, jint length, jboolean swap) {
-       
-    offset = offset << 1;
-    length = length << 1;
-       
-    jshort *src_ =
-        (jshort *)_env->GetPrimitiveArrayCritical(src, (jboolean *)0);
+    jshort* dst = reinterpret_cast<jshort*>(static_cast<uintptr_t>(pointer));
+    _env->GetShortArrayRegion(src, offset, length, dst);
     if (swap) {
-        swapShorts(src_ + offset, length);
+        swapShorts(dst, length);
     }
-    memcpy((jbyte *)pointer, (jbyte *)src_ + offset, length);
-    if (swap) {
-        swapShorts(src_ + offset, length);
-    }
-    _env->ReleasePrimitiveArrayCritical(src, src_, JNI_ABORT);
 }
 
 /*
  * Class:     org_apache_harmony_luni_platform_OSMemory
- * Method:    putIntsImpl
+ * Method:    setIntArrayImpl
  * Signature: (I[IIIZ)V
  */
-static void harmony_nio_putIntsImpl(JNIEnv *_env, jobject _this,
+static void harmony_nio_setIntArrayImpl(JNIEnv *_env, jobject _this,
        jint pointer, jintArray src, jint offset, jint length, jboolean swap) {
-
-    offset = offset << 2;
-    length = length << 2;
-       
-    jint *src_ =
-        (jint *)_env->GetPrimitiveArrayCritical(src, (jboolean *)0);
+    jint* dst = reinterpret_cast<jint*>(static_cast<uintptr_t>(pointer));
+    _env->GetIntArrayRegion(src, offset, length, dst);
     if (swap) {
-        swapInts(src_ + offset, length);
+        swapInts(dst, length);
     }
-    memcpy((jbyte *)pointer, (jbyte *)src_ + offset, length);
-    if (swap) {
-        swapInts(src_ + offset, length);
-    }
-    _env->ReleasePrimitiveArrayCritical(src, src_, JNI_ABORT);
 }
 
 /*
@@ -588,8 +567,8 @@
     { "memmove",            "(IIJ)V",  (void*) harmony_nio_memmove },
     { "getByteArray",       "(I[BII)V",(void*) harmony_nio_getBytesImpl },
     { "setByteArray",       "(I[BII)V",(void*) harmony_nio_putBytesImpl },
-    { "setShortArray",     "(I[SIIZ)V",(void*) harmony_nio_putShortsImpl },
-    { "setIntArray",       "(I[IIIZ)V",(void*) harmony_nio_putIntsImpl },
+    { "setShortArray",     "(I[SIIZ)V",(void*) harmony_nio_setShortArrayImpl },
+    { "setIntArray",       "(I[IIIZ)V",(void*) harmony_nio_setIntArrayImpl },
     { "getByte",            "(I)B",    (void*) harmony_nio_getByteImpl },
     { "setByte",            "(IB)V",   (void*) harmony_nio_putByteImpl },
     { "getShort",           "(I)S",    (void*) harmony_nio_getShortImpl },
@@ -653,4 +632,3 @@
                 "org/apache/harmony/luni/platform/OSMemory",
                 gMethods, NELEM(gMethods));
 }
-
diff --git a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
index cce822a..d689fc7 100644
--- a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
+++ b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
@@ -156,8 +156,9 @@
 struct CachedFields {
     jfieldID fd_descriptor;
     jclass iaddr_class;
-    jmethodID iaddr_class_init;
     jmethodID iaddr_getbyaddress;
+    jclass i4addr_class;
+    jmethodID i4addr_class_init;
     jfieldID iaddr_ipaddress;
     jclass genericipmreq_class;
     jclass integer_class;
@@ -171,6 +172,7 @@
     jfieldID byte_class_value;
     jclass string_class;
     jmethodID string_class_init;
+    jclass socketimpl_class;
     jfieldID socketimpl_address;
     jfieldID socketimpl_port;
     jclass dpack_class;
@@ -1397,229 +1399,77 @@
     }
 
     memset(&gCachedFields, 0, sizeof(gCachedFields));
+    struct CachedFields *c = &gCachedFields;
 
-    // initializing InetAddress
-
-    jclass iaddrclass = env->FindClass("java/net/InetAddress");
-
-    if (iaddrclass == NULL) {
-        jniThrowException(env, "java/lang/ClassNotFoundException",
-                "java.net.InetAddress");
-        return;
+    struct classInfo {
+        jclass *clazz;
+        const char *name;
+    } classes[] = {
+        {&c->iaddr_class, "java/net/InetAddress"},
+        {&c->i4addr_class, "java/net/Inet4Address"},
+        {&c->genericipmreq_class, "org/apache/harmony/luni/net/GenericIPMreq"},
+        {&c->integer_class, "java/lang/Integer"},
+        {&c->boolean_class, "java/lang/Boolean"},
+        {&c->byte_class, "java/lang/Byte"},
+        {&c->string_class, "java/lang/String"},
+        {&c->socketimpl_class, "java/net/SocketImpl"},
+        {&c->dpack_class, "java/net/DatagramPacket"}
+    };
+    for (unsigned i = 0; i < sizeof(classes) / sizeof(classes[0]); i++) {
+        classInfo c = classes[i];
+        jclass tempClass = env->FindClass(c.name);
+        if (tempClass == NULL) return;
+        *c.clazz = (jclass) env->NewGlobalRef(tempClass);
     }
 
-    gCachedFields.iaddr_class = (jclass) env->NewGlobalRef(iaddrclass);
-
-    jmethodID iaddrclassinit = env->GetMethodID(iaddrclass, "<init>", "()V");
-
-    if (iaddrclassinit == NULL) {
-        jniThrowException(env, "java/lang/NoSuchMethodError", "InetAddress.<init>()");
-        return;
+    struct methodInfo {
+        jmethodID *method;
+        jclass clazz;
+        const char *name;
+        const char *signature;
+        bool isStatic;
+    } methods[] = {
+        {&c->i4addr_class_init, c->i4addr_class, "<init>", "([B)V", false},
+        {&c->integer_class_init, c->integer_class, "<init>", "(I)V", false},
+        {&c->boolean_class_init, c->boolean_class, "<init>", "(Z)V", false},
+        {&c->byte_class_init, c->byte_class, "<init>", "(B)V", false},
+        {&c->string_class_init, c->string_class, "<init>", "([B)V", false},
+        {&c->iaddr_getbyaddress, c->iaddr_class, "getByAddress",
+                    "([B)Ljava/net/InetAddress;", true}
+    };
+    for (unsigned i = 0; i < sizeof(methods) / sizeof(methods[0]); i++) {
+        methodInfo m = methods[i];
+        if (m.isStatic) {
+            *m.method = env->GetStaticMethodID(m.clazz, m.name, m.signature);
+        } else {
+            *m.method = env->GetMethodID(m.clazz, m.name, m.signature);
+        }
+        if (*m.method == NULL) return;
     }
 
-    gCachedFields.iaddr_class_init = iaddrclassinit;
-
-    jmethodID iaddrgetbyaddress = env->GetStaticMethodID(iaddrclass,
-            "getByAddress", "([B)Ljava/net/InetAddress;");
-
-    if (iaddrgetbyaddress == NULL) {
-        jniThrowException(env, "java/lang/NoSuchMethodError",
-                "InetAddress.getByAddress(byte[] val)");
-        return;
+    struct fieldInfo {
+        jfieldID *field;
+        jclass clazz;
+        const char *name;
+        const char *type;
+    } fields[] = {
+        {&c->iaddr_ipaddress, c->iaddr_class, "ipaddress", "[B"},
+        {&c->integer_class_value, c->integer_class, "value", "I"},
+        {&c->boolean_class_value, c->boolean_class, "value", "Z"},
+        {&c->byte_class_value, c->byte_class, "value", "B"},
+        {&c->socketimpl_port, c->socketimpl_class, "port", "I"},
+        {&c->socketimpl_address, c->socketimpl_class, "address",
+                "Ljava/net/InetAddress;"},
+        {&c->dpack_address, c->dpack_class, "address",
+                "Ljava/net/InetAddress;"},
+        {&c->dpack_port, c->dpack_class, "port", "I"},
+        {&c->dpack_length, c->dpack_class, "length", "I"}
+    };
+    for (unsigned i = 0; i < sizeof(fields) / sizeof(fields[0]); i++) {
+        fieldInfo f = fields[i];
+        *f.field = env->GetFieldID(f.clazz, f.name, f.type);
+        if (*f.field == NULL) return;
     }
-
-    gCachedFields.iaddr_getbyaddress = iaddrgetbyaddress;
-
-    jfieldID iaddripaddress = env->GetFieldID(iaddrclass, "ipaddress", "[B");
-
-    if (iaddripaddress == NULL) {
-        jniThrowException(env, "java/lang/NoSuchFieldError",
-                "Can't find field InetAddress.ipaddress");
-        return;
-    }
-
-    gCachedFields.iaddr_ipaddress = iaddripaddress;
-
-    // get the GenericIPMreq class
-
-    jclass genericipmreqclass = env->FindClass("org/apache/harmony/luni/net/GenericIPMreq");
-
-    if (genericipmreqclass == NULL) {
-        jniThrowException(env, "java/lang/ClassNotFoundException",
-                "org.apache.harmony.luni.net.GenericIPMreq");
-        return;
-    }
-
-    gCachedFields.genericipmreq_class = (jclass) env->NewGlobalRef(genericipmreqclass);
-
-    // initializing Integer
-
-    jclass integerclass = env->FindClass("java/lang/Integer");
-
-    if (integerclass == NULL) {
-        jniThrowException(env, "java/lang/ClassNotFoundException",
-                "java.lang.Integer");
-        return;
-    }
-
-    jmethodID integerclassinit = env->GetMethodID(integerclass, "<init>", "(I)V");
-
-    if (integerclassinit == NULL) {
-        jniThrowException(env, "java/lang/NoSuchMethodError",
-                "Integer.<init>(int val)");
-        return;
-    }
-
-    jfieldID integerclassvalue = env->GetFieldID(integerclass, "value", "I");
-
-    if (integerclassvalue == NULL) {
-        jniThrowException(env, "java/lang/NoSuchMethodError", "Integer.value");
-        return;
-    }
-
-    gCachedFields.integer_class = (jclass) env->NewGlobalRef(integerclass);
-    gCachedFields.integer_class_init = integerclassinit;
-    gCachedFields.integer_class_value = integerclassvalue;
-
-    // initializing Boolean
-
-    jclass booleanclass = env->FindClass("java/lang/Boolean");
-
-    if (booleanclass == NULL) {
-        jniThrowException(env, "java/lang/ClassNotFoundException",
-                "java.lang.Boolean");
-        return;
-    }
-
-    jmethodID booleanclassinit = env->GetMethodID(booleanclass, "<init>", "(Z)V");
-
-    if (booleanclassinit == NULL) {
-        jniThrowException(env, "java/lang/NoSuchMethodError",
-                "Boolean.<init>(boolean val)");
-        return;
-    }
-
-    jfieldID booleanclassvalue = env->GetFieldID(booleanclass, "value", "Z");
-
-    if (booleanclassvalue == NULL) {
-        jniThrowException(env, "java/lang/NoSuchMethodError", "Boolean.value");
-        return;
-    }
-
-    gCachedFields.boolean_class = (jclass) env->NewGlobalRef(booleanclass);
-    gCachedFields.boolean_class_init = booleanclassinit;
-    gCachedFields.boolean_class_value = booleanclassvalue;
-
-    // initializing Byte
-
-    jclass byteclass = env->FindClass("java/lang/Byte");
-
-    if (byteclass == NULL) {
-        jniThrowException(env, "java/lang/ClassNotFoundException",
-                "java.lang.Byte");
-        return;
-    }
-
-    jmethodID byteclassinit = env->GetMethodID(byteclass, "<init>", "(B)V");
-
-    if (byteclassinit == NULL) {
-        jniThrowException(env, "java/lang/NoSuchMethodError",
-                "Byte.<init>(byte val)");
-        return;
-    }
-
-    jfieldID byteclassvalue = env->GetFieldID(byteclass, "value", "B");
-
-    if (byteclassvalue == NULL) {
-        jniThrowException(env, "java/lang/NoSuchMethodError", "Byte.value");
-        return;
-    }
-
-    gCachedFields.byte_class = (jclass) env->NewGlobalRef(byteclass);
-    gCachedFields.byte_class_init = byteclassinit;
-    gCachedFields.byte_class_value = byteclassvalue;
-
-    // initializing String
-
-    jclass stringclass = env->FindClass("java/lang/String");
-
-    if (stringclass == NULL) {
-        jniThrowException(env, "java/lang/ClassNotFoundException",
-                "java.lang.String");
-        return;
-    }
-
-    jmethodID stringclassinit = env->GetMethodID(stringclass, "<init>", "([B)V");
-
-    if (stringclassinit == NULL) {
-        jniThrowException(env, "java/lang/NoSuchMethodError",
-                "String.<init>(byte[] val)");
-        return;
-    }
-
-    gCachedFields.string_class = (jclass) env->NewGlobalRef(stringclass);
-    gCachedFields.string_class_init = stringclassinit;
-
-    // initializing ScoketImpl
-
-    jclass socketimplclass = env->FindClass("java/net/SocketImpl");
-
-    if (socketimplclass == NULL) {
-        jniThrowException(env, "java/lang/ClassNotFoundException",
-                "java.net.SocketImpl");
-        return;
-    }
-
-    jfieldID socketimplport = env->GetFieldID(socketimplclass, "port", "I");
-
-    if (socketimplport == NULL) {
-        jniThrowException(env, "java/lang/NoSuchFieldError", "SocketImpl.port");
-        return;
-    }
-
-    jfieldID socketimpladdress = env->GetFieldID(socketimplclass, "address",
-            "Ljava/net/InetAddress;");
-
-    if (socketimpladdress == NULL) {
-        jniThrowException(env, "java/lang/NoSuchFieldError",
-                "SocketImpl.address");
-        return;
-    }
-
-    gCachedFields.socketimpl_address = socketimpladdress;
-    gCachedFields.socketimpl_port = socketimplport;
-
-    gCachedFields.dpack_class = env->FindClass("java/net/DatagramPacket");
-    if (gCachedFields.dpack_class == NULL) {
-        jniThrowException(env, "java/lang/ClassNotFoundException",
-                "java.net.DatagramPacket");
-        return;
-    }
-
-    gCachedFields.dpack_address = env->GetFieldID(gCachedFields.dpack_class,
-            "address", "Ljava/net/InetAddress;");
-    if (gCachedFields.dpack_address == NULL) {
-        jniThrowException(env, "java/lang/NoSuchFieldError",
-                "DatagramPacket.address");
-        return;
-    }
-
-    gCachedFields.dpack_port = env->GetFieldID(gCachedFields.dpack_class,
-            "port", "I");
-    if (gCachedFields.dpack_port == NULL) {
-        jniThrowException(env, "java/lang/NoSuchFieldError",
-                "DatagramPacket.port");
-        return;
-    }
-
-    gCachedFields.dpack_length = env->GetFieldID(gCachedFields.dpack_class,
-            "length", "I");
-    if (gCachedFields.dpack_length == NULL) {
-        jniThrowException(env, "java/lang/NoSuchFieldError",
-                "DatagramPacket.length");
-        return;
-    }
-
 }
 
 /**
@@ -1628,8 +1478,10 @@
  *
  * @param fileDescriptor the file descriptor to bind the socket to
  * @param type the socket type to create, e.g., SOCK_STREAM
+ * @throws SocketException an error occurred when creating the socket
  *
- * @return the socket file descriptor, or -1 on failure
+ * @return the socket file descriptor. On failure, an exception is thrown and
+ *         a negative value is returned.
  *
  */
 static int createSocketFileDescriptor(JNIEnv* env, jobject fileDescriptor,
@@ -1648,6 +1500,7 @@
     if (sock < 0) {
         int err = convertError(errno);
         throwSocketException(env, err);
+        return sock;
     }
     jniSetFileDescriptorOfFD(env, fileDescriptor, sock);
     return sock;
@@ -3440,88 +3293,6 @@
     close(handle);
 }
 
-static jobject osNetworkSystem_getHostByAddrImpl(JNIEnv* env, jclass clazz,
-        jbyteArray addrStr) {
-    // LOGD("ENTER getHostByAddrImpl");
-
-    if (addrStr == NULL) {
-        throwNullPointerException(env);
-        return JNI_FALSE;
-    }
-
-    jstring address = (jstring)newJavaLangString(env, addrStr);
-    jstring result;
-    const char* addr = env->GetStringUTFChars(address, NULL);
-
-    struct hostent* ent = gethostbyaddr(addr, strlen(addr), AF_INET);
-
-    if (ent != NULL  && ent->h_name != NULL) {
-        result = env->NewStringUTF(ent->h_name);
-    } else {
-        result = NULL;
-    }
-
-    env->ReleaseStringUTFChars(address, addr);
-
-    return result;
-}
-
-static jobject osNetworkSystem_getHostByNameImpl(JNIEnv* env, jclass clazz,
-        jstring nameStr, jboolean preferIPv6Addresses) {
-    // LOGD("ENTER getHostByNameImpl");
-
-    if (nameStr == NULL) {
-        throwNullPointerException(env);
-        return NULL;
-    }
-
-    const char* name = env->GetStringUTFChars(nameStr, NULL);
-
-    if (useAdbNetworking) {
-
-        union {
-            struct in_addr a;
-            jbyte j[4];
-        } outaddr;
-
-        // LOGD("ADB networking: +gethostbyname '%s'", name);
-        int err;
-        err = adb_networking_gethostbyname(name, &(outaddr.a));
-
-        env->ReleaseStringUTFChars(nameStr, name);
-#if 0
-        LOGD("ADB networking: -gethostbyname err %d addr 0x%08x %u.%u.%u.%u",
-                err, (unsigned int)outaddr.a.s_addr,
-                outaddr.j[0],outaddr.j[1],
-                outaddr.j[2],outaddr.j[3]);
-#endif
-
-        if (err < 0) {
-            return NULL;
-        } else {
-            jbyteArray addr = env->NewByteArray(4);
-            env->SetByteArrayRegion(addr, 0, 4, outaddr.j);
-            return addr;
-        }
-    } else {
-
-        // normal case...no adb networking
-        struct hostent* ent = gethostbyname(name);
-
-        env->ReleaseStringUTFChars(nameStr, name);
-
-        if (ent != NULL  && ent->h_length > 0) {
-            jbyteArray addr = env->NewByteArray(4);
-            jbyte v[4];
-            memcpy(v, ent->h_addr, 4);
-            env->SetByteArrayRegion(addr, 0, 4, v);
-            return addr;
-        } else {
-            return NULL;
-        }
-    }
-}
-
 static void osNetworkSystem_setInetAddressImpl(JNIEnv* env, jobject obj,
         jobject sender, jbyteArray address) {
     // LOGD("ENTER setInetAddressImpl");
@@ -3621,8 +3392,10 @@
                     ntohs(local_addr.sin_port));
 
             // new and set remote addr
-            addr_object = env->NewObject(gCachedFields.iaddr_class,
-                    gCachedFields.iaddr_class_init);
+            addr_array = env->NewByteArray((jsize)4);
+            env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
+            addr_object = env->NewObject(gCachedFields.i4addr_class,
+                    gCachedFields.i4addr_class_init, addr_array);
             if (NULL == addr_object) {
                 goto clean;
             }
@@ -3634,13 +3407,6 @@
             if (NULL == socketaddr_object) {
                 goto clean;
             }
-            addr_field = env->GetFieldID(socketaddr_class, "addr",
-                    "Ljava/net/InetAddress;");
-            env->SetObjectField(socketaddr_object, addr_field, addr_object);
-            addr_array = env->NewByteArray((jsize)4);
-            env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
-            env->SetObjectField(addr_object, gCachedFields.iaddr_ipaddress,
-                     addr_array);
 
             // localAddr
             socketaddr_class = env->FindClass("java/net/InetSocketAddress");
@@ -3650,9 +3416,11 @@
                      socketaddr_field);
 
             localAddr_field = env->GetFieldID(channel_class, "localAddress",
-                     "Ljava/net/InetAddress;");
-            localAddr_object = env->NewObject(gCachedFields.iaddr_class,
-                     gCachedFields.iaddr_class_init);
+                     "Ljava/net/Inet4Address;");
+            addr_array = env->NewByteArray((jsize)4);
+            env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, localAddr);
+            localAddr_object = env->NewObject(gCachedFields.i4addr_class,
+                     gCachedFields.i4addr_class_init, addr_array);
             jfieldID socketaddr_field = env->GetFieldID(channel_class,
                      "connectAddress", "Ljava/net/InetSocketAddress;");
             jobject socketaddr_object = env->GetObjectField(channel_object,
@@ -3662,10 +3430,6 @@
             if (NULL == localAddr_object) {
                 goto clean;
             }
-            addr_array = env->NewByteArray((jsize)4);
-            env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, localAddr);
-            env->SetObjectField(localAddr_object, gCachedFields.iaddr_ipaddress,
-                    addr_array);
 
 
             // set port
@@ -3718,10 +3482,13 @@
                  goto clean;
             }
 
+            addr_array = env->NewByteArray((jsize)4);
             localAddr_field = env->GetFieldID(channel_class, "localAddress",
                     "Ljava/net/InetAddress;");
-            localAddr_object = env->NewObject(gCachedFields.iaddr_class,
-                    gCachedFields.iaddr_class_init);
+            memset(address, 0, 4);
+            env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
+            localAddr_object = env->NewObject(gCachedFields.i4addr_class,
+                    gCachedFields.i4addr_class_init, addr_array);
             if (NULL == localAddr_object) {
                  goto clean;
             }
@@ -3768,8 +3535,10 @@
         env->SetIntField(channel_object, port_field, ntohs(local_addr.sin_port));
 
         // new and set remote addr
+        addr_array = env->NewByteArray((jsize)4);
+        env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
         addr_object = env->NewObject(gCachedFields.iaddr_class,
-                gCachedFields.iaddr_class_init);
+                gCachedFields.i4addr_class_init, addr_array);
         if (NULL == addr_object) {
             goto clean;
         }
@@ -3780,12 +3549,6 @@
         if (NULL == socketaddr_object) {
             goto clean;
         }
-        addr_field = env->GetFieldID(socketaddr_class, "addr",
-                "Ljava/net/InetAddress;");
-        env->SetObjectField(socketaddr_object, addr_field, addr_object);
-        addr_array = env->NewByteArray((jsize)4);
-        env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
-        env->SetObjectField(addr_object, gCachedFields.iaddr_ipaddress, addr_array);
 
         // set bound
         if (0 != local_addr.sin_port) {
@@ -3845,8 +3608,6 @@
     { "setSocketOptionImpl",               "(Ljava/io/FileDescriptor;ILjava/lang/Object;)V",                           (void*) osNetworkSystem_setSocketOptionImpl                },
     { "getSocketFlagsImpl",                "()I",                                                                      (void*) osNetworkSystem_getSocketFlagsImpl                 },
     { "socketCloseImpl",                   "(Ljava/io/FileDescriptor;)V",                                              (void*) osNetworkSystem_socketCloseImpl                    },
-    { "getHostByAddrImpl",                 "([B)Ljava/net/InetAddress;",                                               (void*) osNetworkSystem_getHostByAddrImpl                  },
-    { "getHostByNameImpl",                 "(Ljava/lang/String;Z)Ljava/net/InetAddress;",                              (void*) osNetworkSystem_getHostByNameImpl                  },
     { "setInetAddressImpl",                "(Ljava/net/InetAddress;[B)V",                                              (void*) osNetworkSystem_setInetAddressImpl                 },
     { "inheritedChannelImpl",              "()Ljava/nio/channels/Channel;",                                            (void*) osNetworkSystem_inheritedChannelImpl               },
 };
diff --git a/libcore/luni/src/test/java/org/apache/harmony/luni/platform/AllTests.java b/libcore/luni/src/test/java/org/apache/harmony/luni/platform/AllTests.java
new file mode 100644
index 0000000..be28d41
--- /dev/null
+++ b/libcore/luni/src/test/java/org/apache/harmony/luni/platform/AllTests.java
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+package org.apache.harmony.luni.platform;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+
+public class AllTests {
+    public static void run() {
+        TestRunner.main(new String[] { AllTests.class.getName() });
+    }
+    
+    public static final Test suite() {
+        TestSuite suite = tests.TestSuiteFactory.createTestSuite("Tests for org.apache.harmony.luni.platform");
+        
+        suite.addTestSuite(OSMemoryTest.class);
+        
+        return suite;
+    }
+}
diff --git a/libcore/luni/src/test/java/org/apache/harmony/luni/platform/OSMemoryTest.java b/libcore/luni/src/test/java/org/apache/harmony/luni/platform/OSMemoryTest.java
new file mode 100644
index 0000000..a546289
--- /dev/null
+++ b/libcore/luni/src/test/java/org/apache/harmony/luni/platform/OSMemoryTest.java
@@ -0,0 +1,164 @@
+/* 
+ * 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.
+ */
+
+package org.apache.harmony.luni.platform;
+
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.AndroidOnly;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests org.apache.harmony.luni.platform.OSMemory (via IMemorySystem).
+ */
+@TestTargetClass(org.apache.harmony.luni.platform.OSMemory.class)
+public class OSMemoryTest extends TestCase {
+    @TestTargetNew(
+        level = TestLevel.PARTIAL_COMPLETE,
+        notes = "",
+        method = "memset",
+        args = {}
+    )
+    public void testMemset() {
+        IMemorySystem memory = Platform.getMemorySystem();
+        
+        int byteCount = 32;
+        int ptr = memory.malloc(byteCount);
+        try {
+            // Ensure our newly-allocated block isn't zeroed.
+            memory.setByte(ptr, (byte) 1);
+            assertEquals((byte) 1, memory.getByte(ptr));
+            // Check that we can clear memory.
+            memory.memset(ptr, (byte) 0, byteCount);
+            assertBytesEqual((byte) 0, ptr, byteCount);
+            // Check that we can set an arbitrary value.
+            memory.memset(ptr, (byte) 1, byteCount);
+            assertBytesEqual((byte) 1, ptr, byteCount);
+        } finally {
+            memory.free(ptr);
+        }
+    }
+    
+    void assertBytesEqual(byte value, int ptr, int byteCount) {
+        IMemorySystem memory = Platform.getMemorySystem();
+        for (int i = 0; i < byteCount; ++i) {
+            assertEquals(value, memory.getByte(ptr + i));
+        }
+    }
+    
+    @TestTargetNew(
+        level = TestLevel.PARTIAL_COMPLETE,
+        notes = "",
+        method = "setIntArray",
+        args = {}
+    )
+    public void testSetIntArray() {
+        IMemorySystem memory = Platform.getMemorySystem();
+        
+        int[] values = { 3, 7, 31, 127, 8191, 131071, 524287, 2147483647 };
+        int[] swappedValues = new int[values.length];
+        for (int i = 0; i < values.length; ++i) {
+            swappedValues[i] = swapInt(values[i]);
+        }
+        
+        int scale = ICommonDataTypes.SIZEOF_JINT;
+        int ptr = memory.malloc(scale * values.length);
+        try {
+            // Regular copy. Memset first so we start from a known state.
+            memory.memset(ptr, (byte) 0, scale * values.length);
+            memory.setIntArray(ptr, values, 0, values.length, false);
+            assertIntsEqual(values, ptr);
+            
+            // Swapped copy.
+            memory.memset(ptr, (byte) 0, scale * values.length);
+            memory.setIntArray(ptr, values, 0, values.length, true);
+            assertIntsEqual(swappedValues, ptr);
+            
+            // Swapped copies of slices (to ensure we test non-zero offsets).
+            memory.memset(ptr, (byte) 0, scale * values.length);
+            for (int i = 0; i < values.length; ++i) {
+                memory.setIntArray(ptr + i * scale, values, i, 1, true);
+            }
+            assertIntsEqual(swappedValues, ptr);
+        } finally {
+            memory.free(ptr);
+        }
+    }
+    
+    private void assertIntsEqual(int[] expectedValues, int ptr) {
+        IMemorySystem memory = Platform.getMemorySystem();
+        for (int i = 0; i < expectedValues.length; ++i) {
+            assertEquals(expectedValues[i], memory.getInt(ptr + ICommonDataTypes.SIZEOF_JINT * i));
+        }
+    }
+    
+    private static int swapInt(int n) {
+        return (((n >>  0) & 0xff) << 24) |
+               (((n >>  8) & 0xff) << 16) |
+               (((n >> 16) & 0xff) <<  8) |
+               (((n >> 24) & 0xff) <<  0);
+    }
+    
+    @TestTargetNew(
+        level = TestLevel.PARTIAL_COMPLETE,
+        notes = "",
+        method = "setShortArray",
+        args = {}
+    )
+    public void testSetShortArray() {
+        IMemorySystem memory = Platform.getMemorySystem();
+        
+        short[] values = { 0x0001, 0x0020, 0x0300, 0x4000 };
+        short[] swappedValues = { 0x0100, 0x2000, 0x0003, 0x0040 };
+        
+        int scale = ICommonDataTypes.SIZEOF_JSHORT;
+        int ptr = memory.malloc(scale * values.length);
+        try {
+            // Regular copy. Memset first so we start from a known state.
+            memory.memset(ptr, (byte) 0, scale * values.length);
+            memory.setShortArray(ptr, values, 0, values.length, false);
+            assertShortsEqual(values, ptr);
+            
+            // Swapped copy.
+            memory.memset(ptr, (byte) 0, scale * values.length);
+            memory.setShortArray(ptr, values, 0, values.length, true);
+            assertShortsEqual(swappedValues, ptr);
+            
+            // Swapped copies of slices (to ensure we test non-zero offsets).
+            memory.memset(ptr, (byte) 0, scale * values.length);
+            for (int i = 0; i < values.length; ++i) {
+                memory.setShortArray(ptr + i * scale, values, i, 1, true);
+            }
+            assertShortsEqual(swappedValues, ptr);
+        } finally {
+            memory.free(ptr);
+        }
+    }
+    
+    private void assertShortsEqual(short[] expectedValues, int ptr) {
+        IMemorySystem memory = Platform.getMemorySystem();
+        for (int i = 0; i < expectedValues.length; ++i) {
+            assertEquals(expectedValues[i], memory.getShort(ptr + ICommonDataTypes.SIZEOF_JSHORT * i));
+        }
+    }
+    
+    private static short swapShort(short n) {
+        return (short) ((((n >>  0) & 0xff) << 8) | (((n >>  8) & 0xff) << 0));
+    }
+}
diff --git a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/InetAddressTest.java b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/InetAddressTest.java
index 5c8808c..6087a46 100644
--- a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/InetAddressTest.java
+++ b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/InetAddressTest.java
@@ -479,10 +479,6 @@
         }
     }
 
-    static final int TEST_IP_HASHCODE = 2130706433;
-    static final int TEST_IP6_HASHCODE = -1022939537;
-    static final int TEST_IP6_LO_HASHCODE = 1353309698;
-
     /**
      * @tests java.net.InetAddress#hashCode()
      */
@@ -492,28 +488,25 @@
         method = "hashCode",
         args = {}
     )
-    void assertHashCode(String literal, int expectedHashCode) {
+    int getHashCode(String literal) {
         InetAddress host = null;
         try {
             host = InetAddress.getByName(literal);
         } catch(UnknownHostException e) {
             fail("Exception during hashCode test : " + e.getMessage());
         }
-        int hashCode = host.hashCode();
-        assertEquals("incorrect hashCode for " + host, expectedHashCode,
-                hashCode);
+        return host.hashCode();
     }
 
     public void test_hashCode() {
-        // Test for method int java.net.InetAddress.hashCode()
-        // Create InetAddresses from string literals instead of from hostnames
-        // because we are only testing hashCode, not getByName. That way the
-        // test does not depend on name resolution and we can test many
-        // different addresses, not just localhost.
-        assertHashCode(Support_Configuration.InetTestIP, TEST_IP_HASHCODE);
-        assertHashCode(Support_Configuration.InetTestIP6, TEST_IP6_HASHCODE);
-        assertHashCode(Support_Configuration.InetTestIP6LO,
-                TEST_IP6_LO_HASHCODE);
+        int hashCode = getHashCode(Support_Configuration.InetTestIP);
+        int ip6HashCode = getHashCode(Support_Configuration.InetTestIP6);
+        int ip6LOHashCode = getHashCode(Support_Configuration.InetTestIP6LO);
+        assertFalse("Hash collision", hashCode == ip6HashCode);
+        assertFalse("Hash collision", ip6HashCode == ip6LOHashCode);
+        assertFalse("Hash collision", hashCode == ip6LOHashCode);
+        assertFalse("Hash collision", ip6LOHashCode == 0);
+        assertFalse("Hash collision", ip6LOHashCode == 1);
     }
 
     /**
diff --git a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/URLConnectionTest.java b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/URLConnectionTest.java
index bcd73d8..68ccb91 100644
--- a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/URLConnectionTest.java
+++ b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net/URLConnectionTest.java
@@ -17,14 +17,11 @@
 package org.apache.harmony.luni.tests.java.net;
 
 import dalvik.annotation.BrokenTest;
-import dalvik.annotation.KnownFailure;
 import dalvik.annotation.TestLevel;
 import dalvik.annotation.TestTargetClass;
 import dalvik.annotation.TestTargetNew;
 import dalvik.annotation.TestTargets;
-
 import junit.framework.TestCase;
-
 import tests.support.Support_Configuration;
 import tests.support.Support_PortManager;
 import tests.support.Support_TestWebData;
@@ -59,7 +56,6 @@
 import java.net.URLStreamHandler;
 import java.net.UnknownServiceException;
 import java.security.Permission;
-import java.text.DateFormat;
 import java.text.ParseException;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -463,6 +459,28 @@
         }
     }
 
+    public void testHttpPostHeaders() throws IOException {
+        String path = "/" + Math.random();
+        HttpURLConnection connection = (HttpURLConnection)
+                new URL("http://localhost:" + port + path).openConnection();
+
+        // post a request
+        connection.setDoOutput(true);
+        OutputStreamWriter writer
+                = new OutputStreamWriter(connection.getOutputStream());
+        writer.write("hello");
+        writer.flush();
+        assertEquals(200, connection.getResponseCode());
+
+        // validate the request by asking the server what was received
+        Map<String, String> headers = server.pathToRequest().get(path).getHeaders();
+        assertEquals("*, */*", headers.get("Accept"));
+        assertEquals("application/x-www-form-urlencoded", headers.get("Content-Type"));
+        assertEquals("5", headers.get("Content-Length"));
+        assertEquals("localhost:" + port, headers.get("Host"));
+        // TODO: test User-Agent?
+    }
+
     /**
      * @throws IOException 
      * @tests {@link java.net.URLConnection#getAllowUserInteraction()}
diff --git a/libcore/luni/src/test/java/tests/AllTests.java b/libcore/luni/src/test/java/tests/AllTests.java
index 26e58c1..893cdf0 100644
--- a/libcore/luni/src/test/java/tests/AllTests.java
+++ b/libcore/luni/src/test/java/tests/AllTests.java
@@ -54,6 +54,8 @@
         suite.addTest(tests.xml.AllTests.suite());
         suite.addTest(tests.xnet.AllTests.suite());
 
+        suite.addTest(org.apache.harmony.luni.platform.AllTests.suite());
+        
         return suite;
     }
 }
diff --git a/libcore/luni/src/test/java/tests/api/java/io/OutputStreamWriterTest.java b/libcore/luni/src/test/java/tests/api/java/io/OutputStreamWriterTest.java
index b745662..22e1af7 100644
--- a/libcore/luni/src/test/java/tests/api/java/io/OutputStreamWriterTest.java
+++ b/libcore/luni/src/test/java/tests/api/java/io/OutputStreamWriterTest.java
@@ -17,7 +17,6 @@
 
 package tests.api.java.io;
 
-import dalvik.annotation.KnownFailure;
 import dalvik.annotation.TestTargets;
 import dalvik.annotation.TestLevel;
 import dalvik.annotation.TestTargetNew;
@@ -31,7 +30,6 @@
 import java.io.UnsupportedEncodingException;
 import java.nio.charset.Charset;
 import java.nio.charset.CharsetEncoder;
-import java.util.Arrays;
 
 import tests.support.Support_OutputStream;
 
@@ -426,7 +424,6 @@
                 clazz = InputStreamReader.class
         )
     })
-    @KnownFailure("Error when reading bytes in UTF-8 expected:<8916> but was:<8907> ")
     public void test_write$C() throws Exception {
         int upper;
         InputStreamReader isr = null;
@@ -471,7 +468,7 @@
                         j = 0;
                     }
                     assertEquals("Error when reading bytes in "
-                            + MINIMAL_CHARSETS[i], expected++, largeBuffer[j++]);
+                            + MINIMAL_CHARSETS[i] + " at " + j, expected++, largeBuffer[j++]);
                 }
             } finally {
                 try {
@@ -878,5 +875,4 @@
             fail("UTF-8 not supported");
         }
     }
-
 }
diff --git a/libcore/luni/src/test/java/tests/api/java/lang/reflect/ConstructorTest.java b/libcore/luni/src/test/java/tests/api/java/lang/reflect/ConstructorTest.java
index 6bdb55a..e9554dd 100644
--- a/libcore/luni/src/test/java/tests/api/java/lang/reflect/ConstructorTest.java
+++ b/libcore/luni/src/test/java/tests/api/java/lang/reflect/ConstructorTest.java
@@ -104,7 +104,11 @@
         public GenericConstructorTestHelper(T t, S s) {}
         public GenericConstructorTestHelper() throws E{}
     }
- 
+    
+    static class NoPublicConstructorTestHelper {
+        // This class has no public constructor.
+    }
+    
 //    Used to test synthetic constructor.
 //    
 //    static class Outer {
@@ -479,7 +483,6 @@
         } catch (Exception e) {
             fail("Exception during getGenericExceptionTypes test:" + e.toString());
         }
-        System.out.println(Arrays.toString(types));
         assertEquals("Wrong number of exception types returned", 1, types.length);
        
         
@@ -555,7 +558,35 @@
                         .equals(
                                 "public tests.api.java.lang.reflect.ConstructorTest$ConstructorTestHelper(java.lang.Object)"));
     }
-
+    
+    /**
+     * @tests java.lang.reflect.Constructor#getConstructor((Class[]) null)
+     */
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "",
+        method = "getConstructor",
+        args = {}
+    )
+    public void test_getConstructor() throws Exception {
+        // Passing new Class[0] should be equivalent to (Class[]) null.
+        Class<ConstructorTestHelper> c2 = ConstructorTestHelper.class;
+        assertEquals(c2.getConstructor(new Class[0]), c2.getConstructor((Class[]) null));
+        assertEquals(c2.getDeclaredConstructor(new Class[0]),
+                     c2.getDeclaredConstructor((Class[]) null));
+        
+        // We can get a non-public constructor via getDeclaredConstructor...
+        Class<NoPublicConstructorTestHelper> c1 = NoPublicConstructorTestHelper.class;
+        c1.getDeclaredConstructor((Class[]) null);
+        // ...but not with getConstructor (which only returns public constructors).
+        try {
+            c1.getConstructor((Class[]) null);
+            fail("Should throw NoSuchMethodException");
+        } catch (NoSuchMethodException ex) {
+            // Expected.
+        }
+    }
+    
     /**
      * Sets up the fixture, for example, open a network connection. This method
      * is called before a test is executed.
@@ -570,4 +601,3 @@
     protected void tearDown() {
     }
 }
-
diff --git a/libcore/luni/src/test/java/tests/api/java/lang/reflect/MethodTest.java b/libcore/luni/src/test/java/tests/api/java/lang/reflect/MethodTest.java
index 884bc8c..506d173 100644
--- a/libcore/luni/src/test/java/tests/api/java/lang/reflect/MethodTest.java
+++ b/libcore/luni/src/test/java/tests/api/java/lang/reflect/MethodTest.java
@@ -226,7 +226,41 @@
         }
         assertTrue("Inherited method returned not-equal", m1.equals(m2));
     }
-
+    
+    /**
+     * @tests java.lang.Class#getMethod(java.lang.String, java.lang.Class[])
+     */
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "",
+        method = "getMethod",
+        args = {java.lang.String.class, java.lang.Class[].class},
+        clazz = java.lang.Class.class
+    )
+    public void test_getMethod() throws NoSuchMethodException, SecurityException {
+        // Check that getMethod treats null parameterTypes the same as an empty array.
+        Method m1 = TestMethod.class.getMethod("invokeInstanceTest", new Class[0]);
+        Method m2 = TestMethod.class.getMethod("invokeInstanceTest", (Class[]) null);
+        assertEquals(m1, m2);
+    }
+    
+    /**
+     * @tests java.lang.Class#getDeclaredMethod(java.lang.String, java.lang.Class[])
+     */
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "",
+        method = "getDeclaredMethod",
+        args = {java.lang.String.class, java.lang.Class[].class},
+        clazz = java.lang.Class.class
+    )
+    public void test_getDeclaredMethod() throws NoSuchMethodException, SecurityException {
+        // Check that getDeclaredMethod treats null parameterTypes the same as an empty array.
+        Method m1 = TestMethod.class.getDeclaredMethod("invokeInstanceTest", new Class[0]);
+        Method m2 = TestMethod.class.getDeclaredMethod("invokeInstanceTest", (Class[]) null);
+        assertEquals(m1, m2);
+    }
+    
     /**
      * @tests java.lang.reflect.Method#getDeclaringClass()
      */
diff --git a/libcore/luni/src/test/java/tests/api/java/util/CollectionsTest.java b/libcore/luni/src/test/java/tests/api/java/util/CollectionsTest.java
index b75898b..2b1b47e 100644
--- a/libcore/luni/src/test/java/tests/api/java/util/CollectionsTest.java
+++ b/libcore/luni/src/test/java/tests/api/java/util/CollectionsTest.java
@@ -1435,11 +1435,7 @@
                 .indexOfSubList(src, sub2));
     }
 
-    /**
-     * @param string2
-     * @param string1
-     * @param index
-     */
+
     private void testwithCharList(int count, String string1, String string2,
             boolean first) {
         char[] chars = string1.toCharArray();
@@ -2379,9 +2375,11 @@
         m.put("one", "1");
         m.put("two", "2");
         Map um = Collections.unmodifiableMap(m);
-        assertEquals("{one=1, two=2}", um.toString());
+        assertTrue("{one=1, two=2}".equals(um.toString()) ||
+                   "{two=2, one=1}".equals(um.toString())); 
     }
 
+
     @TestTargetNew(
         level = TestLevel.COMPLETE,
         notes = "",
diff --git a/libcore/luni/src/test/java/tests/api/java/util/HashMapTest.java b/libcore/luni/src/test/java/tests/api/java/util/HashMapTest.java
index 1d726ea..af73c0a 100644
--- a/libcore/luni/src/test/java/tests/api/java/util/HashMapTest.java
+++ b/libcore/luni/src/test/java/tests/api/java/util/HashMapTest.java
@@ -20,17 +20,9 @@
 import dalvik.annotation.TestTargetNew;
 import dalvik.annotation.TestTargets;
 import dalvik.annotation.TestLevel;
-import dalvik.annotation.TestTargetClass; 
+import dalvik.annotation.TestTargetClass;
 
-import java.util.AbstractMap;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
+import java.util.*;
 
 import tests.support.Support_MapTest2;
 import tests.support.Support_UnmodifiableCollectionTest;
@@ -39,7 +31,7 @@
 public class HashMapTest extends junit.framework.TestCase {
     class MockMap extends AbstractMap {
         public Set entrySet() {
-            return null;
+            return Collections.EMPTY_SET;
         }
         public int size(){
             return 0;
@@ -151,14 +143,10 @@
         for (int counter = 0; counter < hmSize; counter++)
             assertTrue("Failed to construct correct HashMap", hm
                     .get(objArray2[counter]) == hm2.get(objArray2[counter]));
-        
-        try {
-            Map mockMap = new MockMap();
-            hm = new HashMap(mockMap);
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
-            //empty
-        }
+
+        Map mockMap = new MockMap();
+        hm = new HashMap(mockMap);
+        assertEquals(hm, mockMap);
     }
 
     /**
@@ -296,6 +284,40 @@
     }
 
     /**
+     * @tests java.util.HashMap#entrySet()
+     */
+    @TestTargetNew(
+        level = TestLevel.PARTIAL_COMPLETE,
+        notes = "",
+        method = "entrySet",
+        args = {}
+    )
+    public void test_entrySetEquals() {
+        Set s1 = hm.entrySet();
+        Set s2 = new HashMap(hm).entrySet();
+        assertEquals(s1, s2);
+    }
+
+    /**
+     * @tests java.util.HashMap#entrySet()
+     */
+    @TestTargetNew(
+        level = TestLevel.PARTIAL_COMPLETE,
+        notes = "",
+        method = "entrySet",
+        args = {}
+    )
+    public void test_removeFromViews() {
+        hm.put("A", null);
+        hm.put("B", null);
+        assertTrue(hm.keySet().remove("A"));
+
+        Map<String, String> m2 = new HashMap<String, String>();
+        m2.put("B", null);
+        assertTrue(hm.entrySet().remove(m2.entrySet().iterator().next()));
+    }
+
+    /**
      * @tests java.util.HashMap#get(java.lang.Object)
      */
     @TestTargetNew(
@@ -479,7 +501,39 @@
         } catch (NullPointerException e) {
             // expected.
         }
-    } 
+    }
+
+    @TestTargetNew(
+            level = TestLevel.PARTIAL_COMPLETE,
+            notes = "Checks putAll that causes map to resize",
+            method = "putAll",
+            args = {java.util.Map.class}
+    )
+    public void test_putAllLjava_util_Map_Resize() {
+        Random rnd = new Random(666);
+
+        Map<Integer,Integer> m1 = new HashMap<Integer, Integer>();
+        int MID = 10000;
+        for (int i = 0; i < MID; i++) {
+            Integer j = rnd.nextInt();
+            m1.put(j, j);
+        }
+
+        Map<Integer,Integer> m2 = new HashMap<Integer, Integer>();
+        int HI = 30000;
+        for (int i = MID; i < HI; i++) {
+            Integer j = rnd.nextInt();
+            m2.put(j, j);
+        }
+        
+        m1.putAll(m2);
+
+        rnd = new Random(666);
+        for (int i = 0; i < HI; i++) {
+            Integer j = rnd.nextInt();
+            assertEquals(j, m1.get(j));
+        }
+    }
 
     /**
      * @tests java.util.HashMap#remove(java.lang.Object)
diff --git a/libcore/luni/src/test/java/tests/api/java/util/HashtableTest.java b/libcore/luni/src/test/java/tests/api/java/util/HashtableTest.java
index bbdad50..6c50f1b 100644
--- a/libcore/luni/src/test/java/tests/api/java/util/HashtableTest.java
+++ b/libcore/luni/src/test/java/tests/api/java/util/HashtableTest.java
@@ -35,6 +35,7 @@
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.Vector;
+import java.util.Collections;
 
 import tests.api.java.util.HashMapTest.ReusableKey;
 import tests.support.Support_MapTest2;
@@ -166,6 +167,24 @@
     }
 
     /**
+     * @tests java.util.Hashtable#Hashtable(java.util.Map)
+     */
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "",
+        method = "Hashtable",
+        args = {java.util.Map.class}
+    )
+    public void test_ConversionConstructorNullValue() {
+        Map<String, Void> map = Collections.singletonMap("Dog", null);
+        try {
+            new Hashtable<String, Void>(map);
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            //expected
+        }
+    }
+    /**
      * @tests java.util.Hashtable#clear()
      */
     @TestTargetNew(
@@ -310,46 +329,49 @@
         assertEquals("All keys not retrieved", 10, ht10.size());
     }
 
-    /**
-     * @tests java.util.Hashtable#elements()
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "elements",
-        args = {}
-    )
-    public void test_elements_subtest0() {
-        // this is the reference implementation behavior
-        final Hashtable ht = new Hashtable(7);
-        ht.put("1", "a");
-        // these three elements hash to the same bucket in a 7 element Hashtable
-        ht.put("2", "b");
-        ht.put("9", "c");
-        ht.put("12", "d");
-        // Hashtable looks like:
-        // 0: "1"
-        // 1: "12" -> "9" -> "2"
-        Enumeration en = ht.elements();
-        // cache the first entry
-        en.hasMoreElements();
-        ht.remove("12");
-        ht.remove("9");
-        boolean exception = false;
-        try {
-            // cached "12"
-            Object result = en.nextElement();
-            assertNull("unexpected: " + result, result);
-            // next is removed "9"
-            result = en.nextElement();
-            assertNull("unexpected: " + result, result);
-            result = en.nextElement();
-            assertTrue("unexpected: " + result, "b".equals(result));
-        } catch (NoSuchElementException e) {
-            exception = true;
-        }
-        assertTrue("unexpected NoSuchElementException", !exception);
-    }
+// BEGIN android-removed
+// implementation dependent
+//    /**
+//     * @tests java.util.Hashtable#elements()
+//     */
+//    @TestTargetNew(
+//        level = TestLevel.COMPLETE,
+//        notes = "",
+//        method = "elements",
+//        args = {}
+//    )
+//    public void test_elements_subtest0() {
+//        // this is the reference implementation behavior
+//        final Hashtable ht = new Hashtable(7);
+//        ht.put("1", "a");
+//        // these three elements hash to the same bucket in a 7 element Hashtable
+//        ht.put("2", "b");
+//        ht.put("9", "c");
+//        ht.put("12", "d");
+//        // Hashtable looks like:
+//        // 0: "1"
+//        // 1: "12" -> "9" -> "2"
+//        Enumeration en = ht.elements();
+//        // cache the first entry
+//        en.hasMoreElements();
+//        ht.remove("12");
+//        ht.remove("9");
+//        boolean exception = false;
+//        try {
+//            // cached "12"
+//            Object result = en.nextElement();
+//            assertNull("unexpected: " + result, result);
+//            // next is removed "9"
+//            result = en.nextElement();
+//            assertNull("unexpected: " + result, result);
+//            result = en.nextElement();
+//            assertTrue("unexpected: " + result, "b".equals(result));
+//        } catch (NoSuchElementException e) {
+//            exception = true;
+//        }
+//        assertTrue("unexpected NoSuchElementException", !exception);
+//    }
+// END android-removed
 
     /**
      * @tests java.util.Hashtable#entrySet()
@@ -371,9 +393,11 @@
         while (e.hasMoreElements())
             assertTrue("Returned incorrect entry set", s2.contains(e
                     .nextElement()));
-
-        assertEquals("Not synchronized", 
-                "java.util.Collections$SynchronizedSet", s.getClass().getName());
+// BEGIN android-removed
+// implementation dependent
+//        assertEquals("Not synchronized",
+//                "java.util.Collections$SynchronizedSet", s.getClass().getName());
+// END android-removed
 
         boolean exception = false;
         try {
@@ -417,26 +441,28 @@
         Hashtable h = hashtableClone(htfull);
         assertEquals("Could not retrieve element", "FVal 2", ((String) h.get("FKey 2"))
                 );
-        
-        
-        // Regression for HARMONY-262
-        ReusableKey k = new ReusableKey();
-        Hashtable h2 = new Hashtable();
-        k.setKey(1);
-        h2.put(k, "value1");
 
-        k.setKey(13);
-        assertNull(h2.get(k));
-
-        k.setKey(12);
-        assertNull(h2.get(k));
-
-        try {
-            h2.get(null);
-            fail("NullPointerException expected");
-        } catch (NullPointerException e) {
-            //expected
-        }
+// BEGIN android-removed
+// implementation dependent
+//        // Regression for HARMONY-262
+//        ReusableKey k = new ReusableKey();
+//        Hashtable h2 = new Hashtable();
+//        k.setKey(1);
+//        h2.put(k, "value1");
+//
+//        k.setKey(13);
+//        assertNull(h2.get(k));
+//
+//        k.setKey(12);
+//        assertNull(h2.get(k));
+//        
+//        try {
+//            h2.get(null);
+//            fail("NullPointerException expected");
+//        } catch (NullPointerException e) {
+//            //expected
+//        }
+// END android-removed
     }
 
     /**
@@ -569,9 +595,12 @@
             assertTrue("Returned incorrect key set", s
                     .contains(e.nextElement()));
 
-        assertEquals("Not synchronized", 
-                "java.util.Collections$SynchronizedSet", s.getClass().getName());
-
+// BEGIN android-removed
+// implementation dependent
+//        assertEquals("Not synchronized",
+//                "java.util.Collections$SynchronizedSet", s.getClass().getName());
+// END android-removed
+        
         Map map = new Hashtable(101);
         map.put(new Integer(1), "1");
         map.put(new Integer(102), "102");
@@ -651,54 +680,57 @@
         }
     }
 
-    /**
-     * @tests java.util.Hashtable#keySet()
-     */
-    @TestTargetNew(
-        level = TestLevel.PARTIAL_COMPLETE,
-        notes = "",
-        method = "keySet",
-        args = {}
-    )
-    public void test_keySet_subtest1() {
-        // this is the reference implementation behavior
-        final Hashtable ht = new Hashtable(7);
-        ht.put("1", "a");
-        // these three elements hash to the same bucket in a 7 element Hashtable
-        ht.put("2", "b");
-        ht.put("9", "c");
-        ht.put("12", "d");
-        // Hashtable looks like:
-        // 0: "1"
-        // 1: "12" -> "9" -> "2"
-        Enumeration en = ht.elements();
-        // cache the first entry
-        en.hasMoreElements();
-        Iterator it = ht.keySet().iterator();
-        // this is mostly a copy of the test in test_elements_subtest0()
-        // test removing with the iterator does not null the values
-        while (it.hasNext()) {
-            String key = (String) it.next();
-            if ("12".equals(key) || "9".equals(key)) {
-                it.remove();
-            }
-        }
-        it.remove();
-        boolean exception = false;
-        try {
-            // cached "12"
-            Object result = en.nextElement();
-            assertTrue("unexpected: " + result, "d".equals(result));
-            // next is removed "9"
-            result = en.nextElement();
-            assertTrue("unexpected: " + result, "c".equals(result));
-            result = en.nextElement();
-            assertTrue("unexpected: " + result, "b".equals(result));
-        } catch (NoSuchElementException e) {
-            exception = true;
-        }
-        assertTrue("unexpected NoSuchElementException", !exception);
-    }
+// BEGIN android-removed
+// implementation dependent
+//    /**
+//     * @tests java.util.Hashtable#keySet()
+//     */
+//    @TestTargetNew(
+//        level = TestLevel.PARTIAL_COMPLETE,
+//        notes = "",
+//        method = "keySet",
+//        args = {}
+//    )
+//    public void test_keySet_subtest1() {
+//        // this is the reference implementation behavior
+//        final Hashtable ht = new Hashtable(7);
+//        ht.put("1", "a");
+//        // these three elements hash to the same bucket in a 7 element Hashtable
+//        ht.put("2", "b");
+//        ht.put("9", "c");
+//        ht.put("12", "d");
+//        // Hashtable looks like:
+//        // 0: "1"
+//        // 1: "12" -> "9" -> "2"
+//        Enumeration en = ht.elements();
+//        // cache the first entry
+//        en.hasMoreElements();
+//        Iterator it = ht.keySet().iterator();
+//        // this is mostly a copy of the test in test_elements_subtest0()
+//        // test removing with the iterator does not null the values
+//        while (it.hasNext()) {
+//            String key = (String) it.next();
+//            if ("12".equals(key) || "9".equals(key)) {
+//                it.remove();
+//            }
+//        }
+//        it.remove();
+//        boolean exception = false;
+//        try {
+//            // cached "12"
+//            Object result = en.nextElement();
+//            assertTrue("unexpected: " + result, "d".equals(result));
+//            // next is removed "9"
+//            result = en.nextElement();
+//            assertTrue("unexpected: " + result, "c".equals(result));
+//            result = en.nextElement();
+//            assertTrue("unexpected: " + result, "b".equals(result));
+//        } catch (NoSuchElementException e) {
+//            exception = true;
+//        }
+//        assertTrue("unexpected NoSuchElementException", !exception);
+//    }
+// END android-removed
 
     /**
      * @tests java.util.Hashtable#put(java.lang.Object, java.lang.Object)
@@ -871,9 +903,12 @@
         while (e.hasMoreElements())
             assertTrue("Returned incorrect values", c.contains(e.nextElement()));
 
-        assertEquals("Not synchronized", 
-                "java.util.Collections$SynchronizedCollection", c.getClass().getName());
-
+// BEGIN android-removed
+// implementation dependent
+//        assertEquals("Not synchronized",
+//                "java.util.Collections$SynchronizedCollection", c.getClass().getName());
+// END android-removed
+        
         Hashtable myHashtable = new Hashtable();
         for (int i = 0; i < 100; i++)
             myHashtable.put(new Integer(i), new Integer(i));
diff --git a/libcore/luni/src/test/java/tests/api/java/util/LinkedHashMapTest.java b/libcore/luni/src/test/java/tests/api/java/util/LinkedHashMapTest.java
index bfa474b..f3d0a7b 100644
--- a/libcore/luni/src/test/java/tests/api/java/util/LinkedHashMapTest.java
+++ b/libcore/luni/src/test/java/tests/api/java/util/LinkedHashMapTest.java
@@ -209,6 +209,26 @@
                 new Integer(0)));
     }
 
+
+    @TestTargetNew(
+        level = TestLevel.PARTIAL_COMPLETE,
+        notes = "test that put on an already present key causes entry to move to tail.",
+        method = "put",
+        args = {java.lang.Object.class, java.lang.Object.class}
+    )
+    public void test_putPresent() {
+        Map<String, String> m = new LinkedHashMap<String, String>(8, .75f, true);
+        m.put("KEY", "VALUE");
+        m.put("WOMBAT", "COMBAT");
+        m.put("KEY", "VALUE");
+        Map.Entry newest = null;
+        for (Map.Entry<String, String> e : m.entrySet()) {
+            newest = e;
+        }
+        assertEquals("KEY", newest.getKey());
+        assertEquals("VALUE", newest.getValue());
+    }
+
     /**
      * @tests java.util.LinkedHashMap#putAll(java.util.Map)
      */
@@ -275,6 +295,26 @@
         }
     }
 
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "Test that remove removes the entry from the linked list",
+        method = "entrySet",
+        args = {}
+    )
+    public void test_entrySetRemove() {
+        entrySetRemoveHelper("military", "intelligence");
+        entrySetRemoveHelper(null, "hypothesis");  
+    }
+    private void entrySetRemoveHelper(String key, String value) {
+        Map<String, String> m1 = new LinkedHashMap<String, String>();
+        m1.put(key, value);
+        m1.put("jumbo", "shrimp");
+        LinkedHashMap<String, String> m2 = new LinkedHashMap<String, String>(m1);
+        Set<Map.Entry<String, String>> s1 = m1.entrySet();
+        s1.remove(m2.entrySet().iterator().next());
+        assertEquals("jumbo", s1.iterator().next().getKey());
+    }
+
     /**
      * @tests java.util.LinkedHashMap#keySet()
      */
diff --git a/libcore/prefs/src/main/java/java/util/prefs/AbstractPreferences.java b/libcore/prefs/src/main/java/java/util/prefs/AbstractPreferences.java
index 711cc01..3264569 100644
--- a/libcore/prefs/src/main/java/java/util/prefs/AbstractPreferences.java
+++ b/libcore/prefs/src/main/java/java/util/prefs/AbstractPreferences.java
@@ -20,6 +20,7 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
+import java.util.Collection;
 import java.util.EventListener;
 import java.util.EventObject;
 import java.util.HashMap;
@@ -27,7 +28,6 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.StringTokenizer;
 import java.util.TreeSet;
 
 import org.apache.harmony.luni.util.Base64;
@@ -38,8 +38,9 @@
  * Preferences, which can be used to simplify {@code Preferences} provider's
  * implementation. This class defines nine abstract SPI methods, which must be
  * implemented by a preference provider.
- * 
- * @since Android 1.0
+ *
+ * @since 1.4
+ * @see Preferences
  */
 public abstract class AbstractPreferences extends Preferences {
     /*
@@ -47,14 +48,9 @@
      * Class fields
      * -----------------------------------------------------------
      */
-    /**
-     * The unhandled events collection.
-     */
+    /** the unhandled events collection */
     private static final List<EventObject> events = new LinkedList<EventObject>();
-
-    /**
-     * The event dispatcher thread.
-     */
+    /** the event dispatcher thread */
     private static final EventDispatcher dispatcher = new EventDispatcher("Preference Event Dispatcher"); //$NON-NLS-1$
 
     /*
@@ -72,11 +68,13 @@
                 Preferences sroot = Preferences.systemRoot();
                 try {
                     uroot.flush();
-                } catch (BackingStoreException e) {//ignore
+                } catch (BackingStoreException e) {
+                    // ignore
                 }
                 try {
                     sroot.flush();
-                } catch (BackingStoreException e) {//ignore
+                } catch (BackingStoreException e) {
+                    // ignore
                 }
             }
         });
@@ -87,9 +85,7 @@
      * Instance fields (package-private)
      * -----------------------------------------------------------
      */
-    /**
-     * True, if this node is in user preference hierarchy.
-     */
+    /** true if this node is in user preference hierarchy */
     boolean userNode;
 
     /*
@@ -97,16 +93,11 @@
      * Instance fields (private)
      * -----------------------------------------------------------
      */
-    /**
-     * Marker class for 'lock' field.
-     */
-    private static class Lock {
-    }
+    /** Marker class for 'lock' field. */
+    private static class Lock {}
 
     /**
      * The object used to lock this node.
-     * 
-     * @since Android 1.0
      */
     protected final Object lock;
     
@@ -115,14 +106,10 @@
      * backing store. This field's default value is false, and it is checked
      * when the node creation is completed, and if it is true, the node change
      * event will be fired for this node's parent.
-     * 
-     * @since Android 1.0
      */
     protected boolean newNode;
 
-    /**
-     * Cached child nodes
-     */
+    /** cached child nodes */
     private Map<String, AbstractPreferences> cachedNode;
 
     //the collections of listeners
@@ -147,9 +134,9 @@
      * -----------------------------------------------------------
      */
     /**
-     * Constructs a new {@code AbstractPreferences} instance using the given parent node
-     * and node name.
-     * 
+     * Constructs a new {@code AbstractPreferences} instance using the given
+     * parent node and node name.
+     *
      * @param parent
      *            the parent node of the new node or {@code null} to indicate
      *            that the new node is a root node.
@@ -159,7 +146,6 @@
      * @throws IllegalArgumentException
      *             if the name contains a slash character or is empty if {@code
      *             parent} is not {@code null}.
-     * @since Android 1.0
      */
     protected AbstractPreferences(AbstractPreferences parent, String name) {
         if ((null == parent ^ name.length() == 0) || name.indexOf("/") >= 0) { //$NON-NLS-1$
@@ -185,7 +171,6 @@
      * Returns an array of all cached child nodes.
      * 
      * @return the array of cached child nodes.
-     * @since Android 1.0
      */
     protected final AbstractPreferences[] cachedChildren() {
         return cachedNode.values().toArray(new AbstractPreferences[cachedNode.size()]);
@@ -193,9 +178,10 @@
 
     /**
      * Returns the child node with the specified name or {@code null} if it
-     * doesn't exist. Implementers can assume that the name supplied to this method 
-     * will be a valid node name string (conforming to the node naming format) and 
-     * will not correspond to a node that has been cached or removed.
+     * doesn't exist. Implementers can assume that the name supplied to this
+     * method will be a valid node name string (conforming to the node naming
+     * format) and will not correspond to a node that has been cached or
+     * removed.
      * 
      * @param name
      *            the name of the desired child node.
@@ -204,7 +190,6 @@
      * @throws BackingStoreException
      *             if the backing store is unavailable or causes an operation
      *             failure.
-     * @since Android 1.0
      */
     protected AbstractPreferences getChild(String name)
             throws BackingStoreException {
@@ -226,10 +211,9 @@
     /**
      * Returns whether this node has been removed by invoking the method {@code
      * removeNode()}.
-     * 
+     *
      * @return {@code true}, if this node has been removed, {@code false}
      *         otherwise.
-     * @since Android 1.0
      */
     protected boolean isRemoved() {
         synchronized (lock) {
@@ -240,33 +224,31 @@
     /**
      * Flushes changes of this node to the backing store. This method should
      * only flush this node and should not include the descendant nodes. Any
-     * implementation that wants to provide functionality to flush all nodes 
+     * implementation that wants to provide functionality to flush all nodes
      * at once should override the method {@link #flush() flush()}.
-     * 
+     *
      * @throws BackingStoreException
      *             if the backing store is unavailable or causes an operation
      *             failure.
-     * @since Android 1.0
      */
     protected abstract void flushSpi() throws BackingStoreException;
     
     /**
-     * Returns the names of all of the child nodes of this node or an empty array if
-     * this node has no children. The names of cached children are not required to be
-     * returned.
-     * 
+     * Returns the names of all of the child nodes of this node or an empty
+     * array if this node has no children. The names of cached children are not
+     * required to be returned.
+     *
      * @return the names of this node's children.
      * @throws BackingStoreException
      *             if the backing store is unavailable or causes an operation
      *             failure.
-     * @since Android 1.0
      */
     protected abstract String[] childrenNamesSpi() throws BackingStoreException;
 
     /**
      * Returns the child preference node with the given name, creating it
      * if it does not exist. The caller of this method should ensure that the
-     * given name is valid and that this node has not been removed or cached. 
+     * given name is valid and that this node has not been removed or cached.
      * If the named node has just been removed, the implementation
      * of this method must create a new one instead of reactivating the removed
      * one.
@@ -278,7 +260,6 @@
      * @param name
      *            the name of the child preference to be returned.
      * @return the child preference node.
-     * @since Android 1.0
      */
     protected abstract AbstractPreferences childSpi(String name);
 
@@ -287,39 +268,37 @@
      * Puts the given key-value pair into this node. Caller of this method
      * should ensure that both of the given values are valid and that this
      * node has not been removed.
-     * 
+     *
      * @param name
      *            the given preference key.
      * @param value
      *            the given preference value.
-     * @since Android 1.0
      */
     protected abstract void putSpi(String name, String value);
 
     /**
-     * Gets the preference value mapped to the given key. The caller of this method
-     * should ensure that the given key is valid and that this node has not been
-     * removed. This method should not throw any exceptions but if it does, the
-     * caller will ignore the exception, regarding it as a {@code null} return value.
-     * 
+     * Gets the preference value mapped to the given key. The caller of this
+     * method should ensure that the given key is valid and that this node has
+     * not been removed. This method should not throw any exceptions but if it
+     * does, the caller will ignore the exception, regarding it as a {@code
+     * null} return value.
+     *
      * @param key
      *            the given key to be searched for.
      * @return the preference value mapped to the given key.
-     * @since Android 1.0
      */
     protected abstract String getSpi(String key);
 
 
     /**
      * Returns an array of all preference keys of this node or an empty array if
-     * no preferences have been found. The caller of this method should ensure that
-     * this node has not been removed.
-     * 
+     * no preferences have been found. The caller of this method should ensure
+     * that this node has not been removed.
+     *
      * @return the array of all preference keys.
      * @throws BackingStoreException
      *             if the backing store is unavailable or causes an operation
      *             failure.
-     * @since Android 1.0
      */
     protected abstract String[] keysSpi() throws BackingStoreException;
 
@@ -329,11 +308,10 @@
      * method {@link Preferences#removeNode() Preferences.removeNode()} should
      * invoke this method multiple-times in bottom-up pattern. The removal is
      * not required to be persisted until after it is flushed.
-     * 
+     *
      * @throws BackingStoreException
      *             if the backing store is unavailable or causes an operation
      *             failure.
-     * @since Android 1.0
      */
     protected abstract void removeNodeSpi() throws BackingStoreException;
 
@@ -344,20 +322,18 @@
      * 
      * @param key
      *            the key of the preference that is to be removed.
-     * @since Android 1.0
      */
     protected abstract void removeSpi(String key);
 
     /**
      * Synchronizes this node with the backing store. This method should only
      * synchronize this node and should not include the descendant nodes. An
-     * implementation that wants to provide functionality to synchronize all nodes at once should
-     * override the method {@link #sync() sync()}.
+     * implementation that wants to provide functionality to synchronize all
+     * nodes at once should override the method {@link #sync() sync()}.
      * 
      * @throws BackingStoreException
      *             if the backing store is unavailable or causes an operation
      *             failure.
-     * @since Android 1.0
      */
     protected abstract void syncSpi() throws BackingStoreException;
 
@@ -385,7 +361,7 @@
             for (int i = 0; i < names.length; i++) {
                 result.add(names[i]);
             }
-            return result.toArray(new String[0]);
+            return result.toArray(new String[result.size()]);
         }
     }
 
@@ -439,13 +415,13 @@
         if (key == null) {
             throw new NullPointerException();
         }
-        String result;
+        String result = null;
         synchronized (lock) {
             checkState();
             try {
                 result = getSpi(key);
             } catch (Exception e) {
-                result = null;
+                // ignored
             }
         }
         return (result == null ? deflt : result);
@@ -456,9 +432,10 @@
         String result = get(key, null);
         if (result == null) {
             return deflt;
-        } else if (result.equalsIgnoreCase("true")) { //$NON-NLS-1$
+        }
+        if ("true".equalsIgnoreCase(result)) { //$NON-NLS-1$
             return true;
-        } else if (result.equalsIgnoreCase("false")) { //$NON-NLS-1$
+        } else if ("false".equalsIgnoreCase(result)) { //$NON-NLS-1$
             return false;
         } else {
             return deflt;
@@ -474,17 +451,15 @@
         if (svalue.length() == 0) { 
             return new byte[0];
         }
-        byte[] dres;
         try {
             byte[] bavalue = svalue.getBytes("US-ASCII"); //$NON-NLS-1$
             if (bavalue.length % 4 != 0) {
                 return deflt;
             }
-            dres = Base64.decode(bavalue);
+            return Base64.decode(bavalue);
         } catch (Exception e) {
-            dres = deflt;
+            return deflt;
         }
-        return dres;
     }
 
     @Override
@@ -493,13 +468,11 @@
         if (result == null) {
             return deflt;
         }
-        double dres;
         try {
-            dres = Double.parseDouble(result);
+            return Double.parseDouble(result);
         } catch (NumberFormatException e) {
-            dres = deflt;
+            return deflt;
         }
-        return dres;
     }
 
     @Override
@@ -508,13 +481,11 @@
         if (result == null) {
             return deflt;
         }
-        float fres;
         try {
-            fres = Float.parseFloat(result);
+            return Float.parseFloat(result);
         } catch (NumberFormatException e) {
-            fres = deflt;
+            return deflt;
         }
-        return fres;
     }
 
     @Override
@@ -523,13 +494,11 @@
         if (result == null) {
             return deflt;
         }
-        int ires;
         try {
-            ires = Integer.parseInt(result);
+            return Integer.parseInt(result);
         } catch (NumberFormatException e) {
-            ires = deflt;
+            return deflt;
         }
-        return ires;
     }
 
     @Override
@@ -538,13 +507,11 @@
         if (result == null) {
             return deflt;
         }
-        long lres;
         try {
-            lres = Long.parseLong(result);
+            return Long.parseLong(result);
         } catch (NumberFormatException e) {
-            lres = deflt;
+            return deflt;
         }
-        return lres;
     }
 
     @Override
@@ -583,42 +550,44 @@
                 startNode = this;
             }
         }
-        Preferences result = null;
         try {
-            result = startNode.nodeImpl(name, true);
+            return startNode.nodeImpl(name, true);
         } catch (BackingStoreException e) {
-            //should not happen
+            // should not happen
+            return null;
         }
-        return result;
     }
 
     private void validateName(String name) {
         if (name.endsWith("/") && name.length() > 1) { //$NON-NLS-1$
             // prefs.6=Name cannot end with '/'\!
-            throw new IllegalArgumentException(Messages.getString("prefs.6"));  //$NON-NLS-1$
+            throw new IllegalArgumentException(Messages.getString("prefs.6")); //$NON-NLS-1$
         }
         if (name.indexOf("//") >= 0) { //$NON-NLS-1$
             // prefs.7=Name cannot contains consecutive '/'\!
-            throw new IllegalArgumentException(
-                    Messages.getString("prefs.7"));  //$NON-NLS-1$
+            throw new IllegalArgumentException(Messages.getString("prefs.7")); //$NON-NLS-1$
         }
     }
 
     private AbstractPreferences nodeImpl(String path, boolean createNew)
             throws BackingStoreException {
-        StringTokenizer st = new StringTokenizer(path, "/"); //$NON-NLS-1$
+        String[] names = path.split("/");//$NON-NLS-1$
         AbstractPreferences currentNode = this;
         AbstractPreferences temp = null;
-        while (st.hasMoreTokens() && null != currentNode) {
-            String name = st.nextToken();
-            synchronized (currentNode.lock) {
-                temp = currentNode.cachedNode.get(name);
-                if (temp == null) {
-                    temp = getNodeFromBackend(createNew, currentNode, name);
+        if (null != currentNode) {
+            for (int i = 0; i < names.length; i++) {
+                String name = names[i];
+                synchronized (currentNode.lock) {
+                    temp = currentNode.cachedNode.get(name);
+                    if (temp == null) {
+                        temp = getNodeFromBackend(createNew, currentNode, name);
+                    }
+                }
+                currentNode = temp;
+                if (null == currentNode) {
+                    break;
                 }
             }
-
-            currentNode = temp;
         }
         return currentNode;
     }
@@ -626,12 +595,12 @@
     private AbstractPreferences getNodeFromBackend(boolean createNew,
             AbstractPreferences currentNode, String name)
             throws BackingStoreException {
-        AbstractPreferences temp;
         if (name.length() > MAX_NAME_LENGTH) {
             // prefs.8=Name length is too long: {0}
-            throw new IllegalArgumentException(Messages.getString("prefs.8",  //$NON-NLS-1$
+            throw new IllegalArgumentException(Messages.getString("prefs.8", //$NON-NLS-1$
                     name));
         }
+        AbstractPreferences temp;
         if (createNew) {
             temp = currentNode.childSpi(name);
             currentNode.cachedNode.put(name, temp);
@@ -646,6 +615,9 @@
 
     @Override
     public boolean nodeExists(String name) throws BackingStoreException {
+        if (null == name) {
+            throw new NullPointerException();
+        }
         AbstractPreferences startNode = null;
         synchronized (lock) {
             if (isRemoved()) {
@@ -771,10 +743,11 @@
                     cachedNode.put(childrenNames[i], child);
                 }
             }
-            AbstractPreferences[] children = cachedNode
-                    .values().toArray(new AbstractPreferences[0]);
-            for (int i = 0; i < children.length; i++) {
-                children[i].removeNodeImpl();
+            
+            final Collection<AbstractPreferences> values = cachedNode.values();
+            final AbstractPreferences[] children = values.toArray(new AbstractPreferences[values.size()]);
+            for (AbstractPreferences child : children) {
+                child.removeNodeImpl();
             }
             removeNodeSpi();
             isRemoved = true;
diff --git a/libcore/prefs/src/main/java/java/util/prefs/BackingStoreException.java b/libcore/prefs/src/main/java/java/util/prefs/BackingStoreException.java
index e8a805c..553d7ab 100644
--- a/libcore/prefs/src/main/java/java/util/prefs/BackingStoreException.java
+++ b/libcore/prefs/src/main/java/java/util/prefs/BackingStoreException.java
@@ -17,40 +17,35 @@
 
 package java.util.prefs;
 
-
 /**
  * An exception to indicate that an error was encountered while accessing the
  * backing store.
- * 
- * @since Android 1.0
+ *
+ * @since 1.4
  */
 public class BackingStoreException extends Exception {
-    
+
     private static final long serialVersionUID = 859796500401108469L;
-    
+
     /**
-     * Constructs a new {@code BackingStoreException} instance with a detailed exception
-     * message.
+     * Constructs a new {@code BackingStoreException} instance with a detailed
+     * exception message.
      * 
      * @param s
      *            the detailed exception message.
-     * @since Android 1.0
      */
     public BackingStoreException (String s) {
         super(s);
     }
 
     /**
-     * Constructs a new {@code BackingStoreException} instance with a nested {@code Throwable}.
-     * 
+     * Constructs a new {@code BackingStoreException} instance with a nested
+     * {@code Throwable}.
+     *
      * @param t
      *            the nested {@code Throwable}.
-     * @since Android 1.0
      */
     public BackingStoreException (Throwable t) {
         super(t);
     }
 }
-
-
-
diff --git a/libcore/prefs/src/main/java/java/util/prefs/FilePreferencesFactoryImpl.java b/libcore/prefs/src/main/java/java/util/prefs/FilePreferencesFactoryImpl.java
index cc68e62..69eaa01 100644
--- a/libcore/prefs/src/main/java/java/util/prefs/FilePreferencesFactoryImpl.java
+++ b/libcore/prefs/src/main/java/java/util/prefs/FilePreferencesFactoryImpl.java
@@ -17,10 +17,10 @@
 package java.util.prefs;
 
 /**
- * The default implementation of <code>PreferencesFactory</code> for the Linux 
+ * The default implementation of <code>PreferencesFactory</code> for the Linux
  * platform, using the file system as its back end.
- * 
- * @since Android 1.0
+ *
+ * @since 1.4
  */
 class FilePreferencesFactoryImpl implements PreferencesFactory {
     //  user root preferences
diff --git a/libcore/prefs/src/main/java/java/util/prefs/FilePreferencesImpl.java b/libcore/prefs/src/main/java/java/util/prefs/FilePreferencesImpl.java
index cf85fa0..f6e5e8f 100644
--- a/libcore/prefs/src/main/java/java/util/prefs/FilePreferencesImpl.java
+++ b/libcore/prefs/src/main/java/java/util/prefs/FilePreferencesImpl.java
@@ -28,12 +28,12 @@
 import org.apache.harmony.prefs.internal.nls.Messages;
 
 /**
- * The default implementation of <code>AbstractPreferences</code> for the Linux platform,
- * using the file system as its back end.
- * 
+ * The default implementation of <code>AbstractPreferences</code> for the Linux
+ * platform, using the file system as its back end.
+ *
  * TODO some sync mechanism with backend, Performance - check file edit date
- * 
- * @since Android 1.0
+ *
+ * @since 1.4
  */
 class FilePreferencesImpl extends AbstractPreferences {
 
@@ -64,7 +64,6 @@
                 SYSTEM_HOME = System.getProperty("java.home") + "/.systemPrefs";//$NON-NLS-1$//$NON-NLS-2$
                 return null;
             }
-
         });
     }
 
@@ -97,9 +96,9 @@
      * Constructors
      * --------------------------------------------------------------
      */
-    
+
     /**
-     * Construct root <code>FilePreferencesImpl</code> instance, construct 
+     * Construct root <code>FilePreferencesImpl</code> instance, construct
      * user root if userNode is true, system root otherwise
      */
     FilePreferencesImpl(boolean userNode) {
@@ -108,9 +107,9 @@
         path = userNode ? USER_HOME : SYSTEM_HOME;
         initPrefs();
     }
-    
+
     /**
-     * Construct a prefs using given parent and given name 
+     * Construct a prefs using given parent and given name
      */
     private FilePreferencesImpl(AbstractPreferences parent, String name) {
         super(parent, name);
@@ -132,16 +131,16 @@
     @Override
     protected String[] childrenNamesSpi() throws BackingStoreException {
         String[] names = AccessController
-                .doPrivileged(new PrivilegedAction<String[]>() {
-                    public String[] run() {
-                        return dir.list(new FilenameFilter() {
-                            public boolean accept(File parent, String name) {
-                                return new File(path + File.separator + name).isDirectory(); 
-                            }
-                        });
-
+        .doPrivileged(new PrivilegedAction<String[]>() {
+            public String[] run() {
+                return dir.list(new FilenameFilter() {
+                    public boolean accept(File parent, String name) {
+                        return new File(path + File.separator + name).isDirectory();
                     }
                 });
+
+            }
+        });
         if (null == names) {// file is not a directory, exception case
             // prefs.3=Cannot get children names for {0}!
             throw new BackingStoreException(
@@ -192,14 +191,16 @@
                 prefs = XMLParser.loadFilePrefs(prefsFile);
             }
             return prefs.getProperty(key);
-        } catch (Exception e) {// if Exception happened, return null
+        } catch (Exception e) {
+            // if Exception happened, return null
             return null;
         }
     }
 
     @Override
     protected String[] keysSpi() throws BackingStoreException {
-        return prefs.keySet().toArray(new String[0]);
+        final Set<Object> ks = prefs.keySet();
+        return ks.toArray(new String[ks.size()]);
     }
 
     @Override
diff --git a/libcore/prefs/src/main/java/java/util/prefs/InvalidPreferencesFormatException.java b/libcore/prefs/src/main/java/java/util/prefs/InvalidPreferencesFormatException.java
index b31b3a1..ba8940b 100644
--- a/libcore/prefs/src/main/java/java/util/prefs/InvalidPreferencesFormatException.java
+++ b/libcore/prefs/src/main/java/java/util/prefs/InvalidPreferencesFormatException.java
@@ -21,51 +21,43 @@
  * An exception to indicate that the input XML file is not well-formed or could
  * not be validated against the appropriate document type (specified by
  * in the {@code Preferences}).
- * 
- * @since Android 1.0
  */
 public class InvalidPreferencesFormatException extends Exception {
-    
+
     private static final long serialVersionUID = -791715184232119669L;
-    
+
     /**
-     * Constructs a new {@code InvalidPreferencesFormatException} instance with a
-     * detailed exception message.
+     * Constructs a new {@code InvalidPreferencesFormatException} instance with
+     * a detailed exception message.
      * 
      * @param s
      *            the detailed exception message.
-     * @since Android 1.0
      */
     public InvalidPreferencesFormatException (String s) {
         super(s);
     }
 
     /**
-     * Constructs a new {@code InvalidPreferencesFormatException} instance with a
-     * detailed exception message and a nested {@code Throwable}.
+     * Constructs a new {@code InvalidPreferencesFormatException} instance with
+     * a detailed exception message and a nested {@code Throwable}.
      * 
      * @param s
      *            the detailed exception message.
      * @param t
      *            the nested {@code Throwable}.
-     * @since Android 1.0
      */
     public InvalidPreferencesFormatException (String s, Throwable t) {
         super(s,t);
     }
 
     /**
-     * Constructs a new {@code InvalidPreferencesFormatException} instance with a nested
-     * {@code Throwable}.
-     * 
+     * Constructs a new {@code InvalidPreferencesFormatException} instance with
+     * a nested {@code Throwable}.
+     *
      * @param t
      *            the nested {@code Throwable}.
-     * @since Android 1.0
      */
     public InvalidPreferencesFormatException (Throwable t) {
         super(t);
     }
 }
-
-
-
diff --git a/libcore/prefs/src/main/java/java/util/prefs/NodeChangeEvent.java b/libcore/prefs/src/main/java/java/util/prefs/NodeChangeEvent.java
index e9824bc..3e23f5a 100644
--- a/libcore/prefs/src/main/java/java/util/prefs/NodeChangeEvent.java
+++ b/libcore/prefs/src/main/java/java/util/prefs/NodeChangeEvent.java
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-
 package java.util.prefs;
 
 import java.io.Serializable;
@@ -28,19 +27,22 @@
  * This is the event class to indicate that one child of the preference node has
  * been added or deleted.
  * <p>
- * Please note that the serialization functionality has not yet been implemented, so
- * the serialization methods do nothing but throw a {@code NotSerializableException}.
- * </p>
+ * Please note that although the class is marked as {@code Serializable} by
+ * inheritance from {@code EventObject}, this type is not intended to be serialized
+ * so the serialization methods do nothing but throw a {@code NotSerializableException}.
  * 
- * @since Android 1.0
+ * @see java.util.prefs.Preferences
+ * @see java.util.prefs.NodeChangeListener
+ * 
+ * @since 1.4
  */
 public class NodeChangeEvent extends EventObject implements Serializable {
-    
+
     private static final long serialVersionUID = 8068949086596572957L;
-    
+
     private final Preferences parent;
     private final Preferences child;
-    
+
     /**
      * Constructs a new {@code NodeChangeEvent} instance.
      * 
@@ -49,43 +51,40 @@
      *            considered as the event source.
      * @param c
      *            the child {@code Preferences} instance that was added or deleted.
-     * @since Android 1.0
      */
     public NodeChangeEvent (Preferences p, Preferences c) {
         super(p);
         parent = p;
         child = c;
     }
-    
+
     /**
      * Gets the {@code Preferences} instance that fired this event.
      * 
      * @return the {@code Preferences} instance that fired this event.
-     * @since Android 1.0
      */
     public Preferences getParent() {
         return parent;
     }
-    
+
     /**
      * Gets the child {@code Preferences} node that was added or removed.
      * 
      * @return the added or removed child {@code Preferences} node.
-     * @since Android 1.0
      */
     public Preferences getChild() {
         return child;
     }
-    
-    /*
+
+    /**
      * This method always throws a <code>NotSerializableException</code>,
      * because this object cannot be serialized,
      */
     private void writeObject (ObjectOutputStream out) throws IOException {
         throw new NotSerializableException();
     }
-    
-    /*
+
+    /**
      * This method always throws a <code>NotSerializableException</code>,
      * because this object cannot be serialized,
      */
@@ -93,7 +92,3 @@
         throw new NotSerializableException();
     }
 }
-
-
-
- 
diff --git a/libcore/prefs/src/main/java/java/util/prefs/NodeChangeListener.java b/libcore/prefs/src/main/java/java/util/prefs/NodeChangeListener.java
index f16b206..41da23e 100644
--- a/libcore/prefs/src/main/java/java/util/prefs/NodeChangeListener.java
+++ b/libcore/prefs/src/main/java/java/util/prefs/NodeChangeListener.java
@@ -14,41 +14,36 @@
  * limitations under the License.
  */
 
-
 package java.util.prefs;
 
 import java.util.EventListener;
 import java.util.prefs.NodeChangeEvent;
 
 /**
- * This interface is used to handle preference node change events.
- * The implementation of this interface can be installed by the {@code Preferences} instance.
+ * This interface is used to handle preference node change events. The
+ * implementation of this interface can be installed by the {@code Preferences}
+ * instance.
  * 
+ * @see Preferences
  * @see NodeChangeEvent
  * 
- * @since Android 1.0
+ * @since 1.4
  */
 public interface NodeChangeListener extends EventListener {
-
     /**
      * This method gets called whenever a child node is added to another node.
      * 
      * @param e
      *            the node change event.
-     * @since Android 1.0
      */
     public void childAdded (NodeChangeEvent e);
-    
+
     /**
      * This method gets called whenever a child node is removed from another
      * node.
      * 
      * @param e
      *            the node change event.
-     * @since Android 1.0
      */
     public void childRemoved (NodeChangeEvent e);
 }
-
-
- 
diff --git a/libcore/prefs/src/main/java/java/util/prefs/PreferenceChangeEvent.java b/libcore/prefs/src/main/java/java/util/prefs/PreferenceChangeEvent.java
index f0f0787..d355f4e 100644
--- a/libcore/prefs/src/main/java/java/util/prefs/PreferenceChangeEvent.java
+++ b/libcore/prefs/src/main/java/java/util/prefs/PreferenceChangeEvent.java
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-
 package java.util.prefs;
 
 import java.io.IOException;
@@ -28,16 +27,19 @@
  * This is the event class to indicate that a preference has been added, deleted
  * or updated.
  * <p>
- * Please note that the serialization functionality has not yet been implemented, so
- * the serialization methods do nothing but throw a {@code NotSerializableException}.
- * </p>
+ * Please note that although the class is marked as {@code Serializable} by
+ * inheritance from {@code EventObject}, this type is not intended to be serialized
+ * so the serialization methods do nothing but throw a {@code NotSerializableException}.
  * 
- * @since Android 1.0
+ * @see java.util.prefs.Preferences
+ * @see java.util.prefs.PreferenceChangeListener
+ * 
+ * @since 1.4
  */
 public class PreferenceChangeEvent extends EventObject implements Serializable {
 
     private static final long serialVersionUID = 793724513368024975L;
-    
+
     private final Preferences node;
 
     private final String key;
@@ -55,7 +57,6 @@
      * @param v
      *            the new value of the changed preference, this value can be
      *            {@code null}, which means the preference has been removed.
-     * @since Android 1.0
      */
     public PreferenceChangeEvent(Preferences p, String k, String v) {
         super(p);
@@ -68,7 +69,6 @@
      * Gets the key of the changed preference.
      * 
      * @return the changed preference's key.
-     * @since Android 1.0
      */
     public String getKey() {
         return key;
@@ -78,9 +78,8 @@
      * Gets the new value of the changed preference or {@code null} if the
      * preference has been removed.
      * 
-     * @return the new value of the changed preference or null if the preference
-     *         has been removed.
-     * @since Android 1.0
+     * @return the new value of the changed preference or {@code null} if the
+     *         preference has been removed.
      */
     public String getNewValue() {
         return value;
@@ -90,13 +89,12 @@
      * Gets the {@code Preferences} instance that fired this event.
      * 
      * @return the {@code Preferences} instance that fired this event.
-     * @since Android 1.0
      */
     public Preferences getNode() {
         return node;
     }
 
-    /*
+    /**
      * This method always throws a <code>NotSerializableException</code>,
      * because this object cannot be serialized,
      */
@@ -104,7 +102,7 @@
         throw new NotSerializableException();
     }
 
-    /*
+    /**
      * This method always throws a <code>NotSerializableException</code>,
      * because this object cannot be serialized,
      */
@@ -112,5 +110,3 @@
         throw new NotSerializableException();
     }
 }
-
-
diff --git a/libcore/prefs/src/main/java/java/util/prefs/PreferenceChangeListener.java b/libcore/prefs/src/main/java/java/util/prefs/PreferenceChangeListener.java
index 28bb763..97aeced 100644
--- a/libcore/prefs/src/main/java/java/util/prefs/PreferenceChangeListener.java
+++ b/libcore/prefs/src/main/java/java/util/prefs/PreferenceChangeListener.java
@@ -14,21 +14,23 @@
  * limitations under the License.
  */
 
-
 package java.util.prefs;
 
 import java.util.EventListener;
 
 /**
- * This interface is used to handle preferences change events. The implementation of
- * this interface can be installed by the {@code Preferences} instance.
+ * This interface is used to handle preferences change events. The
+ * implementation of this interface can be installed by the {@code Preferences}
+ * instance.
  * 
+ * @see Preferences
  * @see PreferenceChangeEvent
+ *
  * 
- * @since Android 1.0
+ * @since 1.4
  */
 public interface PreferenceChangeListener extends EventListener {
-    
+
     /**
      * This method gets invoked whenever a preference is added, deleted or
      * updated.
@@ -36,10 +38,6 @@
      * @param pce
      *            the event instance which describes the changed {@code Preferences}
      *            instance and the preference value.
-     * @since Android 1.0
      */
     void preferenceChange (PreferenceChangeEvent pce);
 }
-
-
- 
diff --git a/libcore/prefs/src/main/java/java/util/prefs/Preferences.java b/libcore/prefs/src/main/java/java/util/prefs/Preferences.java
index 719c89a..8b961e4 100644
--- a/libcore/prefs/src/main/java/java/util/prefs/Preferences.java
+++ b/libcore/prefs/src/main/java/java/util/prefs/Preferences.java
@@ -30,89 +30,83 @@
 import java.net.MalformedURLException;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.Locale;
 
 import org.apache.harmony.prefs.internal.nls.Messages;
 
 /**
- * An instance of the class {@code Preferences} represents one node in a preference tree,
- * which provides a mechanism to store and access configuration data in a
- * hierarchical way. Two hierarchy trees are maintained, one for system
- * preferences shared by all users and the other for user preferences 
+ * An instance of the class {@code Preferences} represents one node in a
+ * preference tree, which provides a mechanism to store and access configuration
+ * data in a hierarchical way. Two hierarchy trees are maintained, one for
+ * system preferences shared by all users and the other for user preferences
  * specific to the user. {@code Preferences} hierarchy trees and data are stored
  * in an implementation-dependent back-end.
  * <p>
- * Every node has one name and one unique absolute path following the same 
- * notational conventions as directories in a file system. The root node's 
- * name is "", and other node name strings cannot contain the slash character 
- * and cannot be empty. The root node's absolute path is "/", and all other 
- * nodes' absolute paths are constructed in the standard way: &lt;parent's absolute
- * path&gt; + "/" + &lt;node's name&gt;. Since the set of nodes forms a tree with 
- * the root node at its base, all absolute paths start with the slash character.
- * Every node has one relative path to each of its ancestors. The relative path
- * doesn't start with slash: it equals the node's absolute path with leading 
- * substring removed corresponding to the ancestor's absolute path and a slash.
- * </p>
+ * Every node has one name and one unique absolute path following the same
+ * notational conventions as directories in a file system. The root node's
+ * name is "", and other node name strings cannot contain the slash character
+ * and cannot be empty. The root node's absolute path is "/", and all other
+ * nodes' absolute paths are constructed in the standard way: &lt;parent's
+ * absolute path&gt; + "/" + &lt;node's name&gt;. Since the set of nodes forms a
+ * tree with the root node at its base, all absolute paths start with the slash
+ * character. Every node has one relative path to each of its ancestors. The
+ * relative path doesn't start with slash: it equals the node's absolute path
+ * with leading substring removed corresponding to the ancestor's absolute path
+ * and a slash.
  * <p>
- * Modification to preferences data may be asynchronous, which means that 
- * preference update method calls may return immediately instead of blocking. 
- * The {@code flush()} and {@code sync()} methods force the back-end to 
- * synchronously perform all pending updates, but the implementation is 
- * permitted to perform the modifications on the underlying back-end data 
- * at any time between the moment the request is made and the moment the 
- * {@code flush()} or {@code sync()} method returns.
- * Please note that if JVM exit normally, the implementation must assure all
- * modifications are persisted implicitly.
- * </p>
+ * Modification to preferences data may be asynchronous, which means that
+ * preference update method calls may return immediately instead of blocking.
+ * The {@code flush()} and {@code sync()} methods force the back-end to
+ * synchronously perform all pending updates, but the implementation is
+ * permitted to perform the modifications on the underlying back-end data
+ * at any time between the moment the request is made and the moment the
+ * {@code flush()} or {@code sync()} method returns. Please note that if the JVM
+ * exits normally, the implementation must assure all modifications are
+ * persisted implicitly.
  * <p>
- * When invoking a method that retrieves preferences, the user must provide 
- * a default value. The default value is returned when the preferences cannot 
- * be found or the back-end is unavailable. Some other methods will throw 
+ * When invoking a method that retrieves preferences, the user must provide
+ * a default value. The default value is returned when the preferences cannot
+ * be found or the back-end is unavailable. Some other methods will throw
  * {@code BackingStoreException} when the back-end is unavailable.
  * </p>
  * <p>
- * Preferences can be exported to and imported from an XML files.
+ * Preferences can be exported to and imported from an XML files. These
+ * documents must have an XML DOCTYPE declaration:
+ * <pre>{@code
+ * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
+ * }</pre>
+ * This system URI is not really accessed by network, it is only a
+ * identification string. Visit the DTD location to see the actual format
+ * permitted.
  * <p>
  * There must be a concrete {@code PreferencesFactory} type for every concrete
- * {@code Preferences} type developed. Every J2SE implementation must provide a default
- * implementation for every supported platform, and must also provide a means of
- * replacing the default implementation. This implementation uses the system property
- * {@code java.util.prefs.PreferencesFactory} to detemine which preferences 
- * implementation to use.
- * </p>
+ * {@code Preferences} type developed. Every J2SE implementation must provide a
+ * default implementation for every supported platform, and must also provide a
+ * means of replacing the default implementation. This implementation uses the
+ * system property {@code java.util.prefs.PreferencesFactory} to detemine which
+ * preferences implementation to use.
  * <p>
- * The methods of this class are thread-safe. If multiple JVMs are using the same
- * back-end concurrently, the back-end won't be corrupted, but no other
+ * The methods of this class are thread-safe. If multiple JVMs are using the
+ * same back-end concurrently, the back-end won't be corrupted, but no other
  * behavior guarantees are made.
- * </p>
+ *
+ * @see PreferencesFactory
  * 
- * @since Android 1.0
+ * @since 1.4
  */
 public abstract class Preferences {
-    
-    /*
-     * ---------------------------------------------------------
-     * Class fields 
-     * ---------------------------------------------------------
-     */
-    
     /**
      * Maximum size in characters allowed for a preferences key.
-     * 
-     * @since Android 1.0
      */
     public static final int MAX_KEY_LENGTH = 80;
-    
+
     /**
      * Maximum size in characters allowed for a preferences name.
-     * 
-     * @since Android 1.0
      */
     public static final int MAX_NAME_LENGTH = 80;
-    
+
     /**
      * Maximum size in characters allowed for a preferences value.
-     * 
-     * @since Android 1.0
      */
     public static final int MAX_VALUE_LENGTH = 8192;
 
@@ -137,36 +131,53 @@
 
     //permission
     private static final RuntimePermission PREFS_PERM = new RuntimePermission("preferences"); //$NON-NLS-1$
-    
+
     //factory used to get user/system prefs root
     private static final PreferencesFactory factory;
-    
-    /**
-     * ---------------------------------------------------------
-     * Class initializer
-     * ---------------------------------------------------------
-     */        
-    static{
+
+    // BEGIN android-removed
+    // // default provider factory name for Windows
+    // private static final String DEFAULT_FACTORY_NAME_WIN = "java.util.prefs.RegistryPreferencesFactoryImpl"; //$NON-NLS-1$
+    //
+    // // default provider factory name for Unix
+    // private static final String DEFAULT_FACTORY_NAME_UNIX = "java.util.prefs.FilePreferencesFactoryImpl"; //$NON-NLS-1$
+    // END android-removed
+
+    static {
         String factoryClassName = AccessController.doPrivileged(new PrivilegedAction<String>() {
             public String run() {
                 return System.getProperty("java.util.prefs.PreferencesFactory"); //$NON-NLS-1$
             }
         });
         // BEGIN android-removed
-        // if(factoryClassName != null) {
+        // // set default provider
+        // if (factoryClassName == null) {
+        //     String osName = AccessController.doPrivileged(new PrivilegedAction<String>() {
+        //         public String run() {
+        //             return System.getProperty("os.name"); //$NON-NLS-1$
+        //         }
+        //     });
+        //
+        //     // only comparing ASCII, so assume english locale
+        //     osName = (osName == null ? null : osName.toLowerCase(Locale.ENGLISH));
+        //
+        //     if (osName != null && osName.startsWith("windows")) {
+        //         factoryClassName = DEFAULT_FACTORY_NAME_WIN;
+        //     } else {
+        //         factoryClassName = DEFAULT_FACTORY_NAME_UNIX;
+        //     }
+        // }
         // try {
-        // ClassLoader loader = Thread.currentThread().getContextClassLoader();
-        // if(loader == null){
-        // loader = ClassLoader.getSystemClassLoader();
-        // }
-        // Class<?> factoryClass = loader.loadClass(factoryClassName);
-        // factory = (PreferencesFactory) factoryClass.newInstance();
+        //     ClassLoader loader = Thread.currentThread().getContextClassLoader();
+        //     if(loader == null){
+        //         loader = ClassLoader.getSystemClassLoader();
+        //     }
+        //     Class<?> factoryClass = loader.loadClass(factoryClassName);
+        //     factory = (PreferencesFactory) factoryClass.newInstance();
         // } catch (Exception e) {
-        // // prefs.10=Cannot initiate PreferencesFactory: {0}. Caused by {1}
-        //         throw new InternalError(Messages.getString("prefs.10", factoryClassName, e));   //$NON-NLS-1$
+        //     // prefs.10=Cannot initiate PreferencesFactory: {0}. Caused by {1}
+        //     throw new InternalError(Messages.getString("prefs.10", factoryClassName, e));   //$NON-NLS-1$
         // }
-        // }
-        // END android-removed
         // BEGIN android-added
         ClassLoader loader = Thread.currentThread().getContextClassLoader();
         if (loader == null) {
@@ -182,10 +193,8 @@
                     try {
                         InputStream is = en.nextElement().openStream();
                         // Read each line for charset provider class names
-                        // BEGIN android-modified
                         reader = new BufferedReader(new InputStreamReader(is,
                                 CONFIGURATION_FILE_ENCODING), 8192);
-                        // END android-modified
                         factoryClassName = reader.readLine();
                         commentIndex = factoryClassName.indexOf(CONFIGURATION_FILE_COMMENT);
                         if (commentIndex > 0) {
@@ -215,42 +224,27 @@
             factory = (PreferencesFactory)c.newInstance();
         } catch (Exception e) {
             // prefs.10=Cannot initiate PreferencesFactory: {0}. Caused by {1}
-            throw new InternalError(Messages.getString("prefs.10", factoryClassName, e)); //$NON-NLS-1$  
+            throw new InternalError(Messages.getString("prefs.10", factoryClassName, e)); //$NON-NLS-1$
         }
         // END android-added
     }
-    
-    /*
-     * ---------------------------------------------------------
-     * Constructors
-     * ---------------------------------------------------------
-     */
-    
+
     /**
      * Default constructor, for use by subclasses only.
-     * 
-     * @since Android 1.0
      */
     protected Preferences() {
         super();
     }
-    
-    /*
-     * ---------------------------------------------------------
-     * Methods
-     * ---------------------------------------------------------
-     */
-    
+
     /**
      * Gets the absolute path string of this preference node.
      * 
      * @return the preference node's absolute path string.
-     * @since Android 1.0
      */
     public abstract String absolutePath();
-    
+
     /**
-     * Returns the names of all children of this node or an empty string if this
+     * Returns the names of all children of this node or an empty array if this
      * node has no children.
      * 
      * @return the names of all children of this node.
@@ -259,10 +253,9 @@
      *             failure.
      * @throws IllegalStateException
      *             if this node has been removed.
-     * @since Android 1.0
      */
     public abstract String[] childrenNames() throws BackingStoreException;
-    
+
     /**
      * Removes all preferences of this node.
      * 
@@ -271,13 +264,12 @@
      *             failure.
      * @throws IllegalStateException
      *             if this node has been removed.
-     * @since Android 1.0
      */
     public abstract void clear() throws BackingStoreException;
-    
+
     /**
-     * Exports all of the preferences of this node to a XML document using the given
-     * output stream.
+     * Exports all of the preferences of this node to a XML document using the
+     * given output stream.
      * <p>
      * This XML document uses the UTF-8 encoding and is written according to the
      * DTD in its DOCTYPE declaration, which is the following:
@@ -286,7 +278,8 @@
      * &lt;!DOCTYPE preferences SYSTEM &quot;http://java.sun.com/dtd/preferences.dtd&quot;&gt;
      * </pre>
      * 
-     * <i>Please note that (unlike the methods of this class that don't concern serialization), this call is not thread-safe.</i>
+     * <i>Please note that (unlike the methods of this class that don't concern
+     * serialization), this call is not thread-safe.</i>
      * </p>
      * 
      * @param ostream
@@ -298,13 +291,12 @@
      *             failure.
      * @throws IllegalStateException
      *             if this node has been removed.
-     * @since Android 1.0
      */
-    public abstract void exportNode (OutputStream ostream) throws IOException, BackingStoreException;
-    
+    public abstract void exportNode(OutputStream ostream) throws IOException, BackingStoreException;
+
     /**
-     * Exports all of the preferences of this node and all its descendants to a XML
-     * document using the given output stream.
+     * Exports all of the preferences of this node and all its descendants to a
+     * XML document using the given output stream.
      * <p>
      * This XML document uses the UTF-8 encoding and is written according to the
      * DTD in its DOCTYPE declaration, which is the following:
@@ -313,7 +305,8 @@
      * &lt;!DOCTYPE preferences SYSTEM &quot;http://java.sun.com/dtd/preferences.dtd&quot;&gt;
      * </pre>
      * 
-     * <i>Please note that (unlike the methods of this class that don't concern serialization), this call is not thread-safe.</i>
+     * <i>Please note that (unlike the methods of this class that don't concern
+     * serialization), this call is not thread-safe.</i>
      * </p>
      * 
      * @param ostream
@@ -325,12 +318,12 @@
      *             failure.
      * @throws IllegalStateException
      *             if this node has been removed.
-     * @since Android 1.0
      */
-    public abstract void exportSubtree (OutputStream ostream) throws IOException, BackingStoreException;
-    
+    public abstract void exportSubtree(OutputStream ostream) throws IOException,
+            BackingStoreException;
+
     /**
-     * Forces all pending updates to this node and its descendants to be 
+     * Forces all pending updates to this node and its descendants to be
      * persisted in the backing store.
      * <p>
      * If this node has been removed, the invocation of this method only flushes
@@ -340,13 +333,12 @@
      * @throws BackingStoreException
      *             if the backing store is unavailable or causes an operation
      *             failure.
-     * @since Android 1.0
      */
     public abstract void flush() throws BackingStoreException;
-    
+
     /**
-     * Gets the {@code String} value mapped to the given key or its default value if no
-     * value is mapped or no backing store is available.
+     * Gets the {@code String} value mapped to the given key or its default
+     * value if no value is mapped or no backing store is available.
      * <p>
      * Some implementations may store default values in backing stores. In this
      * case, if there is no value mapped to the given key, the stored default
@@ -363,16 +355,16 @@
      *             if this node has been removed.
      * @throws NullPointerException
      *             if the parameter {@code key} is {@code null}.
-     * @since Android 1.0
      */
-    public abstract String get (String key, String deflt);
-    
+    public abstract String get(String key, String deflt);
+
     /**
-     * Gets the {@code boolean} value mapped to the given key or its default value if no
-     * value is mapped, if the backing store is unavailable, or if the value is invalid.
+     * Gets the {@code boolean} value mapped to the given key or its default
+     * value if no value is mapped, if the backing store is unavailable, or if
+     * the value is invalid.
      * <p>
-     * The only valid values are the {@code String} "true", which represents {@code true} and
-     * "false", which represents {@code false}, ignoring case.
+     * The only valid values are the {@code String} "true", which represents
+     * {@code true} and "false", which represents {@code false}, ignoring case.
      * </p>
      * <p>
      * Some implementations may store default values in backing stores. In this
@@ -384,25 +376,24 @@
      *            the preference key.
      * @param deflt
      *            the default value, which will be returned if no value is
-     *            mapped to the given key, if the backing store is unavailable, or if the
-     *            value is invalid.
+     *            mapped to the given key, if the backing store is unavailable,
+     *            or if the value is invalid.
      * @return the boolean value mapped to the given key.
      * @throws IllegalStateException
      *             if this node has been removed.
      * @throws NullPointerException
      *             if the parameter {@code key} is {@code null}.
-     * @since Android 1.0
      */
-    public abstract boolean getBoolean (String key, boolean deflt);
-    
+    public abstract boolean getBoolean(String key, boolean deflt);
+
     /**
-     * Gets the {@code byte} array value mapped to the given key or its default value if
-     * no value is mapped, if the backing store is unavailable, or if the value is an
-     * invalid string.
+     * Gets the {@code byte} array value mapped to the given key or its default
+     * value if no value is mapped, if the backing store is unavailable, or if
+     * the value is an invalid string.
      * <p>
-     * To be valid, the value string must be Base64-encoded binary data. The Base64 encoding
-     * is as defined in <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC
-     * 2045</a>, section 6.8.
+     * To be valid, the value string must be Base64-encoded binary data. The
+     * Base64 encoding is as defined in <a
+     * href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>, section 6.8.
      * </p>
      * <p>
      * Some implementations may store default values in backing stores. In this
@@ -414,25 +405,24 @@
      *            the preference key.
      * @param deflt
      *            the default value, which will be returned if no value is
-     *            mapped to the given key, if the backing store is unavailable, or if the
-     *            value is invalid.
+     *            mapped to the given key, if the backing store is unavailable,
+     *            or if the value is invalid.
      * @return the byte array value mapped to the given key.
      * @throws IllegalStateException
      *             if this node has been removed.
      * @throws NullPointerException
      *             if the parameter {@code key} is {@code null}.
-     * @since Android 1.0
      */
-    public abstract byte[] getByteArray (String key, byte[] deflt);
-    
+    public abstract byte[] getByteArray(String key, byte[] deflt);
+
     /**
-     * Gets the {@code double} value mapped to the given key or its default value if no
-     * value is mapped, if the backing store is unavailable, or if the value is an invalid
-     * string.
+     * Gets the {@code double} value mapped to the given key or its default
+     * value if no value is mapped, if the backing store is unavailable, or if
+     * the value is an invalid string.
      * <p>
-     * To be valid, the value string must be a string that can be converted to a {@code double} by
-     * {@link Double#parseDouble(String) Double.parseDouble(String)}.
-     * </p>
+     * To be valid, the value string must be a string that can be converted to a
+     * {@code double} by {@link Double#parseDouble(String)
+     * Double.parseDouble(String)}.
      * <p>
      * Some implementations may store default values in backing stores. In this
      * case, if there is no value mapped to the given key, the stored default
@@ -450,17 +440,17 @@
      *             if this node has been removed.
      * @throws NullPointerException
      *             if the parameter {@code key} is {@code null}.
-     * @since Android 1.0
      */
-    public abstract double getDouble (String key, double deflt);
-    
+    public abstract double getDouble(String key, double deflt);
+
     /**
-     * Gets the {@code float} value mapped to the given key or its default value if no
-     * value is mapped, if the backing store is unavailable, or if the value is an invalid
-     * string.
+     * Gets the {@code float} value mapped to the given key or its default value
+     * if no value is mapped, if the backing store is unavailable, or if the
+     * value is an invalid string.
      * <p>
-     * To be valid, the value string must be a string that can be converted to a {@code float} by
-     * {@link Float#parseFloat(String) Float.parseFloat(String)}.
+     * To be valid, the value string must be a string that can be converted to a
+     * {@code float} by {@link Float#parseFloat(String)
+     * Float.parseFloat(String)}.
      * </p>
      * <p>
      * Some implementations may store default values in backing stores. In this
@@ -479,17 +469,17 @@
      *             if this node has been removed.
      * @throws NullPointerException
      *             if the parameter {@code key} is {@code null}.
-     * @since Android 1.0
      */
-    public abstract float getFloat (String key, float deflt);
-    
+    public abstract float getFloat(String key, float deflt);
+
     /**
-     * Gets the {@code int} value mapped to the given key or its default value if no
-     * value is mapped, if the backing store is unavailable, or if the value is an invalid
-     * string.
+     * Gets the {@code int} value mapped to the given key or its default value
+     * if no value is mapped, if the backing store is unavailable, or if the
+     * value is an invalid string.
      * <p>
-     * To be valid, the value string must be a string that can be converted to an {@code int} by
-     * {@link Integer#parseInt(String) Integer.parseInt(String)}.
+     * To be valid, the value string must be a string that can be converted to
+     * an {@code int} by {@link Integer#parseInt(String)
+     * Integer.parseInt(String)}.
      * </p>
      * <p>
      * Some implementations may store default values in backing stores. In this
@@ -501,24 +491,23 @@
      *            the preference key.
      * @param deflt
      *            the default value, which will be returned if no value is
-     *            mapped to the given key, if the backing store is unavailable, or if the
-     *            value is invalid.
+     *            mapped to the given key, if the backing store is unavailable,
+     *            or if the value is invalid.
      * @return the integer value mapped to the given key.
      * @throws IllegalStateException
      *             if this node has been removed.
      * @throws NullPointerException
      *             if the parameter {@code key} is {@code null}.
-     * @since Android 1.0
      */
-    public abstract int getInt (String key, int deflt);
-    
+    public abstract int getInt(String key, int deflt);
+
     /**
-     * Gets the {@code long} value mapped to the given key or its default value if no
-     * value is mapped, if the backing store is unavailable, or if the value is an invalid
-     * string.
+     * Gets the {@code long} value mapped to the given key or its default value
+     * if no value is mapped, if the backing store is unavailable, or if the
+     * value is an invalid string.
      * <p>
-     * To be valid, the value string must be a string that can be converted to a {@code long} by
-     * {@link Long#parseLong(String) Long.parseLong(String)}.
+     * To be valid, the value string must be a string that can be converted to a
+     * {@code long} by {@link Long#parseLong(String) Long.parseLong(String)}.
      * </p>
      * <p>
      * Some implementations may store default values in backing stores. In this
@@ -530,29 +519,29 @@
      *            the preference key.
      * @param deflt
      *            the default value, which will be returned if no value is
-     *            mapped to the given key, if the backing store is unavailable, or if the
-     *            value is invalid.
+     *            mapped to the given key, if the backing store is unavailable,
+     *            or if the value is invalid.
      * @return the long value mapped to the given key.
      * @throws IllegalStateException
      *             if this node has been removed.
      * @throws NullPointerException
      *             if the parameter {@code key} is {@code null}.
-     * @since Android 1.0
      */
-    public abstract long getLong (String key, long deflt);
-    
+    public abstract long getLong(String key, long deflt);
+
     /**
      * Imports all the preferences from an XML document using the given input
      * stream.
      * <p>
-     * This XML document uses the UTF-8 encoding and must be written according to the
-     * DTD in its DOCTYPE declaration, which must be the following:
+     * This XML document uses the UTF-8 encoding and must be written according
+     * to the DTD in its DOCTYPE declaration, which must be the following:
      * 
      * <pre>
      * &lt;!DOCTYPE preferences SYSTEM &quot;http://java.sun.com/dtd/preferences.dtd&quot;&gt;
      * </pre>
      * 
-     * <i>Please note that (unlike the methods of this class that don't concern serialization), this call is not thread-safe.</i>
+     * <i>Please note that (unlike the methods of this class that don't concern
+     * serialization), this call is not thread-safe.</i>
      * </p>
      * 
      * @param istream
@@ -565,7 +554,6 @@
      * @throws SecurityException
      *             if {@code RuntimePermission("preferences")} is denied by a
      *             SecurityManager.
-     * @since Android 1.0
      */
     public static void importPreferences (InputStream istream) throws InvalidPreferencesFormatException, IOException {
         checkSecurity();
@@ -575,16 +563,15 @@
         }
         XMLParser.importPrefs(istream);
     }
-    
+
     /**
      * Returns whether this is a user preference node.
      * 
      * @return {@code true}, if this is a user preference node, {@code false} if
      *         this is a system preference node.
-     * @since Android 1.0
      */
     public abstract boolean isUserNode();
-    
+
     /**
      * Returns all preference keys stored in this node or an empty array if no
      * key was found.
@@ -595,18 +582,16 @@
      *             failure.
      * @throws IllegalStateException
      *             if this node has been removed.
-     * @since Android 1.0
      */
     public abstract String[] keys() throws BackingStoreException;
-    
+
     /**
      * Returns the name of this node.
      * 
      * @return the name of this node.
-     * @since Android 1.0
      */
     public abstract String name();
-    
+
     /**
      * Returns the preference node with the given path name. The path name can
      * be relative or absolute. The requested node and its ancestors will
@@ -625,10 +610,9 @@
      *             if the path name is invalid.
      * @throws NullPointerException
      *             if the given path is {@code null}.
-     * @since Android 1.0
      */
-    public abstract Preferences node (String path);
-    
+    public abstract Preferences node(String path);
+
     /**
      * Returns whether the preference node with the given path name exists. The
      * path is treated as relative to this node if it doesn't start with a slash,
@@ -653,10 +637,9 @@
      * @throws BackingStoreException
      *             if the backing store is unavailable or causes an operation
      *             failure.
-     * @since Android 1.0
      */
-    public abstract boolean nodeExists (String path) throws BackingStoreException;
-    
+    public abstract boolean nodeExists(String path) throws BackingStoreException;
+
     /**
      * Returns the parent preference node of this node or {@code null} if this
      * node is the root node.
@@ -664,10 +647,9 @@
      * @return the parent preference node of this node.
      * @throws IllegalStateException
      *             if this node has been removed.
-     * @since Android 1.0
      */
     public abstract Preferences parent();
-    
+
     /**
      * Adds a new preference to this node using the given key and value or
      * updates the value if a preference with the given key already exists.
@@ -684,14 +666,13 @@
      *             MAX_VALUE_LENGTH}.
      * @throws IllegalStateException
      *             if this node has been removed.
-     * @since Android 1.0
      */
-    public abstract void put (String key, String value);
-    
+    public abstract void put(String key, String value);
+
     /**
-     * Adds a new preference with a {@code boolean} value to this node using the given
-     * key and value or updates the value if a preference with the given key
-     * already exists.
+     * Adds a new preference with a {@code boolean} value to this node using the
+     * given key and value or updates the value if a preference with the given
+     * key already exists.
      * 
      * @param key
      *            the preference key to be added or updated.
@@ -704,10 +685,9 @@
      *             MAX_KEY_LENGTH}.
      * @throws IllegalStateException
      *             if this node has been removed.
-     * @since Android 1.0
      */
-    public abstract void putBoolean (String key, boolean value);
-    
+    public abstract void putBoolean(String key, boolean value);
+
     /**
      * Adds a new preference to this node using the given key and the string
      * form of the given value or updates the value if a preference with the
@@ -730,10 +710,9 @@
      *             quarters of {@code MAX_KEY_LENGTH}.
      * @throws IllegalStateException
      *             if this node has been removed.
-     * @since Android 1.0
      */
-    public abstract void putByteArray (String key, byte[] value);
-    
+    public abstract void putByteArray(String key, byte[] value);
+
     /**
      * Adds a new preference to this node using the given key and {@code double}
      * value or updates the value if a preference with the
@@ -754,12 +733,11 @@
      *             MAX_KEY_LENGTH}.
      * @throws IllegalStateException
      *             if this node has been removed.
-     * @since Android 1.0
      */
-    public abstract void putDouble (String key, double value);
-    
+    public abstract void putDouble(String key, double value);
+
     /**
-     * Adds a new preference to this node using the given key and {@code float} 
+     * Adds a new preference to this node using the given key and {@code float}
      * value or updates the value if a preference with the
      * given key already exists.
      * <p>
@@ -778,12 +756,11 @@
      *             MAX_KEY_LENGTH}.
      * @throws IllegalStateException
      *             if this node has been removed.
-     * @since Android 1.0
      */
-    public abstract void putFloat (String key, float value);
-    
+    public abstract void putFloat(String key, float value);
+
     /**
-     * Adds a new preference to this node using the given key and {@code int} 
+     * Adds a new preference to this node using the given key and {@code int}
      * value or updates the value if a preference with the
      * given key already exists.
      * <p>
@@ -802,12 +779,11 @@
      *             MAX_KEY_LENGTH}.
      * @throws IllegalStateException
      *             if this node has been removed.
-     * @since Android 1.0
      */
-    public abstract void putInt (String key, int value);
-    
+    public abstract void putInt(String key, int value);
+
     /**
-     * Adds a new preference to this node using the given key and {@code long} 
+     * Adds a new preference to this node using the given key and {@code long}
      * value or updates the value if a preference with the
      * given key already exists.
      * <p>
@@ -826,9 +802,8 @@
      *             MAX_KEY_LENGTH}.
      * @throws IllegalStateException
      *             if this node has been removed.
-     * @since Android 1.0
      */
-    public abstract void putLong (String key, long value);
+    public abstract void putLong(String key, long value);
 
     /**
      * Removes the preference mapped to the given key from this node.
@@ -839,13 +814,12 @@
      *             if the given key is {@code null}.
      * @throws IllegalStateException
      *             if this node has been removed.
-     * @since Android 1.0
      */
-    public abstract void remove (String key);
-    
+    public abstract void remove(String key);
+
     /**
-     * Removes this preference node with all its descendants. The removal 
-     * won't necessarily be persisted until the method {@code flush()} is invoked.
+     * Removes this preference node with all its descendants. The removal won't
+     * necessarily be persisted until the method {@code flush()} is invoked.
      * 
      * @throws BackingStoreException
      *             if the backing store is unavailable or causes an operation
@@ -854,14 +828,13 @@
      *             if this node has been removed.
      * @throws UnsupportedOperationException
      *             if this is a root node.
-     * @since Android 1.0
      */
     public abstract void removeNode() throws BackingStoreException;
-    
+
     /**
-     * Registers a {@code NodeChangeListener} instance for this node, which will handle
-     * {@code NodeChangeEvent}s. {@code NodeChangeEvent}s will be fired when a child node has
-     * been added to or removed from this node.
+     * Registers a {@code NodeChangeListener} instance for this node, which will
+     * handle {@code NodeChangeEvent}s. {@code NodeChangeEvent}s will be fired
+     * when a child node has been added to or removed from this node.
      * 
      * @param ncl
      *            the listener to be registered.
@@ -869,25 +842,24 @@
      *             if the given listener is {@code null}.
      * @throws IllegalStateException
      *             if this node has been removed.
-     * @since Android 1.0
      */
-    public abstract void addNodeChangeListener (NodeChangeListener ncl);
-    
+    public abstract void addNodeChangeListener(NodeChangeListener ncl);
+
     /**
-     * Registers a {@code PreferenceChangeListener} instance for this node, which will
-     * handle {@code PreferenceChangeEvent}s. {@code PreferenceChangeEvent}s will be fired when
-     * a preference has been added to, removed from, or updated for this node.
-     * 
+     * Registers a {@code PreferenceChangeListener} instance for this node,
+     * which will handle {@code PreferenceChangeEvent}s. {@code
+     * PreferenceChangeEvent}s will be fired when a preference has been added
+     * to, removed from, or updated for this node.
+     *
      * @param pcl
      *            the listener to be registered.
      * @throws NullPointerException
      *             if the given listener is {@code null}.
      * @throws IllegalStateException
      *             if this node has been removed.
-     * @since Android 1.0
      */
     public abstract void addPreferenceChangeListener (PreferenceChangeListener pcl);
-    
+
     /**
      * Removes the given {@code NodeChangeListener} instance from this node.
      * 
@@ -897,12 +869,12 @@
      *             if the given listener is {@code null}.
      * @throws IllegalStateException
      *             if this node has been removed.
-     * @since Android 1.0
      */
     public abstract void removeNodeChangeListener (NodeChangeListener ncl);
-    
+
     /**
-     * Removes the given {@code PreferenceChangeListener} instance from this node.
+     * Removes the given {@code PreferenceChangeListener} instance from this
+     * node.
      * 
      * @param pcl
      *            the listener to be removed.
@@ -910,36 +882,34 @@
      *             if the given listener is {@code null}.
      * @throws IllegalStateException
      *             if this node has been removed.
-     * @since Android 1.0
      */
     public abstract void removePreferenceChangeListener (PreferenceChangeListener pcl);
-    
+
     /**
      * Synchronizes the data of this preference node and its descendants with
-     * the back-end preference store. Any changes found in the back-end data should be reflected
-     * in this node and its descendants, and at the same time any local changes to this node and
-     * descendants should be persisted.
+     * the back-end preference store. Any changes found in the back-end data
+     * should be reflected in this node and its descendants, and at the same
+     * time any local changes to this node and descendants should be persisted.
      * 
      * @throws BackingStoreException
      *             if the backing store is unavailable or causes an operation
      *             failure.
      * @throws IllegalStateException
      *             if this node has been removed.
-     * @since Android 1.0
      */
     public abstract void sync() throws BackingStoreException;
-    
+
     /**
      * Returns the system preference node for the package of the given class.
      * The absolute path of the returned node is one slash followed by the given
      * class's full package name, replacing each period character ('.') with
-     * a slash. For example, the absolute path of the preference associated with 
+     * a slash. For example, the absolute path of the preference associated with
      * the class Object would be "/java/lang". As a special case, the unnamed
      * package is associated with a preference node "/&lt;unnamed&gt;". This
      * method will create the node and its ancestors as needed. Any nodes created
-     * by this method won't necessarily be persisted until the method {@code flush()} is
-     * invoked.
-     * 
+     * by this method won't necessarily be persisted until the method {@code
+     * flush()} is invoked.
+     *
      * @param c
      *            the given class.
      * @return the system preference node for the package of the given class.
@@ -948,13 +918,12 @@
      * @throws SecurityException
      *             if the {@code RuntimePermission("preferences")} is denied by
      *             a SecurityManager.
-     * @since Android 1.0
      */
     public static Preferences systemNodeForPackage (Class<?> c) {
         checkSecurity();
         return factory.systemRoot().node(getNodeName(c));
     }
-    
+
     /**
      * Returns the root node of the system preference hierarchy.
      * 
@@ -962,33 +931,32 @@
      * @throws SecurityException
      *             if the {@code RuntimePermission("preferences")} is denied by
      *             a SecurityManager.
-     * @since Android 1.0
      */
     public static Preferences systemRoot() {
         checkSecurity();
         return factory.systemRoot();
     }
-    
+
     //check the RuntimePermission("preferences")
     private static void checkSecurity() {
         SecurityManager manager = System.getSecurityManager();
         if(null != manager){
             manager.checkPermission(PREFS_PERM);
         }
-        
+
     }
 
     /**
      * Returns the user preference node for the package of the given class.
      * The absolute path of the returned node is one slash followed by the given
      * class's full package name, replacing each period character ('.') with
-     * a slash. For example, the absolute path of the preference associated with 
+     * a slash. For example, the absolute path of the preference associated with
      * the class Object would be "/java/lang". As a special case, the unnamed
      * package is associated with a preference node "/&lt;unnamed&gt;". This
      * method will create the node and its ancestors as needed. Any nodes created
-     * by this method won't necessarily be persisted until the method {@code flush()} is
-     * invoked.
-     * 
+     * by this method won't necessarily be persisted until the method {@code
+     * flush()} is invoked.
+     *
      * @param c
      *            the given class.
      * @return the user preference node for the package of the given class.
@@ -997,13 +965,12 @@
      * @throws SecurityException
      *             if the {@code RuntimePermission("preferences")} is denied by
      *             a SecurityManager.
-     * @since Android 1.0
      */
     public static Preferences userNodeForPackage (Class<?> c) {
         checkSecurity();
         return factory.userRoot().node(getNodeName(c));
     }
-    
+
     //parse node's absolute path from class instance
     private static String getNodeName(Class<?> c){
         Package p = c.getPackage();
@@ -1020,7 +987,6 @@
      * @throws SecurityException
      *             if the {@code RuntimePermission("preferences")} is denied by
      *             a SecurityManager.
-     * @since Android 1.0
      */
     public static Preferences userRoot() {
         checkSecurity();
@@ -1032,7 +998,6 @@
      * Preference Node: " followed by this node's absolute path.
      * 
      * @return the string representation of this node.
-     * @since Android 1.0
      */
     @Override
     public abstract String toString();
diff --git a/libcore/prefs/src/main/java/java/util/prefs/PreferencesFactory.java b/libcore/prefs/src/main/java/java/util/prefs/PreferencesFactory.java
index e56dd95..3ac13e4 100644
--- a/libcore/prefs/src/main/java/java/util/prefs/PreferencesFactory.java
+++ b/libcore/prefs/src/main/java/java/util/prefs/PreferencesFactory.java
@@ -14,36 +14,30 @@
  * limitations under the License.
  */
 
-
 package java.util.prefs;
 
 /**
  * This interface is used by the {@link Preferences} class as factory class to
- * create {@code Preferences} instances. This interface can be implemented and installed
- * to replace the default preferences implementation.
+ * create {@code Preferences} instances. This interface can be implemented and
+ * installed to replace the default preferences implementation.
  * 
- * @since Android 1.0
+ * @see java.util.prefs.Preferences
+ * 
+ * @since 1.4
  */
 public interface PreferencesFactory {
-
     /**
      * Returns the root node of the preferences hierarchy for the calling user
      * context.
      * 
      * @return the user preferences hierarchy root node.
-     * @since Android 1.0
      */
     Preferences userRoot();
-    
+
     /**
      * Returns the root node of the system preferences hierarchy.
      * 
      * @return the system preferences hierarchy root node.
-     * @since Android 1.0
      */
     Preferences systemRoot();
 }
-
-
-
- 
diff --git a/libcore/prefs/src/main/java/java/util/prefs/XMLParser.java b/libcore/prefs/src/main/java/java/util/prefs/XMLParser.java
index 2edfc71..c5a234c 100644
--- a/libcore/prefs/src/main/java/java/util/prefs/XMLParser.java
+++ b/libcore/prefs/src/main/java/java/util/prefs/XMLParser.java
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-
 package java.util.prefs;
 
 import java.io.BufferedInputStream;
@@ -27,6 +26,7 @@
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.StringReader;
+import java.io.Writer;
 import java.nio.channels.FileChannel;
 import java.nio.channels.FileLock;
 import java.security.AccessController;
@@ -64,9 +64,7 @@
 // END android-added
 
 /**
- * Utility class for importing and exporting {@code Preferences} data from an XML file.
- * 
- * @since Android 1.0
+ * Utility class for the Preferences import/export from XML file.
  */
 class XMLParser {
 
@@ -79,15 +77,15 @@
      * Constant - the DTD string
      */
     static final String PREFS_DTD = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" //$NON-NLS-1$
-            + "    <!ELEMENT preferences (root)>" //$NON-NLS-1$
-            + "    <!ATTLIST preferences EXTERNAL_XML_VERSION CDATA \"0.0\" >" //$NON-NLS-1$
-            + "    <!ELEMENT root (map, node*) >" //$NON-NLS-1$
-            + "    <!ATTLIST root type (system|user) #REQUIRED >" //$NON-NLS-1$
-            + "    <!ELEMENT node (map, node*) >" //$NON-NLS-1$
-            + "    <!ATTLIST node name CDATA #REQUIRED >" //$NON-NLS-1$
-            + "    <!ELEMENT map (entry*) >" //$NON-NLS-1$
-            + "    <!ELEMENT entry EMPTY >" //$NON-NLS-1$
-            + "    <!ATTLIST entry key   CDATA #REQUIRED value CDATA #REQUIRED >"; //$NON-NLS-1$
+        + "    <!ELEMENT preferences (root)>" //$NON-NLS-1$
+        + "    <!ATTLIST preferences EXTERNAL_XML_VERSION CDATA \"0.0\" >" //$NON-NLS-1$
+        + "    <!ELEMENT root (map, node*) >" //$NON-NLS-1$
+        + "    <!ATTLIST root type (system|user) #REQUIRED >" //$NON-NLS-1$
+        + "    <!ELEMENT node (map, node*) >" //$NON-NLS-1$
+        + "    <!ATTLIST node name CDATA #REQUIRED >" //$NON-NLS-1$
+        + "    <!ELEMENT map (entry*) >" //$NON-NLS-1$
+        + "    <!ELEMENT entry EMPTY >" //$NON-NLS-1$
+        + "    <!ATTLIST entry key   CDATA #REQUIRED value CDATA #REQUIRED >"; //$NON-NLS-1$
 
     /*
      * Constant - the specified header
@@ -103,24 +101,24 @@
      * empty string array constant
      */
     private static final String[] EMPTY_SARRAY = new String[0];
-    
+
     /*
-     * Constant - used by FilePreferencesImpl, which is default implementation of Linux platform 
+     * Constant - used by FilePreferencesImpl, which is default implementation of Linux platform
      */
     private static final String FILE_PREFS = "<!DOCTYPE map SYSTEM 'http://java.sun.com/dtd/preferences.dtd'>"; //$NON-NLS-1$
 
     /*
      * Constant - specify the DTD version
      */
-    private static final float XML_VERSION = 1.0f;    
-    
+    private static final float XML_VERSION = 1.0f;
+
     /*
      * DOM builder
      */
     private static final DocumentBuilder builder;
 
     /*
-     * specify the indent level 
+     * specify the indent level
      */
     private static int indent = -1;
 
@@ -139,7 +137,7 @@
         }
         builder.setEntityResolver(new EntityResolver() {
             public InputSource resolveEntity(String publicId, String systemId)
-                    throws SAXException, IOException {
+            throws SAXException, IOException {
                 if (systemId.equals(PREFS_DTD_NAME)) {
                     InputSource result = new InputSource(new StringReader(
                             PREFS_DTD));
@@ -196,7 +194,7 @@
         flushEmptyElement("map", out); //$NON-NLS-1$
 
         StringTokenizer ancestors = new StringTokenizer(prefs.absolutePath(),
-                "/"); //$NON-NLS-1$
+        "/"); //$NON-NLS-1$
         exportNode(ancestors, prefs, withSubTree, out);
 
         flushEndTag("root", out); //$NON-NLS-1$
@@ -207,7 +205,7 @@
 
     private static void exportNode(StringTokenizer ancestors,
             Preferences prefs, boolean withSubTree, BufferedWriter out)
-            throws IOException, BackingStoreException {
+    throws IOException, BackingStoreException {
         if (ancestors.hasMoreTokens()) {
             String name = ancestors.nextToken();
             flushStartTag(
@@ -226,7 +224,7 @@
     }
 
     private static void exportSubTree(Preferences prefs, BufferedWriter out)
-            throws BackingStoreException, IOException {
+    throws BackingStoreException, IOException {
         String[] names = prefs.childrenNames();
         if (names.length > 0) {
             for (int i = 0; i < names.length; i++) {
@@ -241,7 +239,7 @@
     }
 
     private static void exportEntries(Preferences prefs, BufferedWriter out)
-            throws BackingStoreException, IOException {
+    throws BackingStoreException, IOException {
         String[] keys = prefs.keys();
         String[] values = new String[keys.length];
         for (int i = 0; i < keys.length; i++) {
@@ -267,7 +265,7 @@
     }
 
     private static void flushEndTag(String tagName, BufferedWriter out)
-            throws IOException {
+    throws IOException {
         flushIndent(indent--, out);
         out.write("</"); //$NON-NLS-1$
         out.write(tagName);
@@ -276,7 +274,7 @@
     }
 
     private static void flushEmptyElement(String tagName, BufferedWriter out)
-            throws IOException {
+    throws IOException {
         flushIndent(++indent, out);
         out.write("<"); //$NON-NLS-1$
         out.write(tagName);
@@ -308,7 +306,7 @@
     }
 
     private static void flushIndent(int ind, BufferedWriter out)
-            throws IOException {
+    throws IOException {
         for (int i = 0; i < ind; i++) {
             out.write("  "); //$NON-NLS-1$
         }
@@ -325,7 +323,7 @@
     }
 
     private static void flushStartTag(String tagName, BufferedWriter out)
-            throws IOException {
+    throws IOException {
         flushIndent(++indent, out);
         out.write("<"); //$NON-NLS-1$
         out.write(tagName);
@@ -365,7 +363,7 @@
      * utilities for Preferences import
      **************************************************************************/
     static void importPrefs(InputStream in) throws IOException,
-            InvalidPreferencesFormatException {
+    InvalidPreferencesFormatException {
         try {
             // load XML document
             Document doc = builder.parse(new InputSource(in));
@@ -382,7 +380,7 @@
 
             // check preferences root's type
             Element root = (Element) preferences
-                    .getElementsByTagName("root").item(0); //$NON-NLS-1$
+            .getElementsByTagName("root").item(0); //$NON-NLS-1$
             Preferences prefsRoot = null;
             String type = root.getAttribute("type"); //$NON-NLS-1$
             if (type.equals("user")) { //$NON-NLS-1$
@@ -445,15 +443,15 @@
     // TODO dirty implementation of a method from javax.xml.xpath
     // should be replaced with a call to a good impl of this method
     private static NodeList selectNodeList(Element documentElement, String string) {
-        
+
         NodeList result = null;
-                
+
         ArrayList<Node> input = new ArrayList<Node>();
-        
+
         String[] path = string.split("/");
-        
+
         NodeList childNodes = documentElement.getChildNodes();
-        
+
         if(path[0].equals("entry") || path[0].equals("node")) {
             for(int i = 0; i < childNodes.getLength(); i++) {
                 Object next = childNodes.item(i);
@@ -483,21 +481,21 @@
                 }
             }
         }
-        
+
         result = new NodeSet(input.iterator());
-        
+
         return result;
     }
     // END android-added
-    
+
     /***************************************************************************
      * utilities for FilePreferencesImpl, which is default implementation of Linux platform
      **************************************************************************/
     /**
      * load preferences from file, if cannot load, create a new one FIXME: need
      * lock or not?
-     * 
-     * @param file  the XML file to be read
+     *
+     * @param file	the XML file to be read
      * @return Properties instance which indicates the preferences key-value pairs
      */
     static Properties loadFilePrefs(final File file) {
@@ -506,14 +504,6 @@
                 return loadFilePrefsImpl(file);
             }
         });
-
-        // try {
-        // //FIXME: lines below can be deleted, because it is not required to
-        // persistent at the very beginning
-        // flushFilePrefs(file, result);
-        // } catch (IOException e) {
-        // e.printStackTrace();
-        // }
     }
 
     static Properties loadFilePrefsImpl(final File file) {
@@ -524,7 +514,6 @@
             InputStream in = null;
             FileLock lock = null;
             try {
-
                 FileInputStream istream = new FileInputStream(file);
                 // BEGIN android-modified
                 in = new BufferedInputStream(istream, 8192);
@@ -544,17 +533,16 @@
                     result.setProperty(key, value);
                 }
                 return result;
-            } catch (Exception e) {
-                e.printStackTrace();
+            } catch (IOException e) {
+            } catch (SAXException e) {
+            // BEGIN android-removed
+            // } catch (TransformerException e) {
+            //     // transform shouldn't fail for xpath call
+            //     throw new AssertionError(e);
+            // END android-removed
             } finally {
-                try {
-                    lock.release();
-                } catch (Exception e) {//ignore
-                }
-                try {
-                    in.close();
-                } catch (Exception e) {//ignore
-                }
+                releaseQuietly(lock);
+                closeQuietly(in);
             }
         } else {
             file.delete();
@@ -563,7 +551,7 @@
     }
 
     /**
-     * 
+     *
      * @param file
      * @param prefs
      * @throws PrivilegedActionException
@@ -576,7 +564,7 @@
             }
         });
     }
-    
+
     static void flushFilePrefsImpl(File file, Properties prefs) throws IOException {
         BufferedWriter out = null;
         FileLock lock = null;
@@ -604,18 +592,35 @@
             }
             out.flush();
         } finally {
-            try {
-                lock.release();
-            } catch (Exception e) {//ignore
-            }
-            try {
-                if (null != out) {
-                    out.close();
-                }
-            } catch (Exception e) {//ignore
-            }
+            releaseQuietly(lock);
+            closeQuietly(out);
         }
     }
+
+    private static void releaseQuietly(FileLock lock) {
+        if (lock == null) {
+            return;
+        }
+        try {
+            lock.release();
+        } catch (IOException e) {}
+    }
+
+    private static void closeQuietly(Writer out) {
+        if (out == null) {
+            return;
+        }
+        try {
+            out.close();
+        } catch (IOException e) {}
+    }
+
+    private static void closeQuietly(InputStream in) {
+        if (in == null) {
+            return;
+        }
+        try {
+            in.close();
+        } catch (IOException e) {}
+    }
 }
-
-
diff --git a/libcore/prefs/src/main/java/org/apache/harmony/prefs/internal/nls/Messages.java b/libcore/prefs/src/main/java/org/apache/harmony/prefs/internal/nls/Messages.java
index cfc7236..aaf5d8d 100644
--- a/libcore/prefs/src/main/java/org/apache/harmony/prefs/internal/nls/Messages.java
+++ b/libcore/prefs/src/main/java/org/apache/harmony/prefs/internal/nls/Messages.java
@@ -43,7 +43,7 @@
  * is looked up, or resource bundle support is not available, the key itself
  * will be returned as the associated message. This means that the <em>KEY</em>
  * should a reasonable human-readable (english) string.
- * 
+ *
  */
 public class Messages {
 
@@ -54,7 +54,7 @@
 
     /**
      * Retrieves a message which has no arguments.
-     * 
+     *
      * @param msg
      *            String the key to look up.
      * @return String the message for that key in the system message bundle.
@@ -67,7 +67,7 @@
 
     /**
      * Retrieves a message which takes 1 argument.
-     * 
+     *
      * @param msg
      *            String the key to look up.
      * @param arg
@@ -80,7 +80,7 @@
 
     /**
      * Retrieves a message which takes 1 integer argument.
-     * 
+     *
      * @param msg
      *            String the key to look up.
      * @param arg
@@ -93,7 +93,7 @@
 
     /**
      * Retrieves a message which takes 1 character argument.
-     * 
+     *
      * @param msg
      *            String the key to look up.
      * @param arg
@@ -106,7 +106,7 @@
 
     /**
      * Retrieves a message which takes 2 arguments.
-     * 
+     *
      * @param msg
      *            String the key to look up.
      * @param arg1
@@ -121,7 +121,7 @@
 
     /**
      * Retrieves a message which takes several arguments.
-     * 
+     *
      * @param msg
      *            String the key to look up.
      * @param args
diff --git a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/AbstractPreferencesTest.java b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/AbstractPreferencesTest.java
index 418e52d..76ef4e7 100644
--- a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/AbstractPreferencesTest.java
+++ b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/AbstractPreferencesTest.java
@@ -35,9 +35,13 @@
 import java.util.prefs.PreferenceChangeListener;
 import java.util.prefs.Preferences;
 
+import tests.util.PrefsTester;
+
 @TestTargetClass(AbstractPreferences.class)
 public class AbstractPreferencesTest extends TestCase {
 
+    private final PrefsTester prefsTester = new PrefsTester();
+
     AbstractPreferences pref;
 
     static AbstractPreferences root;
@@ -51,13 +55,8 @@
     
     protected void setUp() throws Exception {
         super.setUp();
+        prefsTester.setUp();
 
-        System.setProperty("user.home", System.getProperty("java.io.tmpdir"));
-        System.setProperty("java.home", System.getProperty("java.io.tmpdir"));
-        
-        Preferences.systemRoot().clear();
-        Preferences.userRoot().clear();
-        
         root = (AbstractPreferences) Preferences.userRoot();
         parent = (AbstractPreferences) Preferences.userNodeForPackage(this.getClass());
 
@@ -65,11 +64,7 @@
     }
 
     protected void tearDown() throws Exception {
-        parent.removeNode();
-        Preferences.systemRoot().clear();
-        Preferences.userRoot().clear();
-        System.setProperty("user.home", oldUserHome);
-        System.setProperty("java.home", oldJavaHome);
+        prefsTester.tearDown();
         super.tearDown();
     }
 
@@ -855,6 +850,31 @@
     }
 
     @TestTargetNew(
+            level = TestLevel.PARTIAL_COMPLETE,
+            notes = "",
+            method = "nodeExists",
+            args = {String.class}
+    )
+    public void test_nodeExists() throws BackingStoreException {
+        AbstractPreferences test = (AbstractPreferences) Preferences.userRoot()
+                .node("test");
+        try {
+            test.nodeExists(null);
+            fail("should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+
+        test.removeNode();
+        try {
+            test.nodeExists(null);
+            fail("should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+    }
+
+    @TestTargetNew(
         level = TestLevel.COMPLETE,
         notes = "",
         method = "parent",
diff --git a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/FilePreferencesImplTest.java b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/FilePreferencesImplTest.java
index 0c61e75..0cb1975 100644
--- a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/FilePreferencesImplTest.java
+++ b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/FilePreferencesImplTest.java
@@ -28,28 +28,22 @@
 import java.util.prefs.Preferences;
 
 import junit.framework.TestCase;
+import tests.util.PrefsTester;
 
 @TestTargetClass(java.util.prefs.Preferences.class)
 public class FilePreferencesImplTest extends TestCase {
 
-    String oldUserHome = System.getProperty("user.home");
-    String oldJavaHome = System.getProperty("java.home");
+    private final PrefsTester prefsTester = new PrefsTester();
 
+    @Override
     protected void setUp() throws Exception {
         super.setUp();
-
-        System.setProperty("user.home", System.getProperty("java.io.tmpdir"));
-        System.setProperty("java.home", System.getProperty("java.io.tmpdir"));
-        Preferences.systemRoot().clear();
-        Preferences.userRoot().clear();
+        prefsTester.setUp();
     }
 
+    @Override
     protected void tearDown() throws Exception {
-        Preferences.systemRoot().clear();
-        Preferences.userRoot().clear();
-        System.setProperty("user.home", oldUserHome);
-        System.setProperty("java.home", oldJavaHome);
-
+        prefsTester.tearDown();
         super.tearDown();
     }
 
@@ -313,6 +307,7 @@
             System.setSecurityManager(dflt);
         }
 
+        @Override
         public void checkPermission(Permission perm) {
             if (perm instanceof FilePermission) {
                 throw new SecurityException();
@@ -321,6 +316,7 @@
             }
         }
 
+        @Override
         public void checkPermission(Permission perm, Object ctx) {
             if (perm instanceof FilePermission) {
                 System.out.println(perm.getActions());
diff --git a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/InvalidPreferencesFormatExceptionTest.java b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/InvalidPreferencesFormatExceptionTest.java
index 28c953e..c7ff946 100644
--- a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/InvalidPreferencesFormatExceptionTest.java
+++ b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/InvalidPreferencesFormatExceptionTest.java
@@ -44,7 +44,7 @@
     )
     public void testInvalidPreferencesFormatExceptionString() {
         InvalidPreferencesFormatException e = new InvalidPreferencesFormatException(
-                "msg");
+        "msg");
         assertNull(e.getCause());
         assertEquals("msg", e.getMessage());
     }
@@ -99,7 +99,7 @@
     public void testSerializationSelf() throws Exception {
 
         SerializationTest.verifySelf(new InvalidPreferencesFormatException(
-                "msg"));
+        "msg"));
     }
 
     /**
diff --git a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockAbstractPreferences.java b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockAbstractPreferences.java
index 1820954..b149225 100644
--- a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockAbstractPreferences.java
+++ b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockAbstractPreferences.java
@@ -84,6 +84,7 @@
         return lock;
     }
 
+    @Override
     public String[] childrenNamesSpi() throws BackingStoreException {
         checkException();
         if (result == returnNull)
@@ -108,6 +109,7 @@
         return childSpi(name);
     }
 
+    @Override
     public AbstractPreferences childSpi(String name) {
         try {
             checkException();
@@ -123,11 +125,13 @@
         return r;
     }
 
+    @Override
     public void flushSpi() throws BackingStoreException {
         checkException();
         flushedTimes++;
     }
 
+    @Override
     public String getSpi(String key) {
         try {
             checkException();
@@ -139,6 +143,7 @@
         return result == returnNull ? null : attr.getProperty(key);
     }
 
+    @Override
     public String[] keysSpi() throws BackingStoreException {
         checkException();
         Set<Object> keys = attr.keySet();
@@ -147,6 +152,7 @@
         return result == returnNull ? null : results;
     }
 
+    @Override
     public void putSpi(String name, String value) {
         try {
             checkException();
@@ -158,11 +164,13 @@
         attr.put(name, value);
     }
 
+    @Override
     protected void removeNodeSpi() throws BackingStoreException {
         checkException();
         ((MockAbstractPreferences) parent()).childs.remove(name());
     }
 
+    @Override
     public void removeSpi(String key) {
         try {
             checkException();
@@ -174,6 +182,7 @@
         attr.remove(key);
     }
 
+    @Override
     public void syncSpi() throws BackingStoreException {
         checkException();
         syncTimes++;
diff --git a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockSecurityManager.java b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockSecurityManager.java
index e5a0bfd..d6047fb 100644
--- a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockSecurityManager.java
+++ b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockSecurityManager.java
@@ -39,6 +39,7 @@
         System.setSecurityManager(dflt);
     }
 
+    @Override
     public void checkPermission(Permission perm) {
         if (perm instanceof RuntimePermission
                 && perm.getName().equals("preferences")) {
@@ -48,6 +49,7 @@
         }
     }
 
+    @Override
     public void checkPermission(Permission perm, Object ctx) {
         if (perm instanceof RuntimePermission
                 && perm.getName().equals("preferences")) {
diff --git a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeEventTest.java b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeEventTest.java
index eab3b14..1afd755 100644
--- a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeEventTest.java
+++ b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeEventTest.java
@@ -30,6 +30,7 @@
 import junit.framework.TestCase;
 
 import org.apache.harmony.testframework.serialization.SerializationTest;
+import tests.util.PrefsTester;
 
 /**
  * 
@@ -37,26 +38,17 @@
 @TestTargetClass(NodeChangeEvent.class)
 public class NodeChangeEventTest extends TestCase {
 
-    NodeChangeEvent event;
+    private final PrefsTester prefsTester = new PrefsTester();
 
-    String oldUserHome = System.getProperty("user.home");
-    String oldJavaHome = System.getProperty("java.home");
+    NodeChangeEvent event;
 
     protected void setUp() throws Exception {
         super.setUp();
-
-        System.setProperty("user.home", System.getProperty("java.io.tmpdir"));
-        System.setProperty("java.home", System.getProperty("java.io.tmpdir"));
-        Preferences.systemRoot().clear();
-        Preferences.userRoot().clear();
+        prefsTester.setUp();
     }
 
     protected void tearDown() throws Exception {
-        Preferences.systemRoot().clear();
-        Preferences.userRoot().clear();
-        System.setProperty("user.home", oldUserHome);
-        System.setProperty("java.home", oldJavaHome);
-
+        prefsTester.tearDown();
         super.tearDown();
     }
 
diff --git a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeListenerTest.java b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeListenerTest.java
index c5e3252..3cdb4d9 100644
--- a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeListenerTest.java
+++ b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeListenerTest.java
@@ -26,6 +26,7 @@
 import java.util.prefs.Preferences;
 
 import junit.framework.TestCase;
+import tests.util.PrefsTester;
 
 /**
  * 
@@ -33,20 +34,26 @@
 @TestTargetClass(NodeChangeListener.class)
 public class NodeChangeListenerTest extends TestCase {
 
+    private final PrefsTester prefsTester = new PrefsTester();
+
     NodeChangeListener l;
 
     /*
      * @see TestCase#setUp()
      */
+    @Override
     protected void setUp() throws Exception {
         super.setUp();
+        prefsTester.setUp();
         l = new NodeChangeListenerImpl();
     }
 
     /*
      * @see TestCase#tearDown()
      */
+    @Override
     protected void tearDown() throws Exception {
+        prefsTester.tearDown();
         super.tearDown();
     }
 
diff --git a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeEventTest.java b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeEventTest.java
index 4030b89..dda1f6c 100644
--- a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeEventTest.java
+++ b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeEventTest.java
@@ -92,7 +92,7 @@
     )
     public void testConstructor() {
         event = new PreferenceChangeEvent(Preferences.userRoot(), "key",
-                "value");
+        "value");
         assertEquals("key", event.getKey());
         assertEquals("value", event.getNewValue());
         assertSame(Preferences.userRoot(), event.getNode());
@@ -107,7 +107,7 @@
     )
     public void testSerialization() throws Exception {
         event = new PreferenceChangeEvent(Preferences.userRoot(), "key",
-                "value");
+        "value");
         try {
             SerializationTest.copySerializable(event);
             fail("No expected NotSerializableException");
diff --git a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeListenerTest.java b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeListenerTest.java
index e4df9c4..7080aa5 100644
--- a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeListenerTest.java
+++ b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeListenerTest.java
@@ -38,6 +38,7 @@
     /*
      * @see TestCase#setUp()
      */
+    @Override
     protected void setUp() throws Exception {
         super.setUp();
         l = new PreferenceChangeListenerImpl();
diff --git a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesFactoryTest.java b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesFactoryTest.java
index 818d5ad..729bc05 100644
--- a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesFactoryTest.java
+++ b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesFactoryTest.java
@@ -37,6 +37,7 @@
     /*
      * @see TestCase#setUp()
      */
+    @Override
     protected void setUp() throws Exception {
         super.setUp();
         f = new PreferencesFactoryImpl();
@@ -49,7 +50,7 @@
         args = {}
     )
     public void testUserRoot() {
-        f.userRoot();
+        assertNull(f.userRoot());
     }
 
     @TestTargetNew(
@@ -59,7 +60,7 @@
         args = {}
     )
     public void testSystemRoot() {
-        f.systemRoot();
+        assertNull(f.systemRoot());
     }
 
     public static class PreferencesFactoryImpl implements PreferencesFactory {
diff --git a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesTest.java b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesTest.java
index 0ebf6bb..c9c74fd 100644
--- a/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesTest.java
+++ b/libcore/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesTest.java
@@ -39,14 +39,15 @@
 import java.util.prefs.PreferenceChangeListener;
 import java.util.prefs.Preferences;
 
+import tests.util.PrefsTester;
+
 /**
  * 
  */
 @TestTargetClass(Preferences.class)
 public class PreferencesTest extends TestCase {
 
-    String oldUserHome = System.getProperty("user.home");
-    String oldJavaHome = System.getProperty("java.home");
+    private final PrefsTester prefsTester = new PrefsTester();
 
     MockSecurityManager manager = new MockSecurityManager();
 
@@ -74,43 +75,24 @@
     /*
      * @see TestCase#setUp()
      */
+    @Override
     protected void setUp() throws Exception {
         super.setUp();
         in = new ByteArrayInputStream(
                 "<!DOCTYPE preferences SYSTEM \"http://java.sun.com/dtd/preferences.dtd\"><preferences><root type=\"user\"><map></map></root></preferences>"
                         .getBytes("UTF-8"));
         stream = new MockInputStream(in);
-
-        System.setProperty("user.home", System.getProperty("java.io.tmpdir"));
-        System.setProperty("java.home", System.getProperty("java.io.tmpdir"));
-        Preferences.systemRoot().clear();
-        Preferences.userRoot().clear();
-
-        Preferences p = Preferences.userNodeForPackage(Preferences.class);
-        p.clear();
-        try {
-            p.removeNode();
-        } catch (BackingStoreException e) {
-        }
+        prefsTester.setUp();
     }
 
     /*
      * @see TestCase#tearDown()
      */
+    @Override
     protected void tearDown() throws Exception {
-        super.tearDown();
         stream.close();
-        Preferences p = Preferences.userNodeForPackage(Preferences.class);
-        p.clear();        
-        try {
-            p.removeNode();
-        } catch (BackingStoreException e) {
-        }
-
-        Preferences.systemRoot().clear();
-        Preferences.userRoot().clear();
-        System.setProperty("user.home", oldUserHome);
-        System.setProperty("java.home", oldJavaHome);
+        prefsTester.tearDown();
+        super.tearDown();
     }
 
     @TestTargetNew(
@@ -1830,6 +1812,7 @@
             wrapper = in;
         }
 
+        @Override
         public int read() throws IOException {
             checkException();
             return wrapper.read();
@@ -1843,136 +1826,170 @@
             super();
         }
 
+        @Override
         public String absolutePath() {
             return null;
         }
 
+        @Override
         public String[] childrenNames() throws BackingStoreException {
             return null;
         }
 
+        @Override
         public void clear() throws BackingStoreException {
         }
 
+        @Override
         public void exportNode(OutputStream ostream) throws IOException,
                 BackingStoreException {
         }
 
+        @Override
         public void exportSubtree(OutputStream ostream) throws IOException,
                 BackingStoreException {
         }
 
+        @Override
         public void flush() throws BackingStoreException {
         }
 
+        @Override
         public String get(String key, String deflt) {
             return null;
         }
 
+        @Override
         public boolean getBoolean(String key, boolean deflt) {
             return false;
         }
 
+        @Override
         public byte[] getByteArray(String key, byte[] deflt) {
             return null;
         }
 
+        @Override
         public double getDouble(String key, double deflt) {
             return 0;
         }
 
+        @Override
         public float getFloat(String key, float deflt) {
             return 0;
         }
 
+        @Override
         public int getInt(String key, int deflt) {
             return 0;
         }
 
+        @Override
         public long getLong(String key, long deflt) {
             return 0;
         }
 
+        @Override
         public boolean isUserNode() {
             return false;
         }
 
+        @Override
         public String[] keys() throws BackingStoreException {
             return null;
         }
 
+        @Override
         public String name() {
             return null;
         }
 
+        @Override
         public Preferences node(String name) {
             return null;
         }
 
+        @Override
         public boolean nodeExists(String name) throws BackingStoreException {
             return false;
         }
 
+        @Override
         public Preferences parent() {
             return null;
         }
 
+        @Override
         public void put(String key, String value) {
 
         }
 
+        @Override
         public void putBoolean(String key, boolean value) {
 
         }
 
+        @Override
         public void putByteArray(String key, byte[] value) {
 
         }
 
+        @Override
         public void putDouble(String key, double value) {
 
         }
 
+        @Override
         public void putFloat(String key, float value) {
 
         }
 
+        @Override
         public void putInt(String key, int value) {
 
         }
 
+        @Override
         public void putLong(String key, long value) {
 
         }
 
+        @Override
         public void remove(String key) {
 
         }
 
+        @Override
         public void removeNode() throws BackingStoreException {
 
         }
 
+        @Override
         public void addNodeChangeListener(NodeChangeListener ncl) {
 
         }
 
+        @Override
         public void addPreferenceChangeListener(PreferenceChangeListener pcl) {
 
         }
 
+        @Override
         public void removeNodeChangeListener(NodeChangeListener ncl) {
 
         }
 
+        @Override
         public void removePreferenceChangeListener(PreferenceChangeListener pcl) {
 
         }
 
+        @Override
         public void sync() throws BackingStoreException {
 
         }
 
+        @Override
         public String toString() {
             return null;
         }
diff --git a/libcore/prefs/src/test/java/tests/prefs/AllTests.java b/libcore/prefs/src/test/java/tests/prefs/AllTests.java
index 843d733..b3f2ed6 100644
--- a/libcore/prefs/src/test/java/tests/prefs/AllTests.java
+++ b/libcore/prefs/src/test/java/tests/prefs/AllTests.java
@@ -20,7 +20,8 @@
 import junit.framework.TestSuite;
 
 /**
- * Test suite that includes all tests for the Math project.
+ * Test suite that includes all tests for the Prefs project.
+ *
  */
 public class AllTests {
 
diff --git a/libcore/prefs/src/test/resources/prefs/java/util/prefs/preferences.dtd b/libcore/prefs/src/test/resources/prefs/java/util/prefs/preferences.dtd
deleted file mode 100644
index a116015..0000000
--- a/libcore/prefs/src/test/resources/prefs/java/util/prefs/preferences.dtd
+++ /dev/null
@@ -1,56 +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.
- -->
-
-<!-- DTD for a Preferences tree. -->
-
-<!-- The preferences element is at the root of an XML document
-     representing a Preferences tree. -->
-<!ELEMENT preferences (root)>
-
-<!-- The preferences element contains an optional version attribute,
-      which specifies version of DTD. -->
-<!ATTLIST preferences EXTERNAL_XML_VERSION CDATA "0.0" >  
-
-<!-- The root element has a map representing the root's preferences
-     (if any), and one node for each child of the root (if any). -->
-<!ELEMENT root (map, node*) >
-
-<!-- Additionally, the root contains a type attribute, which
-     specifies whether it's the system or user root. -->
-<!ATTLIST root
-          type (system|user) #REQUIRED >
-
-<!-- Each node has a map representing its preferences (if any),
-     and one node for each child (if any). -->
-
-<!ELEMENT node (map, node*) >
-
-<!-- Additionally, each node has a name attribute -->
-<!ATTLIST node
-          name CDATA #REQUIRED >
-
-<!-- A map represents the preferences stored at a node (if any). -->
-<!ELEMENT map (entry*) >
-
-<!-- An entry represents a single preference, which is simply
-      a key-value pair. -->
-<!ELEMENT entry EMPTY >
-<!ATTLIST entry
-          key   CDATA #REQUIRED
-          value CDATA #REQUIRED >
\ No newline at end of file
diff --git a/libcore/regex/src/main/java/java/util/regex/Pattern.java b/libcore/regex/src/main/java/java/util/regex/Pattern.java
index c058db8..2853bbe 100644
--- a/libcore/regex/src/main/java/java/util/regex/Pattern.java
+++ b/libcore/regex/src/main/java/java/util/regex/Pattern.java
@@ -356,28 +356,33 @@
     }
 
     /**
-     * Splits the given input sequence around occurrences of the {@code Pattern}.
-     * The function first determines all occurrences of the {@code Pattern}
-     * inside the input sequence. It then builds an array of the
-     * &quot;remaining&quot; strings before, in-between, and after these
-     * occurrences. An additional parameter determines the maximal number of
-     * entries in the resulting array and the handling of trailing empty
-     * strings.
+     * Splits the given input sequence at occurrences of this {@code Pattern}.
+     * 
+     * If this {@code Pattern} does not occur in the input, the result is an
+     * array containing the input (converted from a {@code CharSequence} to
+     * a {@code String}).
+     * 
+     * Otherwise, the {@code limit} parameter controls the contents of the
+     * returned array as described below.
      * 
      * @param inputSeq
      *            the input sequence.
      * @param limit
-     *            Determines the maximal number of entries in the resulting
-     *            array.
+     *            Determines the maximum number of entries in the resulting
+     *            array, and the treatment of trailing empty strings.
      *            <ul>
-     *            <li>For n &gt; 0, it is guaranteed that the resulting array
-     *            contains at most n entries.
+     *            <li>For n &gt; 0, the resulting array contains at most n
+     *            entries. If this is fewer than the number of matches, the
+     *            final entry will contain all remaining input.
      *            <li>For n &lt; 0, the length of the resulting array is
-     *            exactly the number of occurrences of the {@code Pattern} +1.
+     *            exactly the number of occurrences of the {@code Pattern}
+     *            plus one for the text after the final separator.
      *            All entries are included.
-     *            <li>For n == 0, the length of the resulting array is at most
-     *            the number of occurrences of the {@code Pattern} +1. Empty
-     *            strings at the end of the array are not included.
+     *            <li>For n == 0, the result is as for n &lt; 0, except
+     *            trailing empty strings will not be returned. (Note that
+     *            the case where the input is itself an empty string is
+     *            special, as described above, and the limit parameter does
+     *            not apply there.)
      *            </ul>
      * 
      * @return the resulting array.
@@ -385,6 +390,13 @@
      * @since Android 1.0
      */
     public String[] split(CharSequence inputSeq, int limit) {
+        if (inputSeq.length() == 0) {
+            // Unlike Perl, which considers the result of splitting the empty
+            // string to be the empty array, Java returns an array containing
+            // the empty string.
+            return new String[] { "" };
+        }
+        
         int maxLength = limit <= 0 ? Integer.MAX_VALUE : limit;
 
         String input = inputSeq.toString();
@@ -393,14 +405,10 @@
         Matcher matcher = new Matcher(this, inputSeq);
         int savedPos = 0;
         
-        // Add text preceding each occurrence, if enough space. Only do this for
-        // non-empty input sequences, because otherwise we'd add the "trailing
-        // empty string" twice.
-        if (inputSeq.length() != 0) {
-            while(matcher.find() && list.size() + 1 < maxLength) {
-                list.add(input.substring(savedPos, matcher.start()));
-                savedPos = matcher.end();
-            }
+        // Add text preceding each occurrence, if enough space.
+        while(matcher.find() && list.size() + 1 < maxLength) {
+            list.add(input.substring(savedPos, matcher.start()));
+            savedPos = matcher.end();
         }
         
         // Add trailing text if enough space.
@@ -412,11 +420,10 @@
             }
         }
         
-        // Remove trailing spaces, if limit == 0 is requested.
+        // Remove trailing empty matches in the limit == 0 case.
         if (limit == 0) {
             int i = list.size() - 1;
-            // Don't remove 1st element, since array must not be empty.
-            while(i > 0 && "".equals(list.get(i))) {
+            while (i >= 0 && "".equals(list.get(i))) {
                 list.remove(i);
                 i--;
             }
diff --git a/libcore/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/SplitTest.java b/libcore/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/SplitTest.java
index ea615c0..894dfff 100644
--- a/libcore/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/SplitTest.java
+++ b/libcore/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/SplitTest.java
@@ -32,12 +32,62 @@
         Pattern p = Pattern.compile("/");
         String[] results = p.split("have/you/done/it/right");
         String[] expected = new String[] { "have", "you", "done", "it", "right" };
-        assertEquals(expected.length, results.length);
-        for (int i = 0; i < expected.length; i++) {
-            assertEquals(results[i], expected[i]);
-        }
+        assertArraysEqual(expected, results);
     }
 
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.PARTIAL_COMPLETE,
+            notes = "Verifies the basic functionality of split with empty matches.",
+            method = "split",
+            args = {java.lang.CharSequence.class}
+        )
+    })
+    public void testEmptySplits() {
+        // Trailing empty matches are removed.
+        assertArraysEqual(new String[0], "hello".split("."));
+        assertArraysEqual(new String[] { "1", "2" }, "1:2:".split(":"));
+        // ...including when that results in an empty result.
+        assertArraysEqual(new String[0], ":".split(":"));
+        // ...but not when limit < 0.
+        assertArraysEqual(new String[] { "1", "2", "" }, "1:2:".split(":", -1));
+        
+        // Leading empty matches are retained.
+        assertArraysEqual(new String[] { "", "", "o" }, "hello".split(".."));
+        
+        // A separator that doesn't occur in the input gets you the input.
+        assertArraysEqual(new String[] { "hello" }, "hello".split("not-present-in-test"));
+        // ...including when the input is the empty string.
+        // (Perl returns an empty list instead.)
+        assertArraysEqual(new String[] { "" }, "".split("not-present-in-test"));
+        assertArraysEqual(new String[] { "" }, "".split("A?"));
+        
+        // The limit argument controls the size of the result.
+        // If l == 0, the result is as long as needed, except trailing empty matches are dropped.
+        // If l < 0, the result is as long as needed, and trailing empty matches are retained.
+        // If l > 0, the result contains the first l matches, plus one string containing the remaining input.
+        // Examples without a trailing separator (and hence without a trailing empty match):
+        assertArraysEqual(new String[] { "a", "b", "c" }, "a,b,c".split(",", 0));
+        assertArraysEqual(new String[] { "a,b,c" }, "a,b,c".split(",", 1));
+        assertArraysEqual(new String[] { "a", "b,c" }, "a,b,c".split(",", 2));
+        assertArraysEqual(new String[] { "a", "b", "c" }, "a,b,c".split(",", 3));
+        assertArraysEqual(new String[] { "a", "b", "c" }, "a,b,c".split(",", Integer.MAX_VALUE));
+        // Examples with a trailing separator (and hence possibly with a trailing empty match):
+        assertArraysEqual(new String[] { "a", "b", "c" }, "a,b,c,".split(",", 0));
+        assertArraysEqual(new String[] { "a,b,c," }, "a,b,c,".split(",", 1));
+        assertArraysEqual(new String[] { "a", "b,c," }, "a,b,c,".split(",", 2));
+        assertArraysEqual(new String[] { "a", "b", "c," }, "a,b,c,".split(",", 3));
+        assertArraysEqual(new String[] { "a", "b", "c", "" }, "a,b,c,".split(",", Integer.MAX_VALUE));
+        assertArraysEqual(new String[] { "a", "b", "c", "" }, "a,b,c,".split(",", -1));
+    }
+    
+    private void assertArraysEqual(String[] expected, String[] actual) {
+        assertEquals(expected.length, actual.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals(Integer.toString(i), expected[i], actual[i]);
+        }
+    }
+    
     @TestTargetNew(
         level = TestLevel.PARTIAL_COMPLETE,
         notes = "Verifies the functionality of split(java.lang.CharSequence). Test uses not empty pattern.",
diff --git a/libcore/security/src/main/files/cacerts.bks b/libcore/security/src/main/files/cacerts.bks
index bbcc080..36f4919 100644
--- a/libcore/security/src/main/files/cacerts.bks
+++ b/libcore/security/src/main/files/cacerts.bks
Binary files differ
diff --git a/libcore/security/src/main/files/cacerts/3e7271e8.0 b/libcore/security/src/main/files/cacerts/3e7271e8.0
new file mode 100644
index 0000000..62b5b22
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/3e7271e8.0
@@ -0,0 +1,85 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 946059622 (0x3863b966)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048)
+        Validity
+            Not Before: Dec 24 17:50:51 1999 GMT
+            Not After : Dec 24 18:20:51 2019 GMT
+        Subject: O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048)
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:ad:4d:4b:a9:12:86:b2:ea:a3:20:07:15:16:64:
+                    2a:2b:4b:d1:bf:0b:4a:4d:8e:ed:80:76:a5:67:b7:
+                    78:40:c0:73:42:c8:68:c0:db:53:2b:dd:5e:b8:76:
+                    98:35:93:8b:1a:9d:7c:13:3a:0e:1f:5b:b7:1e:cf:
+                    e5:24:14:1e:b1:81:a9:8d:7d:b8:cc:6b:4b:03:f1:
+                    02:0c:dc:ab:a5:40:24:00:7f:74:94:a1:9d:08:29:
+                    b3:88:0b:f5:87:77:9d:55:cd:e4:c3:7e:d7:6a:64:
+                    ab:85:14:86:95:5b:97:32:50:6f:3d:c8:ba:66:0c:
+                    e3:fc:bd:b8:49:c1:76:89:49:19:fd:c0:a8:bd:89:
+                    a3:67:2f:c6:9f:bc:71:19:60:b8:2d:e9:2c:c9:90:
+                    76:66:7b:94:e2:af:78:d6:65:53:5d:3c:d6:9c:b2:
+                    cf:29:03:f9:2f:a4:50:b2:d4:48:ce:05:32:55:8a:
+                    fd:b2:64:4c:0e:e4:98:07:75:db:7f:df:b9:08:55:
+                    60:85:30:29:f9:7b:48:a4:69:86:e3:35:3f:1e:86:
+                    5d:7a:7a:15:bd:ef:00:8e:15:22:54:17:00:90:26:
+                    93:bc:0e:49:68:91:bf:f8:47:d3:9d:95:42:c1:0e:
+                    4d:df:6f:26:cf:c3:18:21:62:66:43:70:d6:d5:c0:
+                    07:e1
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            Netscape Cert Type: 
+                SSL CA, S/MIME CA, Object Signing CA
+            X509v3 Authority Key Identifier: 
+                keyid:55:E4:81:D1:11:80:BE:D8:89:B9:08:A3:31:F9:A1:24:09:16:B9:70
+
+            X509v3 Subject Key Identifier: 
+                55:E4:81:D1:11:80:BE:D8:89:B9:08:A3:31:F9:A1:24:09:16:B9:70
+            1.2.840.113533.7.65.0: 
+                0...V5.0:4.0....
+    Signature Algorithm: sha1WithRSAEncryption
+        59:47:ac:21:84:8a:17:c9:9c:89:53:1e:ba:80:85:1a:c6:3c:
+        4e:3e:b1:9c:b6:7c:c6:92:5d:18:64:02:e3:d3:06:08:11:61:
+        7c:63:e3:2b:9d:31:03:70:76:d2:a3:28:a0:f4:bb:9a:63:73:
+        ed:6d:e5:2a:db:ed:14:a9:2b:c6:36:11:d0:2b:eb:07:8b:a5:
+        da:9e:5c:19:9d:56:12:f5:54:29:c8:05:ed:b2:12:2a:8d:f4:
+        03:1b:ff:e7:92:10:87:b0:3a:b5:c3:9d:05:37:12:a3:c7:f4:
+        15:b9:d5:a4:39:16:9b:53:3a:23:91:f1:a8:82:a2:6a:88:68:
+        c1:79:02:22:bc:aa:a6:d6:ae:df:b0:14:5f:b8:87:d0:dd:7c:
+        7f:7b:ff:af:1c:cf:e6:db:07:ad:5e:db:85:9d:d0:2b:0d:33:
+        db:04:d1:e6:49:40:13:2b:76:fb:3e:e9:9c:89:0f:15:ce:18:
+        b0:85:78:21:4f:6b:4f:0e:fa:36:67:cd:07:f2:ff:08:d0:e2:
+        de:d9:bf:2a:af:b8:87:86:21:3c:04:ca:b7:94:68:7f:cf:3c:
+        e9:98:d7:38:ff:ec:c0:d9:50:f0:2e:4b:58:ae:46:6f:d0:2e:
+        c3:60:da:72:55:72:bd:4c:45:9e:61:ba:bf:84:81:92:03:d1:
+        d2:69:7c:c5
+-----BEGIN CERTIFICATE-----
+MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML
+RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp
+bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5
+IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy
+MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3
+LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp
+YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG
+A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq
+K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe
+sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX
+MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT
+XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/
+HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH
+4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA
+vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G
+CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA
+WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo
+oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ
+h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18
+f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN
+B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy
+vUxFnmG6v4SBkgPR0ml8xQ==
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/ab86d4de.0 b/libcore/security/src/main/files/cacerts/ab86d4de.0
new file mode 100644
index 0000000..c6f241f
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/ab86d4de.0
@@ -0,0 +1,104 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 946062766 (0x3863c5ae)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048)
+        Validity
+            Not Before: Aug 25 18:14:26 2008 GMT
+            Not After : Aug 25 18:44:26 2018 GMT
+        Subject: C=US, O=Entrust, Inc., OU=AND ADDITIONAL TERMS GOVERNING USE AND RELIANCE, OU=CPS CONTAINS IMPORTANT LIMITATIONS OF WARRANTIES AND LIABILITY, OU=www.entrust.net/CPS is incorporated by reference, OU=(c) 2008 Entrust, Inc., CN=Entrust Certification Authority - L1B
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:dc:21:f5:68:f9:7a:ce:87:f2:78:df:d8:3b:4d:
+                    06:7d:c6:24:e4:a9:cd:9d:01:56:e4:f6:71:17:aa:
+                    7f:75:22:18:e4:74:6d:1b:3e:56:d5:b1:a6:1e:dd:
+                    59:26:53:ca:06:e6:ba:0b:6f:37:bb:a8:c6:9c:15:
+                    3b:06:1b:87:0c:c2:1a:4d:d3:81:ae:db:50:65:a5:
+                    3a:64:4f:30:34:9a:2b:a9:1f:fd:2b:d1:38:71:19:
+                    68:f2:8e:eb:7b:c9:40:3c:48:c4:19:b1:b7:10:25:
+                    ef:44:a7:e6:77:9b:7d:22:9a:de:d8:5e:d9:c3:ce:
+                    c9:71:22:bb:ae:ef:05:d6:f2:17:e7:56:78:e1:53:
+                    05:4a:26:73:b8:c7:49:67:93:23:0f:56:b2:8f:dd:
+                    c9:59:05:e5:63:15:b4:87:7e:40:46:e9:b5:00:7b:
+                    03:b4:0d:e4:96:67:2c:de:1b:59:0b:1a:1f:b8:63:
+                    44:ae:c1:d7:44:87:c4:91:59:9c:00:43:6d:c6:df:
+                    0a:b0:b1:04:cd:fe:be:30:5e:3a:25:72:dd:a2:3e:
+                    ed:46:3a:c7:a4:5c:5c:e4:25:f2:13:07:e8:ae:da:
+                    9b:19:9b:a2:d9:60:9d:ce:90:47:6a:61:7b:40:e8:
+                    14:c2:fe:2f:84:5a:66:17:c0:97:d3:49:38:de:63:
+                    02:9f
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            Authority Information Access: 
+                OCSP - URI:http://ocsp.entrust.net
+
+            X509v3 CRL Distribution Points: 
+                URI:http://crl.entrust.net/2048ca.crl
+
+            X509v3 Certificate Policies: 
+                Policy: X509v3 Any Policy
+                  CPS: http://www.entrust.net/CPS
+
+            X509v3 Subject Key Identifier: 
+                F5:F2:96:88:7D:0D:F3:2A:F9:4E:E7:34:A0:BD:46:7E:13:D6:16:C8
+            X509v3 Authority Key Identifier: 
+                keyid:55:E4:81:D1:11:80:BE:D8:89:B9:08:A3:31:F9:A1:24:09:16:B9:70
+
+            1.2.840.113533.7.65.0: 
+                0
+..V7.1....
+    Signature Algorithm: sha1WithRSAEncryption
+        0b:25:3c:58:fa:8e:dc:a2:42:3b:76:71:6e:6c:d4:4f:2b:b9:
+        53:5c:b2:58:b9:b1:dc:6f:1a:e4:e3:c4:50:f2:41:82:ba:f4:
+        7d:c7:c1:f9:fa:8c:53:bf:b9:62:b7:49:e3:1d:0a:fc:1f:d6:
+        c4:76:6a:93:cb:77:1e:2c:7f:d0:3f:16:63:4c:72:4c:67:60:
+        0f:f8:80:d6:a7:9a:ca:a2:33:91:0f:44:b2:66:3d:8e:68:0c:
+        40:85:12:37:91:b9:82:77:34:59:2d:5c:df:82:6e:2c:b6:7a:
+        d2:04:90:67:68:4b:70:fc:2d:b8:ff:90:64:6f:7e:91:f7:d1:
+        47:33:f3:5b:b8:58:2e:21:d8:75:60:1b:13:cc:f8:b2:a8:fa:
+        6a:a9:2a:5a:4f:45:85:40:b4:dd:34:05:b7:70:ca:01:ef:e1:
+        81:e7:11:50:db:3e:e2:d7:10:2e:6a:15:7f:b7:d4:a3:62:b2:
+        89:69:61:57:c6:7f:8e:9e:d4:24:7a:f3:a1:43:5f:a0:7a:89:
+        dc:59:cd:7d:d7:75:a7:bc:53:d5:47:35:c6:31:30:20:9f:9b:
+        ba:b5:83:e6:89:55:01:4d:91:3b:d6:89:35:87:3c:83:6b:7a:
+        29:82:d4:4b:d4:e6:16:74:b0:01:10:ab:69:06:14:37:7b:f7:
+        66:30:3a:c5
+-----BEGIN CERTIFICATE-----
+MIIFkTCCBHmgAwIBAgIEOGPFrjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML
+RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp
+bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5
+IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw0wODA4MjUxODE0MjZaFw0xODA4
+MjUxODQ0MjZaMIIBNDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIElu
+Yy4xODA2BgNVBAsTL0FORCBBRERJVElPTkFMIFRFUk1TIEdPVkVSTklORyBVU0Ug
+QU5EIFJFTElBTkNFMUcwRQYDVQQLEz5DUFMgQ09OVEFJTlMgSU1QT1JUQU5UIExJ
+TUlUQVRJT05TIE9GIFdBUlJBTlRJRVMgQU5EIExJQUJJTElUWTE5MDcGA1UECxMw
+d3d3LmVudHJ1c3QubmV0L0NQUyBpcyBpbmNvcnBvcmF0ZWQgYnkgcmVmZXJlbmNl
+MR8wHQYDVQQLExYoYykgMjAwOCBFbnRydXN0LCBJbmMuMS4wLAYDVQQDEyVFbnRy
+dXN0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gTDFCMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA3CH1aPl6zofyeN/YO00GfcYk5KnNnQFW5PZxF6p/
+dSIY5HRtGz5W1bGmHt1ZJlPKBua6C283u6jGnBU7BhuHDMIaTdOBrttQZaU6ZE8w
+NJorqR/9K9E4cRlo8o7re8lAPEjEGbG3ECXvRKfmd5t9Ipre2F7Zw87JcSK7ru8F
+1vIX51Z44VMFSiZzuMdJZ5MjD1ayj93JWQXlYxW0h35ARum1AHsDtA3klmcs3htZ
+CxofuGNErsHXRIfEkVmcAENtxt8KsLEEzf6+MF46JXLdoj7tRjrHpFxc5CXyEwfo
+rtqbGZui2WCdzpBHamF7QOgUwv4vhFpmF8CX00k43mMCnwIDAQABo4IBJjCCASIw
+DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wMwYIKwYBBQUHAQEEJzAl
+MCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5lbnRydXN0Lm5ldDAyBgNVHR8EKzAp
+MCegJaAjhiFodHRwOi8vY3JsLmVudHJ1c3QubmV0LzIwNDhjYS5jcmwwOwYDVR0g
+BDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly93d3cuZW50cnVzdC5u
+ZXQvQ1BTMB0GA1UdDgQWBBT18paIfQ3zKvlO5zSgvUZ+E9YWyDAfBgNVHSMEGDAW
+gBRV5IHREYC+2Im5CKMx+aEkCRa5cDAZBgkqhkiG9n0HQQAEDDAKGwRWNy4xAwIA
+gTANBgkqhkiG9w0BAQUFAAOCAQEACyU8WPqO3KJCO3ZxbmzUTyu5U1yyWLmx3G8a
+5OPEUPJBgrr0fcfB+fqMU7+5YrdJ4x0K/B/WxHZqk8t3Hix/0D8WY0xyTGdgD/iA
+1qeayqIzkQ9EsmY9jmgMQIUSN5G5gnc0WS1c34JuLLZ60gSQZ2hLcPwtuP+QZG9+
+kffRRzPzW7hYLiHYdWAbE8z4sqj6aqkqWk9FhUC03TQFt3DKAe/hgecRUNs+4tcQ
+LmoVf7fUo2KyiWlhV8Z/jp7UJHrzoUNfoHqJ3FnNfdd1p7xT1Uc1xjEwIJ+burWD
+5olVAU2RO9aJNYc8g2t6KYLUS9TmFnSwARCraQYUN3v3ZjA6xQ==
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/b0f3e76e.0 b/libcore/security/src/main/files/cacerts/b0f3e76e.0
index 05ce1ec..386b70a 100644
--- a/libcore/security/src/main/files/cacerts/b0f3e76e.0
+++ b/libcore/security/src/main/files/cacerts/b0f3e76e.0
@@ -2,12 +2,12 @@
     Data:
         Version: 3 (0x2)
         Serial Number:
-            02:00:00:00:00:00:d6:78:b7:94:05
-        Signature Algorithm: md5WithRSAEncryption
+            04:00:00:00:00:01:15:4b:5a:c3:94
+        Signature Algorithm: sha1WithRSAEncryption
         Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA
         Validity
             Not Before: Sep  1 12:00:00 1998 GMT
-            Not After : Jan 28 12:00:00 2014 GMT
+            Not After : Jan 28 12:00:00 2028 GMT
         Subject: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA
         Subject Public Key Info:
             Public Key Algorithm: rsaEncryption
@@ -35,32 +35,31 @@
         X509v3 extensions:
             X509v3 Key Usage: critical
                 Certificate Sign, CRL Sign
-            X509v3 Subject Key Identifier: 
-                60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B
             X509v3 Basic Constraints: critical
                 CA:TRUE
-    Signature Algorithm: md5WithRSAEncryption
-        ae:aa:9f:fc:b7:d2:cb:1f:5f:39:29:28:18:9e:34:c9:6c:4f:
-        6f:1a:f0:64:a2:70:4a:4f:13:86:9b:60:28:9e:e8:81:49:98:
-        7d:0a:bb:e5:b0:9d:3d:36:db:8f:05:51:ff:09:31:2a:1f:dd:
-        89:77:9e:0f:2e:6c:95:04:ed:86:cb:b4:00:3f:84:02:4d:80:
-        6a:2a:2d:78:0b:ae:6f:2b:a2:83:44:83:1f:cd:50:82:4c:24:
-        af:bd:f7:a5:b4:c8:5a:0f:f4:e7:47:5e:49:8e:37:96:fe:9a:
-        88:05:3a:d9:c0:db:29:87:e6:19:96:47:a7:3a:a6:8c:8b:3c:
-        77:fe:46:63:a7:53:da:21:d1:ac:7e:49:a2:4b:e6:c3:67:59:
-        2f:b3:8a:0e:bb:2c:bd:a9:aa:42:7c:35:c1:d8:7f:d5:a7:31:
-        3a:4e:63:43:39:af:08:b0:61:34:8c:d3:98:a9:43:34:f6:0f:
-        87:29:3b:9d:c2:56:58:98:77:c3:f7:1b:ac:f6:9d:f8:3e:aa:
-        a7:54:45:f0:f5:f9:d5:31:65:fe:6b:58:9c:71:b3:1e:d7:52:
-        ea:32:17:fc:40:60:1d:c9:79:24:b2:f6:6c:fd:a8:66:0e:82:
-        dd:98:cb:da:c2:44:4f:2e:a0:7b:f2:f7:6b:2c:76:11:84:46:
-        8a:78:a3:e3
-SHA1 Fingerprint=2F:17:3F:7D:E9:96:67:AF:A5:7A:F8:0A:A2:D1:B1:2F:AC:83:03:38
+            X509v3 Subject Key Identifier: 
+                60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B
+    Signature Algorithm: sha1WithRSAEncryption
+        d6:73:e7:7c:4f:76:d0:8d:bf:ec:ba:a2:be:34:c5:28:32:b5:
+        7c:fc:6c:9c:2c:2b:bd:09:9e:53:bf:6b:5e:aa:11:48:b6:e5:
+        08:a3:b3:ca:3d:61:4d:d3:46:09:b3:3e:c3:a0:e3:63:55:1b:
+        f2:ba:ef:ad:39:e1:43:b9:38:a3:e6:2f:8a:26:3b:ef:a0:50:
+        56:f9:c6:0a:fd:38:cd:c4:0b:70:51:94:97:98:04:df:c3:5f:
+        94:d5:15:c9:14:41:9c:c4:5d:75:64:15:0d:ff:55:30:ec:86:
+        8f:ff:0d:ef:2c:b9:63:46:f6:aa:fc:df:bc:69:fd:2e:12:48:
+        64:9a:e0:95:f0:a6:ef:29:8f:01:b1:15:b5:0c:1d:a5:fe:69:
+        2c:69:24:78:1e:b3:a7:1c:71:62:ee:ca:c8:97:ac:17:5d:8a:
+        c2:f8:47:86:6e:2a:c4:56:31:95:d0:67:89:85:2b:f9:6c:a6:
+        5d:46:9d:0c:aa:82:e4:99:51:dd:70:b7:db:56:3d:61:e4:6a:
+        e1:5c:d6:f6:fe:3d:de:41:cc:07:ae:63:52:bf:53:53:f4:2b:
+        e9:c7:fd:b6:f7:82:5f:85:d2:41:18:db:81:b3:04:1c:c5:1f:
+        a4:80:6f:15:20:c9:de:0c:88:0a:1d:d6:66:55:e2:fc:48:c9:
+        29:26:69:e0
 -----BEGIN CERTIFICATE-----
-MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzELMAkG
+MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
 A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
 b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
-MDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
 YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
 aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
 jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
@@ -68,12 +67,12 @@
 1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
 snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
 U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
-9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQU
-YHtmGkUNl8qJUC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B
-AQQFAAOCAQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq7
-5bCdPTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q
-gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT2iHR
-rH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlDNPYPhyk7
-ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBgHcl5JLL2bP2o
-Zg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w==
+9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
+AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
+yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
+38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
+AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
+DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
+HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
 -----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/bf64f35b.0 b/libcore/security/src/main/files/cacerts/bf64f35b.0
new file mode 100644
index 0000000..389623c
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/bf64f35b.0
@@ -0,0 +1,92 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1116155212 (0x42872d4c)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=US, O=Entrust.net, OU=www.entrust.net/CPS incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Secure Server Certification Authority
+        Validity
+            Not Before: Jan  5 19:20:39 2007 GMT
+            Not After : Jan  5 19:50:39 2017 GMT
+        Subject: C=US, O=Entrust, Inc., OU=www.entrust.net/CPS is incorporated by reference, OU=(c) 2006 Entrust, Inc., CN=Entrust Root Certification Authority
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:b6:95:b6:43:42:fa:c6:6d:2a:6f:48:df:94:4c:
+                    39:57:05:ee:c3:79:11:41:68:36:ed:ec:fe:9a:01:
+                    8f:a1:38:28:fc:f7:10:46:66:2e:4d:1e:1a:b1:1a:
+                    4e:c6:d1:c0:95:88:b0:c9:ff:31:8b:33:03:db:b7:
+                    83:7b:3e:20:84:5e:ed:b2:56:28:a7:f8:e0:b9:40:
+                    71:37:c5:cb:47:0e:97:2a:68:c0:22:95:62:15:db:
+                    47:d9:f5:d0:2b:ff:82:4b:c9:ad:3e:de:4c:db:90:
+                    80:50:3f:09:8a:84:00:ec:30:0a:3d:18:cd:fb:fd:
+                    2a:59:9a:23:95:17:2c:45:9e:1f:6e:43:79:6d:0c:
+                    5c:98:fe:48:a7:c5:23:47:5c:5e:fd:6e:e7:1e:b4:
+                    f6:68:45:d1:86:83:5b:a2:8a:8d:b1:e3:29:80:fe:
+                    25:71:88:ad:be:bc:8f:ac:52:96:4b:aa:51:8d:e4:
+                    13:31:19:e8:4e:4d:9f:db:ac:b3:6a:d5:bc:39:54:
+                    71:ca:7a:7a:7f:90:dd:7d:1d:80:d9:81:bb:59:26:
+                    c2:11:fe:e6:93:e2:f7:80:e4:65:fb:34:37:0e:29:
+                    80:70:4d:af:38:86:2e:9e:7f:57:af:9e:17:ae:eb:
+                    1c:cb:28:21:5f:b6:1c:d8:e7:a2:04:22:f9:d3:da:
+                    d8:cb
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            Authority Information Access: 
+                OCSP - URI:http://ocsp.entrust.net
+
+            X509v3 CRL Distribution Points: 
+                URI:http://crl.entrust.net/server1.crl
+
+            X509v3 Certificate Policies: 
+                Policy: X509v3 Any Policy
+                  CPS: http://www.entrust.net/CPS
+
+            X509v3 Subject Key Identifier: 
+                68:90:E4:67:A4:A6:53:80:C7:86:66:A4:F1:F7:4B:43:FB:84:BD:6D
+            X509v3 Authority Key Identifier: 
+                keyid:F0:17:62:13:55:3D:B3:FF:0A:00:6B:FB:50:84:97:F3:ED:62:D0:1A
+
+            1.2.840.113533.7.65.0: 
+                0
+..V7.1....
+    Signature Algorithm: sha1WithRSAEncryption
+        0c:b0:84:7c:2d:13:fe:9a:3d:bf:18:05:95:3d:20:48:a3:16:
+        81:87:15:50:15:a4:88:8d:9f:60:d4:3a:6f:eb:2d:6e:3a:86:
+        a4:a9:d2:c1:9d:89:7a:08:1c:a4:2d:b3:47:8e:0f:64:4a:6f:
+        66:03:83:3f:4f:34:94:36:aa:29:6d:8b:8d:02:22:2b:8c:cd:
+        77:a5:70:95:86:91:d1:b6:bf:52:be:33:6a:6b:99:f9:6f:e1:
+        12:be:04:cb:33:bf:f5:12:1a:4e:44:ba:5b:16:4d:30:b9:f3:
+        b4:74:ce:6e:f2:68:56:58:dd:d8:a1:fd:54:05:f4:23:91:85:
+        c9:f9
+-----BEGIN CERTIFICATE-----
+MIIEmzCCBASgAwIBAgIEQoctTDANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC
+VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u
+ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
+KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u
+ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNzAx
+MDUxOTIwMzlaFw0xNzAxMDUxOTUwMzlaMIGwMQswCQYDVQQGEwJVUzEWMBQGA1UE
+ChMNRW50cnVzdCwgSW5jLjE5MDcGA1UECxMwd3d3LmVudHJ1c3QubmV0L0NQUyBp
+cyBpbmNvcnBvcmF0ZWQgYnkgcmVmZXJlbmNlMR8wHQYDVQQLExYoYykgMjAwNiBF
+bnRydXN0LCBJbmMuMS0wKwYDVQQDEyRFbnRydXN0IFJvb3QgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2lbZD
+QvrGbSpvSN+UTDlXBe7DeRFBaDbt7P6aAY+hOCj89xBGZi5NHhqxGk7G0cCViLDJ
+/zGLMwPbt4N7PiCEXu2yViin+OC5QHE3xctHDpcqaMAilWIV20fZ9dAr/4JLya0+
+3kzbkIBQPwmKhADsMAo9GM37/SpZmiOVFyxFnh9uQ3ltDFyY/kinxSNHXF79buce
+tPZoRdGGg1uiio2x4ymA/iVxiK2+vI+sUpZLqlGN5BMxGehOTZ/brLNq1bw5VHHK
+enp/kN19HYDZgbtZJsIR/uaT4veA5GX7NDcOKYBwTa84hi6ef1evnheu6xzLKCFf
+thzY56IEIvnT2tjLAgMBAAGjggEnMIIBIzAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T
+AQH/BAUwAwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9v
+Y3NwLmVudHJ1c3QubmV0MDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZW50
+cnVzdC5uZXQvc2VydmVyMS5jcmwwOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYB
+BQUHAgEWGmh0dHA6Ly93d3cuZW50cnVzdC5uZXQvQ1BTMB0GA1UdDgQWBBRokORn
+pKZTgMeGZqTx90tD+4S9bTAfBgNVHSMEGDAWgBTwF2ITVT2z/woAa/tQhJfz7WLQ
+GjAZBgkqhkiG9n0HQQAEDDAKGwRWNy4xAwIAgTANBgkqhkiG9w0BAQUFAAOBgQAM
+sIR8LRP+mj2/GAWVPSBIoxaBhxVQFaSIjZ9g1Dpv6y1uOoakqdLBnYl6CBykLbNH
+jg9kSm9mA4M/TzSUNqopbYuNAiIrjM13pXCVhpHRtr9SvjNqa5n5b+ESvgTLM7/1
+EhpORLpbFk0wufO0dM5u8mhWWN3Yof1UBfQjkYXJ+Q==
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/certimport.sh b/libcore/security/src/main/files/certimport.sh
index 7c0fab0..c021a10 100755
--- a/libcore/security/src/main/files/certimport.sh
+++ b/libcore/security/src/main/files/certimport.sh
@@ -1,4 +1,5 @@
 #!/bin/bash
+# java version >= 1.6 is required for this script.
 # This script was tested to work with bouncycastle 1.32.
 
 set -x
@@ -6,6 +7,14 @@
 
 CERTSTORE=cacerts.bks
 
+# Check java version.
+JAVA_VERSION=`java -version 2>&1 | head -1`
+JAVA_VERSION_MINOR=`expr match "$JAVA_VERSION" "java version \"[1-9]\.\([0-9]\).*\""`
+if [ $JAVA_VERSION_MINOR -lt 6 ]; then
+  echo "java version 1.6 or greater required for keytool usage"
+  exit 255
+fi
+
 if [ -a $CERTSTORE ]; then
     rm $CERTSTORE || exit 1
 fi
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValue.java b/libcore/security/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValue.java
index c8f9494..34337eb 100644
--- a/libcore/security/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValue.java
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValue.java
@@ -327,11 +327,15 @@
                 if (attrFormat == X500Principal.CANONICAL) {
                     // only PrintableString and UTF8String in string format
                     // all others are output in hex format
+                    // BEGIN android-changed
+                    // no hex for teletex; see bug 2102191
                     int tag = value.getTag();
                     if (!ASN1StringType.UTF8STRING.checkTag(tag)
-                            && !ASN1StringType.PRINTABLESTRING.checkTag(tag)) {
+                            && !ASN1StringType.PRINTABLESTRING.checkTag(tag)
+                            && !ASN1StringType.TELETEXSTRING.checkTag(tag)) {
                         hexFormat = true;
                     }
+                    // END android-changed
                 }
 
             } else {
diff --git a/libcore/security/src/test/java/org/bouncycastle/jce/provider/AllTests.java b/libcore/security/src/test/java/org/bouncycastle/jce/provider/AllTests.java
new file mode 100644
index 0000000..e9fbdb0
--- /dev/null
+++ b/libcore/security/src/test/java/org/bouncycastle/jce/provider/AllTests.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.bouncycastle.jce.provider;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AllTests {
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(AllTests.suite());
+    }
+
+    public static Test suite() {
+        TestSuite suite = tests.TestSuiteFactory.createTestSuite(
+                "All tests for " + AllTests.class.getPackage());
+        suite.addTestSuite(PKIXCertPathValidatorSpiTest.class);
+        return suite;
+    }
+}
diff --git a/libcore/security/src/test/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpiTest.java b/libcore/security/src/test/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpiTest.java
new file mode 100644
index 0000000..734e11d
--- /dev/null
+++ b/libcore/security/src/test/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpiTest.java
@@ -0,0 +1,65 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+
+package org.bouncycastle.jce.provider;
+
+import junit.framework.TestCase;
+import org.apache.harmony.security.provider.cert.X509CertImpl;
+import org.apache.harmony.security.provider.cert.X509CertPathImpl;
+import org.bouncycastle.asn1.x509.X509CertificateStructure;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1InputStream;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.HashSet;
+import java.security.cert.CertificateException;
+import java.security.cert.TrustAnchor;
+import java.security.cert.CertPathValidatorException;
+import java.security.KeyStoreException;
+import java.security.InvalidAlgorithmParameterException;
+
+/**
+ * Verify the behavior of PKIXCertPathValidatorSpi.
+ */
+public class PKIXCertPathValidatorSpiTest extends TestCase {
+
+    /**
+     * A chain of 3 ASN1-encoded certificates for https://service.sprint.com.
+     * The certificate subjects are "service.sprint.com", "Entrust Certification
+     * Authority - L1B", and "Entrust.net Certification Authority (2048)". The
+     * last certificate uses UTF8 encoding for its X509 name.
+     */
+    private final byte[][] serviceSprintComCertChain = new byte[][] {
+            new byte[] { 48, -126, 6, 89, 48, -126, 5, 65, -96, 3, 2, 1, 2, 2, 4, 72, 13, 115, -81, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 5, 5, 0, 48, -126, 1, 52, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 22, 48, 20, 6, 3, 85, 4, 10, 19, 13, 69, 110, 116, 114, 117, 115, 116, 44, 32, 73, 110, 99, 46, 49, 56, 48, 54, 6, 3, 85, 4, 11, 19, 47, 65, 78, 68, 32, 65, 68, 68, 73, 84, 73, 79, 78, 65, 76, 32, 84, 69, 82, 77, 83, 32, 71, 79, 86, 69, 82, 78, 73, 78, 71, 32, 85, 83, 69, 32, 65, 78, 68, 32, 82, 69, 76, 73, 65, 78, 67, 69, 49, 71, 48, 69, 6, 3, 85, 4, 11, 19, 62, 67, 80, 83, 32, 67, 79, 78, 84, 65, 73, 78, 83, 32, 73, 77, 80, 79, 82, 84, 65, 78, 84, 32, 76, 73, 77, 73, 84, 65, 84, 73, 79, 78, 83, 32, 79, 70, 32, 87, 65, 82, 82, 65, 78, 84, 73, 69, 83, 32, 65, 78, 68, 32, 76, 73, 65, 66, 73, 76, 73, 84, 89, 49, 57, 48, 55, 6, 3, 85, 4, 11, 19, 48, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 67, 80, 83, 32, 105, 115, 32, 105, 110, 99, 111, 114, 112, 111, 114, 97, 116, 101, 100, 32, 98, 121, 32, 114, 101, 102, 101, 114, 101, 110, 99, 101, 49, 31, 48, 29, 6, 3, 85, 4, 11, 19, 22, 40, 99, 41, 32, 50, 48, 48, 56, 32, 69, 110, 116, 114, 117, 115, 116, 44, 32, 73, 110, 99, 46, 49, 46, 48, 44, 6, 3, 85, 4, 3, 19, 37, 69, 110, 116, 114, 117, 115, 116, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 32, 65, 117, 116, 104, 111, 114, 105, 116, 121, 32, 45, 32, 76, 49, 66, 48, 30, 23, 13, 48, 57, 48, 52, 50, 57, 49, 53, 50, 54, 53, 57, 90, 23, 13, 49, 49, 48, 53, 48, 53, 49, 53, 53, 54, 53, 55, 90, 48, 120, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 15, 48, 13, 6, 3, 85, 4, 8, 19, 6, 75, 65, 78, 83, 65, 83, 49, 22, 48, 20, 6, 3, 85, 4, 7, 19, 13, 79, 118, 101, 114, 108, 97, 110, 100, 32, 80, 97, 114, 107, 49, 15, 48, 13, 6, 3, 85, 4, 10, 19, 6, 83, 112, 114, 105, 110, 116, 49, 18, 48, 16, 6, 3, 85, 4, 11, 19, 9, 100, 97, 115, 110, 109, 112, 48, 52, 98, 49, 27, 48, 25, 6, 3, 85, 4, 3, 19, 18, 115, 101, 114, 118, 105, 99, 101, 46, 115, 112, 114, 105, 110, 116, 46, 99, 111, 109, 48, -127, -97, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0, 3, -127, -115, 0, 48, -127, -119, 2, -127, -127, 0, -80, 99, 109, 108, 94, -41, -78, 88, 56, -97, 33, -23, 65, -74, -118, 0, 1, 119, 126, 122, -59, -83, -25, -16, -75, -87, 100, 46, 37, -98, 65, -104, 54, -87, 56, -81, 96, -38, -4, -78, 11, 101, -29, 70, -13, -110, -76, -125, -106, -35, 41, 83, 71, 56, 6, 67, -8, 82, -58, -81, -113, 90, 91, 79, 74, -38, 34, 28, 39, -37, -12, 54, 87, 61, 48, 33, -16, 10, 112, -40, -37, -15, 59, -72, 112, 96, 85, 109, 123, -122, 58, 18, 95, 56, -81, 49, 43, -39, 99, 69, -28, -81, -106, -64, 8, -62, 40, -92, 95, -109, -122, 94, 53, -13, -33, 88, -104, 3, -77, -30, -27, 23, 92, -69, 12, -23, -9, 125, 2, 3, 1, 0, 1, -93, -126, 2, -81, 48, -126, 2, -85, 48, 11, 6, 3, 85, 29, 15, 4, 4, 3, 2, 5, -96, 48, 43, 6, 3, 85, 29, 16, 4, 36, 48, 34, -128, 15, 50, 48, 48, 57, 48, 52, 50, 57, 49, 53, 50, 54, 53, 57, 90, -127, 15, 50, 48, 49, 49, 48, 53, 48, 53, 49, 53, 53, 54, 53, 55, 90, 48, 19, 6, 3, 85, 29, 37, 4, 12, 48, 10, 6, 8, 43, 6, 1, 5, 5, 7, 3, 1, 48, 51, 6, 3, 85, 29, 31, 4, 44, 48, 42, 48, 40, -96, 38, -96, 36, -122, 34, 104, 116, 116, 112, 58, 47, 47, 99, 114, 108, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 108, 101, 118, 101, 108, 49, 98, 46, 99, 114, 108, 48, 100, 6, 8, 43, 6, 1, 5, 5, 7, 1, 1, 4, 88, 48, 86, 48, 35, 6, 8, 43, 6, 1, 5, 5, 7, 48, 1, -122, 23, 104, 116, 116, 112, 58, 47, 47, 111, 99, 115, 112, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 48, 47, 6, 8, 43, 6, 1, 5, 5, 7, 48, 2, -122, 35, 104, 116, 116, 112, 58, 47, 47, 97, 105, 97, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 50, 48, 52, 56, 45, 108, 49, 98, 46, 99, 101, 114, 48, -126, 1, 87, 6, 3, 85, 29, 32, 4, -126, 1, 78, 48, -126, 1, 74, 48, -126, 1, 70, 6, 9, 42, -122, 72, -122, -10, 125, 7, 75, 2, 48, -126, 1, 55, 48, 38, 6, 8, 43, 6, 1, 5, 5, 7, 2, 1, 22, 26, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 99, 112, 115, 48, -126, 1, 11, 6, 8, 43, 6, 1, 5, 5, 7, 2, 2, 48, -127, -2, 26, -127, -5, 84, 104, 101, 32, 69, 110, 116, 114, 117, 115, 116, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 32, 80, 114, 97, 99, 116, 105, 99, 101, 32, 83, 116, 97, 116, 101, 109, 101, 110, 116, 32, 40, 67, 80, 83, 41, 32, 97, 118, 97, 105, 108, 97, 98, 108, 101, 32, 97, 116, 32, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 99, 112, 115, 32, 32, 105, 115, 32, 104, 101, 114, 101, 98, 121, 32, 105, 110, 99, 111, 114, 112, 111, 114, 97, 116, 101, 100, 32, 105, 110, 116, 111, 32, 121, 111, 117, 114, 32, 117, 115, 101, 32, 111, 114, 32, 114, 101, 108, 105, 97, 110, 99, 101, 32, 111, 110, 32, 116, 104, 105, 115, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 46, 32, 32, 84, 104, 105, 115, 32, 67, 80, 83, 32, 99, 111, 110, 116, 97, 105, 110, 115, 32, 108, 105, 109, 105, 116, 97, 116, 105, 111, 110, 115, 32, 111, 110, 32, 119, 97, 114, 114, 97, 110, 116, 105, 101, 115, 32, 97, 110, 100, 32, 108, 105, 97, 98, 105, 108, 105, 116, 105, 101, 115, 46, 32, 67, 111, 112, 121, 114, 105, 103, 104, 116, 32, 40, 99, 41, 32, 50, 48, 48, 56, 32, 69, 110, 116, 114, 117, 115, 116, 32, 76, 105, 109, 105, 116, 101, 100, 48, 31, 6, 3, 85, 29, 35, 4, 24, 48, 22, -128, 20, -11, -14, -106, -120, 125, 13, -13, 42, -7, 78, -25, 52, -96, -67, 70, 126, 19, -42, 22, -56, 48, 29, 6, 3, 85, 29, 14, 4, 22, 4, 20, 68, 101, 26, -23, -69, -107, 32, 89, 18, 28, -123, 32, 74, -116, -33, -48, 70, -52, 68, 77, 48, 9, 6, 3, 85, 29, 19, 4, 2, 48, 0, 48, 25, 6, 9, 42, -122, 72, -122, -10, 125, 7, 65, 0, 4, 12, 48, 10, 27, 4, 86, 55, 46, 49, 3, 2, 3, 40, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 5, 5, 0, 3, -126, 1, 1, 0, 18, 56, 92, -74, -100, -56, 95, 121, 27, -84, -88, -104, -27, -98, -12, 58, 48, -26, 40, -7, 25, -68, -124, -104, -54, -121, 84, 52, 3, 22, -106, 88, 44, -39, 126, 17, 96, 4, -41, -84, -101, 74, -92, -113, -12, -99, 77, 108, -30, 38, 19, 78, 48, 32, -126, 95, -10, -114, 58, 98, -49, -108, -109, -87, 5, -80, -43, 121, 21, -99, 43, -73, 26, 51, 31, 87, -38, -119, 78, -113, -59, -100, -118, -84, -46, -48, 93, 99, 2, 40, -39, 76, -48, -122, -60, -25, -73, 103, 126, 83, -86, -26, 66, 122, -65, -89, -102, 115, 105, -124, -85, -18, -66, 85, 30, -29, -96, 104, 65, -66, 40, 69, -91, 101, -19, 39, -86, -21, -18, 39, 51, -1, 36, -52, 53, -65, 53, 12, -62, -97, -45, -26, 113, -20, 102, 56, 102, 104, 37, 17, 57, -96, -83, -71, 106, 63, -64, -122, 61, 59, 8, -123, 108, 22, 62, -58, -105, 88, 38, 96, -6, -29, -114, 105, 110, -102, -72, 109, -33, 56, 61, 52, 70, -75, -92, 97, -9, -6, -64, 53, -76, 81, -100, 90, -50, 19, -87, 30, -24, -53, 109, -75, 45, -38, 14, 119, -31, 44, -30, -93, -76, 14, 97, -53, -107, 60, 30, -102, 68, 12, 26, 76, -114, 73, -13, -127, 21, 94, -42, 94, 30, -50, -3, 116, 41, -3, -89, 23, -27, -49, -3, -95, 119, -104, -45, 112, 35, 66, 59, 84, 116, 19, -102, -68, -104, 1 },
+            new byte[] { 48, -126, 5, -111, 48, -126, 4, 121, -96, 3, 2, 1, 2, 2, 4, 56, 99, -59, -82, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 5, 5, 0, 48, -127, -76, 49, 20, 48, 18, 6, 3, 85, 4, 10, 19, 11, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 49, 64, 48, 62, 6, 3, 85, 4, 11, 20, 55, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 67, 80, 83, 95, 50, 48, 52, 56, 32, 105, 110, 99, 111, 114, 112, 46, 32, 98, 121, 32, 114, 101, 102, 46, 32, 40, 108, 105, 109, 105, 116, 115, 32, 108, 105, 97, 98, 46, 41, 49, 37, 48, 35, 6, 3, 85, 4, 11, 19, 28, 40, 99, 41, 32, 49, 57, 57, 57, 32, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 76, 105, 109, 105, 116, 101, 100, 49, 51, 48, 49, 6, 3, 85, 4, 3, 19, 42, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 32, 65, 117, 116, 104, 111, 114, 105, 116, 121, 32, 40, 50, 48, 52, 56, 41, 48, 30, 23, 13, 48, 56, 48, 56, 50, 53, 49, 56, 49, 52, 50, 54, 90, 23, 13, 49, 56, 48, 56, 50, 53, 49, 56, 52, 52, 50, 54, 90, 48, -126, 1, 52, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 22, 48, 20, 6, 3, 85, 4, 10, 19, 13, 69, 110, 116, 114, 117, 115, 116, 44, 32, 73, 110, 99, 46, 49, 56, 48, 54, 6, 3, 85, 4, 11, 19, 47, 65, 78, 68, 32, 65, 68, 68, 73, 84, 73, 79, 78, 65, 76, 32, 84, 69, 82, 77, 83, 32, 71, 79, 86, 69, 82, 78, 73, 78, 71, 32, 85, 83, 69, 32, 65, 78, 68, 32, 82, 69, 76, 73, 65, 78, 67, 69, 49, 71, 48, 69, 6, 3, 85, 4, 11, 19, 62, 67, 80, 83, 32, 67, 79, 78, 84, 65, 73, 78, 83, 32, 73, 77, 80, 79, 82, 84, 65, 78, 84, 32, 76, 73, 77, 73, 84, 65, 84, 73, 79, 78, 83, 32, 79, 70, 32, 87, 65, 82, 82, 65, 78, 84, 73, 69, 83, 32, 65, 78, 68, 32, 76, 73, 65, 66, 73, 76, 73, 84, 89, 49, 57, 48, 55, 6, 3, 85, 4, 11, 19, 48, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 67, 80, 83, 32, 105, 115, 32, 105, 110, 99, 111, 114, 112, 111, 114, 97, 116, 101, 100, 32, 98, 121, 32, 114, 101, 102, 101, 114, 101, 110, 99, 101, 49, 31, 48, 29, 6, 3, 85, 4, 11, 19, 22, 40, 99, 41, 32, 50, 48, 48, 56, 32, 69, 110, 116, 114, 117, 115, 116, 44, 32, 73, 110, 99, 46, 49, 46, 48, 44, 6, 3, 85, 4, 3, 19, 37, 69, 110, 116, 114, 117, 115, 116, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 32, 65, 117, 116, 104, 111, 114, 105, 116, 121, 32, 45, 32, 76, 49, 66, 48, -126, 1, 34, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0, 3, -126, 1, 15, 0, 48, -126, 1, 10, 2, -126, 1, 1, 0, -36, 33, -11, 104, -7, 122, -50, -121, -14, 120, -33, -40, 59, 77, 6, 125, -58, 36, -28, -87, -51, -99, 1, 86, -28, -10, 113, 23, -86, 127, 117, 34, 24, -28, 116, 109, 27, 62, 86, -43, -79, -90, 30, -35, 89, 38, 83, -54, 6, -26, -70, 11, 111, 55, -69, -88, -58, -100, 21, 59, 6, 27, -121, 12, -62, 26, 77, -45, -127, -82, -37, 80, 101, -91, 58, 100, 79, 48, 52, -102, 43, -87, 31, -3, 43, -47, 56, 113, 25, 104, -14, -114, -21, 123, -55, 64, 60, 72, -60, 25, -79, -73, 16, 37, -17, 68, -89, -26, 119, -101, 125, 34, -102, -34, -40, 94, -39, -61, -50, -55, 113, 34, -69, -82, -17, 5, -42, -14, 23, -25, 86, 120, -31, 83, 5, 74, 38, 115, -72, -57, 73, 103, -109, 35, 15, 86, -78, -113, -35, -55, 89, 5, -27, 99, 21, -76, -121, 126, 64, 70, -23, -75, 0, 123, 3, -76, 13, -28, -106, 103, 44, -34, 27, 89, 11, 26, 31, -72, 99, 68, -82, -63, -41, 68, -121, -60, -111, 89, -100, 0, 67, 109, -58, -33, 10, -80, -79, 4, -51, -2, -66, 48, 94, 58, 37, 114, -35, -94, 62, -19, 70, 58, -57, -92, 92, 92, -28, 37, -14, 19, 7, -24, -82, -38, -101, 25, -101, -94, -39, 96, -99, -50, -112, 71, 106, 97, 123, 64, -24, 20, -62, -2, 47, -124, 90, 102, 23, -64, -105, -45, 73, 56, -34, 99, 2, -97, 2, 3, 1, 0, 1, -93, -126, 1, 38, 48, -126, 1, 34, 48, 14, 6, 3, 85, 29, 15, 1, 1, -1, 4, 4, 3, 2, 1, 6, 48, 15, 6, 3, 85, 29, 19, 1, 1, -1, 4, 5, 48, 3, 1, 1, -1, 48, 51, 6, 8, 43, 6, 1, 5, 5, 7, 1, 1, 4, 39, 48, 37, 48, 35, 6, 8, 43, 6, 1, 5, 5, 7, 48, 1, -122, 23, 104, 116, 116, 112, 58, 47, 47, 111, 99, 115, 112, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 48, 50, 6, 3, 85, 29, 31, 4, 43, 48, 41, 48, 39, -96, 37, -96, 35, -122, 33, 104, 116, 116, 112, 58, 47, 47, 99, 114, 108, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 50, 48, 52, 56, 99, 97, 46, 99, 114, 108, 48, 59, 6, 3, 85, 29, 32, 4, 52, 48, 50, 48, 48, 6, 4, 85, 29, 32, 0, 48, 40, 48, 38, 6, 8, 43, 6, 1, 5, 5, 7, 2, 1, 22, 26, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 67, 80, 83, 48, 29, 6, 3, 85, 29, 14, 4, 22, 4, 20, -11, -14, -106, -120, 125, 13, -13, 42, -7, 78, -25, 52, -96, -67, 70, 126, 19, -42, 22, -56, 48, 31, 6, 3, 85, 29, 35, 4, 24, 48, 22, -128, 20, 85, -28, -127, -47, 17, -128, -66, -40, -119, -71, 8, -93, 49, -7, -95, 36, 9, 22, -71, 112, 48, 25, 6, 9, 42, -122, 72, -122, -10, 125, 7, 65, 0, 4, 12, 48, 10, 27, 4, 86, 55, 46, 49, 3, 2, 0, -127, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 5, 5, 0, 3, -126, 1, 1, 0, 11, 37, 60, 88, -6, -114, -36, -94, 66, 59, 118, 113, 110, 108, -44, 79, 43, -71, 83, 92, -78, 88, -71, -79, -36, 111, 26, -28, -29, -60, 80, -14, 65, -126, -70, -12, 125, -57, -63, -7, -6, -116, 83, -65, -71, 98, -73, 73, -29, 29, 10, -4, 31, -42, -60, 118, 106, -109, -53, 119, 30, 44, 127, -48, 63, 22, 99, 76, 114, 76, 103, 96, 15, -8, -128, -42, -89, -102, -54, -94, 51, -111, 15, 68, -78, 102, 61, -114, 104, 12, 64, -123, 18, 55, -111, -71, -126, 119, 52, 89, 45, 92, -33, -126, 110, 44, -74, 122, -46, 4, -112, 103, 104, 75, 112, -4, 45, -72, -1, -112, 100, 111, 126, -111, -9, -47, 71, 51, -13, 91, -72, 88, 46, 33, -40, 117, 96, 27, 19, -52, -8, -78, -88, -6, 106, -87, 42, 90, 79, 69, -123, 64, -76, -35, 52, 5, -73, 112, -54, 1, -17, -31, -127, -25, 17, 80, -37, 62, -30, -41, 16, 46, 106, 21, 127, -73, -44, -93, 98, -78, -119, 105, 97, 87, -58, 127, -114, -98, -44, 36, 122, -13, -95, 67, 95, -96, 122, -119, -36, 89, -51, 125, -41, 117, -89, -68, 83, -43, 71, 53, -58, 49, 48, 32, -97, -101, -70, -75, -125, -26, -119, 85, 1, 77, -111, 59, -42, -119, 53, -121, 60, -125, 107, 122, 41, -126, -44, 75, -44, -26, 22, 116, -80, 1, 16, -85, 105, 6, 20, 55, 123, -9, 102, 48, 58, -59 },
+            new byte[] { 48, -126, 4, 92, 48, -126, 3, 68, -96, 3, 2, 1, 2, 2, 4, 56, 99, -71, 102, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 5, 5, 0, 48, -127, -76, 49, 20, 48, 18, 6, 3, 85, 4, 10, 19, 11, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 49, 64, 48, 62, 6, 3, 85, 4, 11, 20, 55, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 67, 80, 83, 95, 50, 48, 52, 56, 32, 105, 110, 99, 111, 114, 112, 46, 32, 98, 121, 32, 114, 101, 102, 46, 32, 40, 108, 105, 109, 105, 116, 115, 32, 108, 105, 97, 98, 46, 41, 49, 37, 48, 35, 6, 3, 85, 4, 11, 19, 28, 40, 99, 41, 32, 49, 57, 57, 57, 32, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 76, 105, 109, 105, 116, 101, 100, 49, 51, 48, 49, 6, 3, 85, 4, 3, 19, 42, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 32, 65, 117, 116, 104, 111, 114, 105, 116, 121, 32, 40, 50, 48, 52, 56, 41, 48, 30, 23, 13, 57, 57, 49, 50, 50, 52, 49, 55, 53, 48, 53, 49, 90, 23, 13, 49, 57, 49, 50, 50, 52, 49, 56, 50, 48, 53, 49, 90, 48, -127, -76, 49, 20, 48, 18, 6, 3, 85, 4, 10, 19, 11, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 49, 64, 48, 62, 6, 3, 85, 4, 11, 20, 55, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 67, 80, 83, 95, 50, 48, 52, 56, 32, 105, 110, 99, 111, 114, 112, 46, 32, 98, 121, 32, 114, 101, 102, 46, 32, 40, 108, 105, 109, 105, 116, 115, 32, 108, 105, 97, 98, 46, 41, 49, 37, 48, 35, 6, 3, 85, 4, 11, 19, 28, 40, 99, 41, 32, 49, 57, 57, 57, 32, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 76, 105, 109, 105, 116, 101, 100, 49, 51, 48, 49, 6, 3, 85, 4, 3, 19, 42, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 32, 65, 117, 116, 104, 111, 114, 105, 116, 121, 32, 40, 50, 48, 52, 56, 41, 48, -126, 1, 34, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0, 3, -126, 1, 15, 0, 48, -126, 1, 10, 2, -126, 1, 1, 0, -83, 77, 75, -87, 18, -122, -78, -22, -93, 32, 7, 21, 22, 100, 42, 43, 75, -47, -65, 11, 74, 77, -114, -19, -128, 118, -91, 103, -73, 120, 64, -64, 115, 66, -56, 104, -64, -37, 83, 43, -35, 94, -72, 118, -104, 53, -109, -117, 26, -99, 124, 19, 58, 14, 31, 91, -73, 30, -49, -27, 36, 20, 30, -79, -127, -87, -115, 125, -72, -52, 107, 75, 3, -15, 2, 12, -36, -85, -91, 64, 36, 0, 127, 116, -108, -95, -99, 8, 41, -77, -120, 11, -11, -121, 119, -99, 85, -51, -28, -61, 126, -41, 106, 100, -85, -123, 20, -122, -107, 91, -105, 50, 80, 111, 61, -56, -70, 102, 12, -29, -4, -67, -72, 73, -63, 118, -119, 73, 25, -3, -64, -88, -67, -119, -93, 103, 47, -58, -97, -68, 113, 25, 96, -72, 45, -23, 44, -55, -112, 118, 102, 123, -108, -30, -81, 120, -42, 101, 83, 93, 60, -42, -100, -78, -49, 41, 3, -7, 47, -92, 80, -78, -44, 72, -50, 5, 50, 85, -118, -3, -78, 100, 76, 14, -28, -104, 7, 117, -37, 127, -33, -71, 8, 85, 96, -123, 48, 41, -7, 123, 72, -92, 105, -122, -29, 53, 63, 30, -122, 93, 122, 122, 21, -67, -17, 0, -114, 21, 34, 84, 23, 0, -112, 38, -109, -68, 14, 73, 104, -111, -65, -8, 71, -45, -99, -107, 66, -63, 14, 77, -33, 111, 38, -49, -61, 24, 33, 98, 102, 67, 112, -42, -43, -64, 7, -31, 2, 3, 1, 0, 1, -93, 116, 48, 114, 48, 17, 6, 9, 96, -122, 72, 1, -122, -8, 66, 1, 1, 4, 4, 3, 2, 0, 7, 48, 31, 6, 3, 85, 29, 35, 4, 24, 48, 22, -128, 20, 85, -28, -127, -47, 17, -128, -66, -40, -119, -71, 8, -93, 49, -7, -95, 36, 9, 22, -71, 112, 48, 29, 6, 3, 85, 29, 14, 4, 22, 4, 20, 85, -28, -127, -47, 17, -128, -66, -40, -119, -71, 8, -93, 49, -7, -95, 36, 9, 22, -71, 112, 48, 29, 6, 9, 42, -122, 72, -122, -10, 125, 7, 65, 0, 4, 16, 48, 14, 27, 8, 86, 53, 46, 48, 58, 52, 46, 48, 3, 2, 4, -112, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 5, 5, 0, 3, -126, 1, 1, 0, 89, 71, -84, 33, -124, -118, 23, -55, -100, -119, 83, 30, -70, -128, -123, 26, -58, 60, 78, 62, -79, -100, -74, 124, -58, -110, 93, 24, 100, 2, -29, -45, 6, 8, 17, 97, 124, 99, -29, 43, -99, 49, 3, 112, 118, -46, -93, 40, -96, -12, -69, -102, 99, 115, -19, 109, -27, 42, -37, -19, 20, -87, 43, -58, 54, 17, -48, 43, -21, 7, -117, -91, -38, -98, 92, 25, -99, 86, 18, -11, 84, 41, -56, 5, -19, -78, 18, 42, -115, -12, 3, 27, -1, -25, -110, 16, -121, -80, 58, -75, -61, -99, 5, 55, 18, -93, -57, -12, 21, -71, -43, -92, 57, 22, -101, 83, 58, 35, -111, -15, -88, -126, -94, 106, -120, 104, -63, 121, 2, 34, -68, -86, -90, -42, -82, -33, -80, 20, 95, -72, -121, -48, -35, 124, 127, 123, -1, -81, 28, -49, -26, -37, 7, -83, 94, -37, -123, -99, -48, 43, 13, 51, -37, 4, -47, -26, 73, 64, 19, 43, 118, -5, 62, -23, -100, -119, 15, 21, -50, 24, -80, -123, 120, 33, 79, 107, 79, 14, -6, 54, 103, -51, 7, -14, -1, 8, -48, -30, -34, -39, -65, 42, -81, -72, -121, -122, 33, 60, 4, -54, -73, -108, 104, 127, -49, 60, -23, -104, -41, 56, -1, -20, -64, -39, 80, -16, 46, 75, 88, -82, 70, 111, -48, 46, -61, 96, -38, 114, 85, 114, -67, 76, 69, -98, 97, -70, -65, -124, -127, -110, 3, -47, -46, 105, 124, -59 },
+    };
+
+    /**
+     * ASN1-encoded trusted certificate #946059622 for Entrust.net. This
+     * certificate uses the TELETEX encoding for its X509 name.
+     */
+    private final byte[] trustedCert = new byte[] { 48, -126, 4, 92, 48, -126, 3, 68, -96, 3, 2, 1, 2, 2, 4, 56, 99, -71, 102, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 5, 5, 0, 48, -127, -76, 49, 20, 48, 18, 6, 3, 85, 4, 10, 19, 11, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 49, 64, 48, 62, 6, 3, 85, 4, 11, 20, 55, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 67, 80, 83, 95, 50, 48, 52, 56, 32, 105, 110, 99, 111, 114, 112, 46, 32, 98, 121, 32, 114, 101, 102, 46, 32, 40, 108, 105, 109, 105, 116, 115, 32, 108, 105, 97, 98, 46, 41, 49, 37, 48, 35, 6, 3, 85, 4, 11, 19, 28, 40, 99, 41, 32, 49, 57, 57, 57, 32, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 76, 105, 109, 105, 116, 101, 100, 49, 51, 48, 49, 6, 3, 85, 4, 3, 19, 42, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 32, 65, 117, 116, 104, 111, 114, 105, 116, 121, 32, 40, 50, 48, 52, 56, 41, 48, 30, 23, 13, 57, 57, 49, 50, 50, 52, 49, 55, 53, 48, 53, 49, 90, 23, 13, 49, 57, 49, 50, 50, 52, 49, 56, 50, 48, 53, 49, 90, 48, -127, -76, 49, 20, 48, 18, 6, 3, 85, 4, 10, 19, 11, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 49, 64, 48, 62, 6, 3, 85, 4, 11, 20, 55, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 67, 80, 83, 95, 50, 48, 52, 56, 32, 105, 110, 99, 111, 114, 112, 46, 32, 98, 121, 32, 114, 101, 102, 46, 32, 40, 108, 105, 109, 105, 116, 115, 32, 108, 105, 97, 98, 46, 41, 49, 37, 48, 35, 6, 3, 85, 4, 11, 19, 28, 40, 99, 41, 32, 49, 57, 57, 57, 32, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 76, 105, 109, 105, 116, 101, 100, 49, 51, 48, 49, 6, 3, 85, 4, 3, 19, 42, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 32, 65, 117, 116, 104, 111, 114, 105, 116, 121, 32, 40, 50, 48, 52, 56, 41, 48, -126, 1, 34, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0, 3, -126, 1, 15, 0, 48, -126, 1, 10, 2, -126, 1, 1, 0, -83, 77, 75, -87, 18, -122, -78, -22, -93, 32, 7, 21, 22, 100, 42, 43, 75, -47, -65, 11, 74, 77, -114, -19, -128, 118, -91, 103, -73, 120, 64, -64, 115, 66, -56, 104, -64, -37, 83, 43, -35, 94, -72, 118, -104, 53, -109, -117, 26, -99, 124, 19, 58, 14, 31, 91, -73, 30, -49, -27, 36, 20, 30, -79, -127, -87, -115, 125, -72, -52, 107, 75, 3, -15, 2, 12, -36, -85, -91, 64, 36, 0, 127, 116, -108, -95, -99, 8, 41, -77, -120, 11, -11, -121, 119, -99, 85, -51, -28, -61, 126, -41, 106, 100, -85, -123, 20, -122, -107, 91, -105, 50, 80, 111, 61, -56, -70, 102, 12, -29, -4, -67, -72, 73, -63, 118, -119, 73, 25, -3, -64, -88, -67, -119, -93, 103, 47, -58, -97, -68, 113, 25, 96, -72, 45, -23, 44, -55, -112, 118, 102, 123, -108, -30, -81, 120, -42, 101, 83, 93, 60, -42, -100, -78, -49, 41, 3, -7, 47, -92, 80, -78, -44, 72, -50, 5, 50, 85, -118, -3, -78, 100, 76, 14, -28, -104, 7, 117, -37, 127, -33, -71, 8, 85, 96, -123, 48, 41, -7, 123, 72, -92, 105, -122, -29, 53, 63, 30, -122, 93, 122, 122, 21, -67, -17, 0, -114, 21, 34, 84, 23, 0, -112, 38, -109, -68, 14, 73, 104, -111, -65, -8, 71, -45, -99, -107, 66, -63, 14, 77, -33, 111, 38, -49, -61, 24, 33, 98, 102, 67, 112, -42, -43, -64, 7, -31, 2, 3, 1, 0, 1, -93, 116, 48, 114, 48, 17, 6, 9, 96, -122, 72, 1, -122, -8, 66, 1, 1, 4, 4, 3, 2, 0, 7, 48, 31, 6, 3, 85, 29, 35, 4, 24, 48, 22, -128, 20, 85, -28, -127, -47, 17, -128, -66, -40, -119, -71, 8, -93, 49, -7, -95, 36, 9, 22, -71, 112, 48, 29, 6, 3, 85, 29, 14, 4, 22, 4, 20, 85, -28, -127, -47, 17, -128, -66, -40, -119, -71, 8, -93, 49, -7, -95, 36, 9, 22, -71, 112, 48, 29, 6, 9, 42, -122, 72, -122, -10, 125, 7, 65, 0, 4, 16, 48, 14, 27, 8, 86, 53, 46, 48, 58, 52, 46, 48, 3, 2, 4, -112, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 5, 5, 0, 3, -126, 1, 1, 0, 89, 71, -84, 33, -124, -118, 23, -55, -100, -119, 83, 30, -70, -128, -123, 26, -58, 60, 78, 62, -79, -100, -74, 124, -58, -110, 93, 24, 100, 2, -29, -45, 6, 8, 17, 97, 124, 99, -29, 43, -99, 49, 3, 112, 118, -46, -93, 40, -96, -12, -69, -102, 99, 115, -19, 109, -27, 42, -37, -19, 20, -87, 43, -58, 54, 17, -48, 43, -21, 7, -117, -91, -38, -98, 92, 25, -99, 86, 18, -11, 84, 41, -56, 5, -19, -78, 18, 42, -115, -12, 3, 27, -1, -25, -110, 16, -121, -80, 58, -75, -61, -99, 5, 55, 18, -93, -57, -12, 21, -71, -43, -92, 57, 22, -101, 83, 58, 35, -111, -15, -88, -126, -94, 106, -120, 104, -63, 121, 2, 34, -68, -86, -90, -42, -82, -33, -80, 20, 95, -72, -121, -48, -35, 124, 127, 123, -1, -81, 28, -49, -26, -37, 7, -83, 94, -37, -123, -99, -48, 43, 13, 51, -37, 4, -47, -26, 73, 64, 19, 43, 118, -5, 62, -23, -100, -119, 15, 21, -50, 24, -80, -123, 120, 33, 79, 107, 79, 14, -6, 54, 103, -51, 7, -14, -1, 8, -48, -30, -34, -39, -65, 42, -81, -72, -121, -122, 33, 60, 4, -54, -73, -108, 104, 127, -49, 60, -23, -104, -41, 56, -1, -20, -64, -39, 80, -16, 46, 75, 88, -82, 70, 111, -48, 46, -61, 96, -38, 114, 85, 114, -67, 76, 69, -98, 97, -70, -65, -124, -127, -110, 3, -47, -46, 105, 124, -59 };
+
+    public void testTrustAndRemoteCertificatesWithDifferentEncodings()
+            throws IOException, CertificateException, KeyStoreException,
+            InvalidAlgorithmParameterException, CertPathValidatorException {
+
+        X509CertPathImpl certPath = new X509CertPathImpl(Arrays.asList(
+                new X509CertImpl(serviceSprintComCertChain[0]),
+                new X509CertImpl(serviceSprintComCertChain[1]),
+                new X509CertImpl(serviceSprintComCertChain[2])));
+
+        Set<TrustAnchor> trustAnchors = new HashSet<TrustAnchor>();
+        trustAnchors.add(new TrustAnchor(new X509CertificateObject(
+                new X509CertificateStructure(
+                        (ASN1Sequence) new ASN1InputStream(trustedCert).readObject())), null));
+
+        IndexedPKIXParameters indexedPKIXParameters = new IndexedPKIXParameters(trustAnchors);
+        indexedPKIXParameters.setRevocationEnabled(false);
+
+        new PKIXCertPathValidatorSpi().engineValidate(certPath, indexedPKIXParameters);
+        // completing normally indicates that the certificate was valid
+    }
+}
diff --git a/libcore/security/src/test/java/tests/security/AllTests.java b/libcore/security/src/test/java/tests/security/AllTests.java
index 2a69b59..a88cc0e 100644
--- a/libcore/security/src/test/java/tests/security/AllTests.java
+++ b/libcore/security/src/test/java/tests/security/AllTests.java
@@ -32,6 +32,7 @@
         TestSuite suite = tests.TestSuiteFactory.createTestSuite("All security test suites");
         // $JUnit-BEGIN$
         suite.addTest(org.apache.harmony.security.tests.java.security.AllTests.suite());
+        suite.addTest(org.bouncycastle.jce.provider.AllTests.suite());
         suite.addTest(tests.api.java.security.AllTests.suite());
         suite.addTest(tests.java.security.AllTests.suite());
     
diff --git a/libcore/support/src/test/java/tests/resources/EmptyEntries_signed.jar b/libcore/support/src/test/java/tests/resources/EmptyEntries_signed.jar
new file mode 100644
index 0000000..237d244
--- /dev/null
+++ b/libcore/support/src/test/java/tests/resources/EmptyEntries_signed.jar
Binary files differ
diff --git a/libcore/support/src/test/java/tests/support/Support_TestWebServer.java b/libcore/support/src/test/java/tests/support/Support_TestWebServer.java
index 8ee7248..609e993 100644
--- a/libcore/support/src/test/java/tests/support/Support_TestWebServer.java
+++ b/libcore/support/src/test/java/tests/support/Support_TestWebServer.java
@@ -19,9 +19,9 @@
 import java.io.*;
 import java.lang.Thread;
 import java.net.*;
-import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.logging.Logger;
 
 /**
@@ -42,6 +42,10 @@
     /* Where worker threads stand idle */
     Vector threads = new Vector();
 
+    /** maps the recently requested URLs to the full request snapshot */
+    private final Map<String, Request> pathToRequest
+            = new ConcurrentHashMap<String, Request>();
+
     /* List of all active worker threads */
     Vector activeThreads = new Vector();
 
@@ -206,7 +210,7 @@
      * a redirect code with the Location response header set to the value
      * specified.
      * @param redirect The location to be redirected to
-     * @param redirectCode The code to send when redirecting
+     * @param code The code to send when redirecting
      */
     public void setRedirect(String redirect, int code) {
         redirectHost = redirect;
@@ -215,6 +219,14 @@
     }
 
     /**
+     * Returns a map from recently-requested paths (like "/index.html") to a
+     * snapshot of the request data.
+     */
+    public Map<String, Request> pathToRequest() {
+        return pathToRequest;
+    }
+
+    /**
      * Cause the thread accepting connections on the server socket to close
      */
     public void close() {
@@ -328,6 +340,28 @@
     static final byte[] EOL = {(byte)'\r', (byte)'\n' };
 
     /**
+     * An immutable snapshot of an HTTP request.
+     */
+    public static class Request {
+        private final String path;
+        private final Map<String, String> headers;
+        // TODO: include posted content?
+
+        public Request(String path, Map<String, String> headers) {
+            this.path = path;
+            this.headers = new LinkedHashMap<String, String>(headers);
+        }
+
+        public String getPath() {
+            return path;
+        }
+
+        public Map<String, String> getHeaders() {
+            return headers;
+        }
+    }
+
+    /**
      * The worker thread handles all interactions with a current open
      * connection. If pipelining is turned on, this will allow this
      * thread to continuously operate on numerous requests before the
@@ -347,6 +381,9 @@
         /* Reference to current requests test file/data */
         private String testID;
 
+        /* The requested path, such as "/test1" */
+        private String path;
+
         /* Reference to test number from testID */
         private int testNum;
 
@@ -359,7 +396,7 @@
         boolean running = false;
 
         /* Request headers are stored here */
-        private Hashtable<String, String> headers = new Hashtable<String, String>();
+        private Map<String, String> headers = new LinkedHashMap<String, String>();
 
         /* Create a new worker thread */
         Worker() {
@@ -559,10 +596,8 @@
                     i++;
                 }
 
-                testID = new String(buf, 0, index, i-index);
-                if (testID.startsWith("/")) {
-                    testID = testID.substring(1);
-                }
+                path = new String(buf, 0, index, i-index);
+                testID = path.substring(1);
 
                 return nread;
             }
@@ -601,7 +636,7 @@
             while (buf[i] == ' ') {
                 i++;
             }
-            String headerValue = new String(buf, i, nread-1);
+            String headerValue = new String(buf, i, nread-i);
 
             headers.put(headerName, headerValue);
             return nread;
@@ -666,6 +701,8 @@
                     // If status line found, read any headers
                     nread = readHeaders(is);
 
+                    pathToRequest().put(path, new Request(path, headers));
+
                     // Then read content (if any)
                     // TODO handle chunked encoding from the client
                     if (headers.get(requestHeaders[REQ_CONTENT_LENGTH]) != null) {
diff --git a/libcore/support/src/test/java/tests/util/PrefsTester.java b/libcore/support/src/test/java/tests/util/PrefsTester.java
new file mode 100644
index 0000000..047b357
--- /dev/null
+++ b/libcore/support/src/test/java/tests/util/PrefsTester.java
@@ -0,0 +1,73 @@
+/* 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.
+ */
+
+package tests.util;
+
+import java.util.prefs.BackingStoreException;
+import java.util.prefs.Preferences;
+import java.util.Arrays;
+
+/**
+ * Prepares the shared preferences store for a test by wiping preference data
+ * before and after the test. Sample usage:
+ * <pre>
+ * public void MyPreferencesTest extends TestCase {
+ *     private final PrefsTester prefsTester = new PrefsTester();
+ *
+ *     public void setUp() throws BackingStoreException {
+ *         super.setUp();
+ *         prefsTester.setUp();
+ *     }
+ *
+ *     public void tearDown() throws BackingStoreException {
+ *         prefsTester.tearDown();
+ *         super.tearDown();
+ *     }
+ *
+ *     ...
+ * }</pre>
+ *
+ * <p>Once the preferences classes have been initialized, the path where their
+ * data is stored is fixed. For that reason, every test that reads or writes
+ * preferences must first prepare preferences for testing by using this class.
+ */
+public final class PrefsTester {
+
+    static {
+        String tmp = System.getProperty("java.io.tmpdir");
+        System.setProperty("user.home", tmp);
+        System.setProperty("java.home", tmp);
+    }
+
+    public void setUp() throws BackingStoreException {
+        clear();
+    }
+
+    public void tearDown() throws BackingStoreException {
+        clear();
+    }
+
+    private void clear() throws BackingStoreException {
+        for (Preferences root : Arrays .asList(
+                Preferences.systemRoot(), Preferences.userRoot())) {
+            for (String child : root.childrenNames()) {
+                root.node(child).removeNode();
+            }
+            root.clear();
+            root.flush();
+        }
+    }
+}
diff --git a/libcore/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp b/libcore/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp
index 8f36632..87f2af3 100644
--- a/libcore/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp
+++ b/libcore/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp
@@ -421,7 +421,7 @@
 static int sslCreateAppData(SSL* ssl) {
     APP_DATA* data = (APP_DATA*) malloc(sizeof(APP_DATA));
 
-    memset(data, sizeof(APP_DATA), 0);
+    memset(data, 0, sizeof(APP_DATA));
 
     data->aliveAndKicking = 1;
     data->waitingThreads = 0;
diff --git a/tests/044-proxy/expected.txt b/tests/044-proxy/expected.txt
index 255cf99..69a94f2 100644
--- a/tests/044-proxy/expected.txt
+++ b/tests/044-proxy/expected.txt
@@ -45,10 +45,10 @@
  (no args)
 Got expected ie
 
-Proxy methods: [public native boolean .$Proxy0.equals(java.lang.Object), public native int .$Proxy0.hashCode(), public native java.lang.String .$Proxy0.toString(), public native int .$Proxy0.rectangle(int,int), public native int .$Proxy0.square(int,int), public native int .$Proxy0.trapezoid(int,double,int), public native java.lang.String .$Proxy0.blob(), public native void .$Proxy0.circle(int), public native void .$Proxy0.upCheck(), public native void .$Proxy0.upChuck(), public native double .$Proxy0.blue(int), public native R0aa .$Proxy0.checkMe(), public native int .$Proxy0.green(double), public native int .$Proxy0.mauve(java.lang.String), public native int .$Proxy0.red(float)]
+Proxy methods: [public native boolean $Proxy0.equals(java.lang.Object), public native int $Proxy0.hashCode(), public native java.lang.String $Proxy0.toString(), public native int $Proxy0.rectangle(int,int), public native int $Proxy0.square(int,int), public native int $Proxy0.trapezoid(int,double,int), public native java.lang.String $Proxy0.blob(), public native void $Proxy0.circle(int), public native void $Proxy0.upCheck(), public native void $Proxy0.upChuck(), public native double $Proxy0.blue(int), public native R0aa $Proxy0.checkMe(), public native int $Proxy0.green(double), public native int $Proxy0.mauve(java.lang.String), public native int $Proxy0.red(float)]
 Decl annos: []
 Param annos (1) : [[]]
-Proxy fields: [private static [[Ljava.lang.Throwable; .$Proxy0.throws]
+Proxy fields: [private static [[Ljava.lang.Throwable; $Proxy0.throws]
 Dupe threw expected exception
 Clash threw expected exception
 Clash2 threw expected exception
diff --git a/tools/gclog.py b/tools/gclog.py
index 4696965..4d5b704 100755
--- a/tools/gclog.py
+++ b/tools/gclog.py
@@ -15,8 +15,6 @@
 # limitations under the License.
 
 #
-# Version 1.0, 29-Apr-2009
-#
 # Parse event log output, looking for GC events.  Format them for human
 # consumption.
 #
@@ -28,10 +26,15 @@
 # The data is generated by dalvik/vm/alloc/HeapDebug.c.
 #
 
+import getopt
+import sys
 import os
 import re
 import time
 
+DEBUG = False       # DEBUG is a global variable
+
+
 def unfloat12(f12):
     """Unpack a float12 value"""
     if f12 < 0:
@@ -128,36 +131,41 @@
     return ( footprint, total, limit, bytes )
 
 
-def handleGcInfo(timestamp, pid, values):
+def handleGcInfo(procFilter, timestamp, pid, values):
     """Handle a single dvm_gc_info event"""
 
     pid = int(pid)
 
     global_info = parseGlobalInfo(values[0])
+
+    if len(procFilter) > 0:
+        if global_info[0] != procFilter:
+            return
+
     heap_stats = parseAggHeapStats(values[1])
     zygote = parseZygoteStats(values[2])
     external = parseExternalStats(values[3])
 
-    debug = False
-    if debug:
-        print "RAW: %s %s (%s,%s,%s,%s)" % \
-                (timestamp, pid, values[0], values[1], values[2], values[3])
-
-        print "> id=\"%s\" time=%d freed=%d" % (global_info[0], global_info[1], global_info[2])
-        print ">  freed=%d foot=%d allow=%d objs=%d bytes=%d" % \
-                (heap_stats[0], heap_stats[1], heap_stats[2], heap_stats[3], heap_stats[4])
-        print ">  soft=%d act=%d allow=%d objs=%d bytes=%d" % \
-                (zygote[0], zygote[1], zygote[2], zygote[3], zygote[4])
-        print ">  foot=%d total=%d limit=%d alloc=%d" % \
-                (external[0], external[1], external[2], external[3])
-
     print "%s %s(%d) softlim=%dKB, extlim=%dKB, extalloc=%dKB" % \
             (timestamp, global_info[0], pid, zygote[0]/1024, external[2]/1024, external[3]/1024)
+
+    if DEBUG:
+        # print "RAW: %s %s (%s,%s,%s,%s)" % \
+        #        (timestamp, pid, values[0], values[1], values[2], values[3])
+
+        print "+ id=\"%s\" time=%d freed=%d" % (global_info[0], global_info[1], global_info[2])
+        print "+  freed=%d foot=%d allow=%d objs=%d bytes=%d" % \
+                (heap_stats[0], heap_stats[1], heap_stats[2], heap_stats[3], heap_stats[4])
+        print "+  soft=%d act=%d allow=%d objs=%d bytes=%d" % \
+                (zygote[0], zygote[1], zygote[2], zygote[3], zygote[4])
+        print "+  foot=%d total=%d limit=%d alloc=%d" % \
+                (external[0], external[1], external[2], external[3])
+
     print "  freed %d objects / %d bytes in %dms" % \
             (heap_stats[0], global_info[2], global_info[1])
 
 
-def filterInput(logPipe):
+def filterInput(logPipe, processFilter):
     """Loop until EOF, pulling out GC events"""
 
     # 04-29 20:31:00.334 I/dvm_gc_info(   69): [8320808730292729543,-8916699241518090181,-4006371297196337158,8165229]
@@ -182,18 +190,41 @@
             #print "no match on %s" % line.strip()
             continue
         else:
-            handleGcInfo(match.group(1), match.group(2), ( match.group(3), \
+            handleGcInfo(processFilter, match.group(1), match.group(2), ( match.group(3), \
                     match.group(4), match.group(5), match.group(6) ) )
 
+def PrintUsage():
+  print "usage: %s [-p procFilter] [-d]" % sys.argv[0]
+
+
 def start():
     """Entry point"""
 
+    global DEBUG
+
+    procFilter = ""
+
+    opts, args = getopt.getopt(sys.argv[1:], "hdp:")
+
+    for opt, val in opts:
+        if opt == "-h":
+            PrintUsage()
+            sys.exit(2)
+        elif opt == "-p":
+            procFilter = val
+        elif opt == "-d":
+            DEBUG = True
+
+    print "procfilter = %s" % procFilter
+    print "DEBUG = %s" % DEBUG
+
     # launch a logcat and read from it
     command = 'adb logcat -v time -b events'
     logPipe = os.popen(command)
 
+
     try:
-        filterInput(logPipe)
+        filterInput(logPipe, procFilter)
     except KeyboardInterrupt, err:
         print "Stopping on keyboard interrupt."
 
diff --git a/vm/CheckJni.c b/vm/CheckJni.c
index 2e3b1c1..bc90527 100644
--- a/vm/CheckJni.c
+++ b/vm/CheckJni.c
@@ -998,7 +998,7 @@
     void* originalPtr = (void*) pExtra->originalPtr;
     size_t len = pExtra->originalLen;
 
-    memset(dataBuf, len, 0xdd);
+    memset(dataBuf, 0xdd, len);
     free(fullBuf);
     return originalPtr;
 }
@@ -2607,4 +2607,3 @@
     pVm->baseFuncTable = pVm->funcTable;
     pVm->funcTable = &gCheckInvokeInterface;
 }
-
diff --git a/vm/Dvm.mk b/vm/Dvm.mk
index 66ada15..96f6dac 100644
--- a/vm/Dvm.mk
+++ b/vm/Dvm.mk
@@ -180,6 +180,7 @@
 	native/org_apache_harmony_dalvik_ddmc_DdmServer.c \
 	native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.c \
 	native/sun_misc_Unsafe.c \
+	native/SystemThread.c \
 	oo/AccessCheck.c \
 	oo/Array.c \
 	oo/Class.c \
@@ -195,13 +196,11 @@
 
 ifeq ($(WITH_JIT_TUNING),true)
   LOCAL_CFLAGS += -DWITH_JIT_TUNING
+  # NOTE: Turn on assertion for JIT for now
+  LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1 -DLOG_NDEBUG=1 -DWITH_DALVIK_ASSERT
 endif
 
 ifeq ($(WITH_JIT),true)
-  # NOTE: Turn on assertion for JIT for now
-  LOCAL_CFLAGS += -DWITH_DALVIK_ASSERT
-  # NOTE: Also turn on tuning when JIT is enabled for now
-  LOCAL_CFLAGS += -DWITH_JIT_TUNING
   LOCAL_CFLAGS += -DWITH_JIT
   LOCAL_SRC_FILES += \
 	../dexdump/OpCodeNames.c \
diff --git a/vm/Globals.h b/vm/Globals.h
index e1a91de..9b12d84 100644
--- a/vm/Globals.h
+++ b/vm/Globals.h
@@ -633,6 +633,8 @@
      */
     pid_t systemServerPid;
 
+    int kernelGroupScheduling;
+
 //#define COUNT_PRECISE_METHODS
 #ifdef COUNT_PRECISE_METHODS
     PointerSet* preciseMethods;
diff --git a/vm/Init.c b/vm/Init.c
index 45c66e1..c46de25 100644
--- a/vm/Init.c
+++ b/vm/Init.c
@@ -1117,6 +1117,14 @@
     }
 #endif
 
+    /* Configure group scheduling capabilities */
+    if (!access("/dev/cpuctl/tasks", F_OK)) {
+        LOGV("Using kernel group scheduling");
+        gDvm.kernelGroupScheduling = 1;
+    } else {
+        LOGV("Using kernel scheduler policies");
+    }
+
     /* configure signal handling */
     if (!gDvm.reduceSignals)
         blockSignals();
diff --git a/vm/Thread.c b/vm/Thread.c
index 6a1e9aa..be3e952 100644
--- a/vm/Thread.c
+++ b/vm/Thread.c
@@ -18,6 +18,7 @@
  * Thread support.
  */
 #include "Dalvik.h"
+#include "native/SystemThread.h"
 
 #include "utils/threads.h"      // need Android thread priorities
 
@@ -29,6 +30,8 @@
 #include <errno.h>
 #include <fcntl.h>
 
+#include <cutils/sched_policy.h>
+
 #if defined(HAVE_PRCTL)
 #include <sys/prctl.h>
 #endif
@@ -531,7 +534,7 @@
     u8 startWhen = 0;       // init req'd to placate gcc
     int sleepIter = 0;
     int cc;
-    
+
     do {
         cc = pthread_mutex_trylock(&gDvm._threadSuspendLock);
         if (cc != 0) {
@@ -1295,10 +1298,18 @@
     assert(threadObj != NULL);
 
     if(gDvm.zygote) {
-        dvmThrowException("Ljava/lang/IllegalStateException;",
-            "No new threads in -Xzygote mode");
+        // Allow the sampling profiler thread. We shut it down before forking.
+        StringObject* nameStr = (StringObject*) dvmGetFieldObject(threadObj,
+                    gDvm.offJavaLangThread_name);
+        char* threadName = dvmCreateCstrFromString(nameStr);
+        bool profilerThread = strcmp(threadName, "SamplingProfiler") == 0;
+        free(threadName);
+        if (!profilerThread) {
+            dvmThrowException("Ljava/lang/IllegalStateException;",
+                "No new threads in -Xzygote mode");
 
-        goto fail;
+            goto fail;
+        }
     }
 
     self = dvmThreadSelf();
@@ -2232,6 +2243,9 @@
     dvmUnlockThreadList();
 
     setThreadSelf(NULL);
+
+    dvmDetachSystemThread(self);
+
     freeThread(self);
 }
 
@@ -2416,7 +2430,7 @@
         char proc[100];
         sprintf(proc, "/proc/%d/exe", getpid());
         int len;
-        
+
         len = readlink(proc, exePath, sizeof(exePath)-1);
         exePath[len] = '\0';
     }
@@ -2657,7 +2671,7 @@
         /* wait for the other thread to see the pending suspend */
         waitForThreadSuspend(self, thread);
 
-        LOG_THREAD("threadid=%d:   threadid=%d status=%d c=%d dc=%d isSusp=%d\n", 
+        LOG_THREAD("threadid=%d:   threadid=%d status=%d c=%d dc=%d isSusp=%d\n",
             self->threadId,
             thread->threadId, thread->status, thread->suspendCount,
             thread->dbgSuspendCount, thread->isSuspended);
@@ -3050,46 +3064,6 @@
 };
 
 /*
- * Change the scheduler cgroup of the current thread.
- *
- * Returns 0 on success.
- */
-int dvmChangeThreadSchedulerGroup(const char *cgroup)
-{
-#ifdef HAVE_ANDROID_OS
-    int fd;
-    char path[255];
-
-    snprintf(path, sizeof(path), "/dev/cpuctl/%s/tasks", (cgroup ? cgroup :""));
-
-    if ((fd = open(path, O_WRONLY)) < 0) {
-        int err = errno;
-#if ENABLE_CGROUP_ERR_LOGGING
-        LOGW("Unable to open %s (%s)\n", path, strerror(err));
-#endif
-        return -err;
-    }
-
-    if (write(fd, "0", 1) < 0) {
-        int err = errno;
-#if ENABLE_CGROUP_ERR_LOGGING
-        LOGW("Unable to move tid %d to cgroup %s (%s)\n",
-            dvmThreadSelf()->systemTid,
-            (cgroup ? cgroup : "<default>"), strerror(err));
-#endif
-        close(fd);
-        return -err;
-    }
-    close(fd);
-
-    return 0;
-
-#else // HAVE_ANDROID_OS
-    return 0;
-#endif
-}
-
-/*
  * Change the priority of a system thread to match that of the Thread object.
  *
  * We map a priority value from 1-10 to Linux "nice" values, where lower
@@ -3107,9 +3081,9 @@
     newNice = kNiceValues[newPriority-1];
 
     if (newNice >= ANDROID_PRIORITY_BACKGROUND) {
-        dvmChangeThreadSchedulerGroup("bg_non_interactive");
+        set_sched_policy(dvmGetSysThreadId(), SP_BACKGROUND);
     } else if (getpriority(PRIO_PROCESS, pid) >= ANDROID_PRIORITY_BACKGROUND) {
-        dvmChangeThreadSchedulerGroup(NULL);
+        set_sched_policy(dvmGetSysThreadId(), SP_FOREGROUND);
     }
 
     if (setpriority(PRIO_PROCESS, pid, newNice) != 0) {
@@ -3843,7 +3817,7 @@
      * through the actual ThreadGroups, but it should be
      * equivalent.
      *
-     * This assumes that the ThreadGroup class object is in 
+     * This assumes that the ThreadGroup class object is in
      * the root set, which should always be true;  it's
      * loaded by the built-in class loader, which is part
      * of the root set.
diff --git a/vm/Thread.h b/vm/Thread.h
index 50bf5a0..1bb5314 100644
--- a/vm/Thread.h
+++ b/vm/Thread.h
@@ -78,6 +78,11 @@
 #define kMaxStackSize       (256*1024 + STACK_OVERFLOW_RESERVE)
 
 /*
+ * System thread state. See native/SystemThread.h.
+ */
+typedef struct SystemThread SystemThread;
+
+/*
  * Our per-thread data.
  *
  * These are allocated on the system heap.
@@ -90,7 +95,7 @@
      * Thread's current status.  Can only be changed by the thread itself
      * (i.e. don't mess with this from other threads).
      */
-    ThreadStatus status;
+    volatile ThreadStatus status;
 
     /*
      * This is the number of times the thread has been suspended.  When the
@@ -214,6 +219,9 @@
     /* PC, saved on every instruction; redundant with StackSaveArea */
     const u2*   currentPc2;
 #endif
+
+    /* system thread state */
+    SystemThread* systemThread;
 } Thread;
 
 /* start point for an internal thread; mimics pthread args */
@@ -403,7 +411,7 @@
  * thread is part of the GC's root set.
  */
 bool dvmIsOnThreadList(const Thread* thread);
- 
+
 /*
  * Get/set the JNIEnv field.
  */
@@ -411,16 +419,10 @@
 INLINE void dvmSetThreadJNIEnv(Thread* self, JNIEnv* env) { self->jniEnv = env;}
 
 /*
- * Change the scheduler group of the current process
- */
-int dvmChangeThreadSchedulerGroup(const char *group);
-
-/*
  * Update the priority value of the underlying pthread.
  */
 void dvmChangeThreadPriority(Thread* thread, int newPriority);
 
-
 /*
  * Debug: dump information about a single thread.
  */
@@ -434,7 +436,6 @@
 void dvmDumpAllThreads(bool grabLock);
 void dvmDumpAllThreadsEx(const DebugOutputTarget* target, bool grabLock);
 
-
 #ifdef WITH_MONITOR_TRACKING
 /*
  * Track locks held by the current thread, along with the stack trace at
diff --git a/vm/alloc/Heap.c b/vm/alloc/Heap.c
index c548190..17d6a5c 100644
--- a/vm/alloc/Heap.c
+++ b/vm/alloc/Heap.c
@@ -27,6 +27,8 @@
 #include "utils/threads.h"      // need Android thread priorities
 #define kInvalidPriority        10000
 
+#include <cutils/sched_policy.h>
+
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <limits.h>
@@ -783,7 +785,7 @@
          */
 
         if (priorityResult >= ANDROID_PRIORITY_BACKGROUND) {
-            dvmChangeThreadSchedulerGroup(NULL);
+            set_sched_policy(dvmGetSysThreadId(), SP_FOREGROUND);
         }
 
         if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL) != 0) {
@@ -1036,7 +1038,7 @@
         }
 
         if (oldThreadPriority >= ANDROID_PRIORITY_BACKGROUND) {
-            dvmChangeThreadSchedulerGroup("bg_non_interactive");
+            set_sched_policy(dvmGetSysThreadId(), SP_BACKGROUND);
         }
     }
     gcElapsedTime = (dvmGetRelativeTimeUsec() - gcHeap->gcStartTime) / 1000;
diff --git a/vm/arch/x86/Call386ABI.S b/vm/arch/x86/Call386ABI.S
index 6cb680c..c98876c 100644
--- a/vm/arch/x86/Call386ABI.S
+++ b/vm/arch/x86/Call386ABI.S
@@ -145,7 +145,7 @@
     movl     %eax,(%ecx)
     jmp      cleanUpAndExit
 checkShort:
-    cmpl     $6,%eax  /* U2? */
+    cmpl     $6,%ebx  /* U2? */
     jne      isSignedShort
     movzwl   %ax,%eax
     movl     %eax,(%ecx)
@@ -153,6 +153,7 @@
 isSignedShort:
     /* Must be S2 */
     movswl   %ax,%eax
+    movl     %eax,(%ecx)
     jmp      cleanUpAndExit
 isFP:
     /* Is Float? */
diff --git a/vm/native/SystemThread.c b/vm/native/SystemThread.c
new file mode 100644
index 0000000..bd2be03
--- /dev/null
+++ b/vm/native/SystemThread.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SystemThread"
+
+/*
+ * System thread support.
+ */
+#include "Dalvik.h"
+#include "native/SystemThread.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+struct SystemThread {
+    /*
+     * /proc/PID/task/TID/stat. -1 if not opened yet. -2 indicates an error
+     * occurred while opening the file.
+     */
+    int statFile;
+
+    /* Offset of state char in stat file, last we checked. */
+    int stateOffset;
+};
+
+void dvmDetachSystemThread(Thread* thread) {
+    if (thread->systemThread != NULL) {
+        if (thread->systemThread->statFile > -1) {
+            close(thread->systemThread->statFile);
+        }
+        free(thread->systemThread);
+        thread->systemThread = NULL;
+    }
+}
+
+/* Converts a Linux thread state to a ThreadStatus. */
+static ThreadStatus stateToStatus(char state) {
+    switch (state) {
+        case 'R': return THREAD_RUNNING;    // running
+        case 'S': return THREAD_WAIT;       // sleeping in interruptible wait
+        case 'D': return THREAD_WAIT;       // uninterruptible disk sleep
+        case 'Z': return THREAD_ZOMBIE;     // zombie
+        case 'T': return THREAD_WAIT;       // traced or stopped on a signal
+        case 'W': return THREAD_WAIT;  // paging memory
+        default:
+            LOGE("Unexpected state: %c", state);
+            return THREAD_NATIVE;
+    }
+}
+
+/* Reads the state char starting from the beginning of the file. */
+static char readStateFromBeginning(SystemThread* thread) {
+    char buffer[256];
+    int size = read(thread->statFile, buffer, sizeof(buffer) - 1);
+    if (size <= 0) {
+        LOGE("read() returned %d: %s", size, strerror(errno));
+        return 0;
+    }
+    char* endOfName = (char*) memchr(buffer, ')', size);
+    if (endOfName == NULL) {
+        LOGE("End of executable name not found.");
+        return 0;
+    }
+    char* state = endOfName + 2;
+    if ((state - buffer) + 1 > size) {
+        LOGE("Unexpected EOF while trying to read stat file.");
+        return 0;
+    }
+    thread->stateOffset = state - buffer;
+    return *state;
+}
+
+/*
+ * Looks for the state char at the last place we found it. Read from the
+ * beginning if necessary.
+ */
+static char readStateRelatively(SystemThread* thread) {
+    char buffer[3];
+    // Position file offset at end of executable name.
+    int result = lseek(thread->statFile, thread->stateOffset - 2, SEEK_SET);
+    if (result < 0) {
+        LOGE("lseek() error.");
+        return 0;
+    }
+    int size = read(thread->statFile, buffer, sizeof(buffer));
+    if (size < (int) sizeof(buffer)) {
+        LOGE("Unexpected EOF while trying to read stat file.");
+        return 0;
+    }
+    if (buffer[0] != ')') {
+        // The executable name must have changed.
+        result = lseek(thread->statFile, 0, SEEK_SET);
+        if (result < 0) {
+            LOGE("lseek() error.");
+            return 0;
+        }
+        return readStateFromBeginning(thread);
+    }
+    return buffer[2];
+}
+
+ThreadStatus dvmGetSystemThreadStatus(Thread* thread) {
+    ThreadStatus status = thread->status;
+    if (status != THREAD_NATIVE) {
+        // Return cached status so we don't accidentally return THREAD_NATIVE.
+        return status;
+    }
+
+    if (thread->systemThread == NULL) {
+        thread->systemThread = (SystemThread*) malloc(sizeof(SystemThread));
+        if (thread->systemThread == NULL) {
+            LOGE("Couldn't allocate a SystemThread.");
+            return THREAD_NATIVE;
+        }
+        thread->systemThread->statFile = -1;
+    }
+
+    SystemThread* systemThread = thread->systemThread;
+    if (systemThread->statFile == -2) {
+        // We tried and failed to open the file earlier. Return current status.
+        return thread->status;
+    }
+
+    // Note: see "man proc" for the format of stat.
+    // The format is "PID (EXECUTABLE NAME) STATE_CHAR ...".
+    // Example: "15 (/foo/bar) R ..."
+    char state;
+    if (systemThread->statFile == -1) {
+        // We haven't tried to open the file yet. Do so.
+        char fileName[256];
+        sprintf(fileName, "/proc/self/task/%d/stat", thread->systemTid);
+        systemThread->statFile = open(fileName, O_RDONLY);
+        if (systemThread->statFile == -1) {
+            LOGE("Error opening %s: %s", fileName, strerror(errno));
+            systemThread->statFile = -2;
+            return thread->status;
+        }
+        state = readStateFromBeginning(systemThread);
+    } else {
+        state = readStateRelatively(systemThread);
+    }
+
+    if (state == 0) {
+        close(systemThread->statFile);
+        systemThread->statFile = -2;
+        return thread->status;
+    }
+    ThreadStatus nativeStatus = stateToStatus(state);
+
+    // The thread status could have changed from NATIVE.
+    status = thread->status;
+    return status == THREAD_NATIVE ? nativeStatus : status;
+}
diff --git a/vm/native/SystemThread.h b/vm/native/SystemThread.h
new file mode 100644
index 0000000..fb41b04
--- /dev/null
+++ b/vm/native/SystemThread.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * System thread support.
+ */
+#ifndef _DALVIK_SYSTEM_THREAD
+#define _DALVIK_SYSTEM_THREAD
+
+#include "Thread.h"
+
+/*
+ * Queries the system thread status for the given thread. If the thread is in
+ * native code, this function queries the system thread state and converts it
+ * to an equivalent ThreadStatus. If the system thread state is "paging",
+ * this function returns THREAD_WAIT. If the native status can't be read,
+ * this function returns THREAD_NATIVE. The thread list lock should be held
+ * when calling this function.
+ */
+ThreadStatus dvmGetSystemThreadStatus(Thread* thread);
+
+/*
+ * Frees system thread-specific state in the given thread. The thread list
+ * lock is *not* held when this function is invoked.
+ */
+void dvmDetachSystemThread(Thread* thread);
+
+#endif /*_DALVIK_SYSTEM_THREAD*/
diff --git a/vm/native/dalvik_system_SamplingProfiler.c b/vm/native/dalvik_system_SamplingProfiler.c
index 2381ade..5642bde 100644
--- a/vm/native/dalvik_system_SamplingProfiler.c
+++ b/vm/native/dalvik_system_SamplingProfiler.c
@@ -24,11 +24,12 @@
 
 #include "Dalvik.h"
 #include "native/InternalNativePriv.h"
+#include "native/SystemThread.h"
 
-// ~16k
+// ~20k
 #define INITIAL_CAPACITY 1024
 
-// ~64k
+// ~80k
 #define MAX_CAPACITY 4096
 
 typedef enum {
@@ -43,20 +44,27 @@
 typedef enum {
     /** Executing bytecode. */
     RUNNING_THREAD,
-    /** In a native method. */
-    NATIVE_THREAD,
     /** Waiting on a lock or VM resource. */
     SUSPENDED_THREAD
 } ThreadState;
 
 #define THREAD_STATE_SIZE (SUSPENDED_THREAD + 1)
 
+typedef enum {
+    /** This method is in the call stack. */
+    CALLING_METHOD,
+    /** VM is in this method. */
+    LEAF_METHOD
+} MethodState;
+
+#define METHOD_STATE_SIZE (LEAF_METHOD + 1)
+
 /** SampleSet entry. */
 typedef struct {
     /** Entry key. */
     const Method* method; // 4 bytes
     /** Sample counts for method divided by thread type and state. */
-    u2 counts[THREAD_TYPE_SIZE][THREAD_STATE_SIZE]; // 12 bytes
+    u2 counts[THREAD_TYPE_SIZE][THREAD_STATE_SIZE][METHOD_STATE_SIZE]; // 16B
 } MethodCount;
 
 /**
@@ -143,7 +151,8 @@
 
 /** Increments counter for method in set. */
 static void countMethod(SampleSet* set, const Method* method,
-        ThreadType threadType, ThreadState threadState) {
+        ThreadType threadType, ThreadState threadState,
+        MethodState methodState) {
     MethodCount* entries = set->entries;
     int start = hash(method) & set->mask;
     int i;
@@ -152,7 +161,7 @@
 
         if (entry->method == method) {
             // We found an existing entry.
-            entry->counts[threadType][threadState]++;
+            entry->counts[threadType][threadState][methodState]++;
             return;
         }
 
@@ -160,14 +169,15 @@
             // Add a new entry.
             if (set->size < set->maxSize) {
                 entry->method = method;
-                entry->counts[threadType][threadState] = 1;
+                entry->counts[threadType][threadState][methodState] = 1;
                 set->collisions += (i != start);
                 set->size++;
             } else {
                 if (set->capacity < MAX_CAPACITY) {
                     // The set is 3/4 full. Expand it, and then add the entry.
                     expand(set);
-                    countMethod(set, method, threadType, threadState);
+                    countMethod(set, method, threadType, threadState,
+                            methodState);
                 } else {
                     // Don't add any more entries.
                     // TODO: Should we replace the LRU entry?
@@ -193,10 +203,10 @@
         ? EVENT_THREAD : OTHER_THREAD;
 
     ThreadState threadState;
-    switch (thread->status) {
+    switch (dvmGetSystemThreadStatus(thread)) {
         case THREAD_RUNNING: threadState = RUNNING_THREAD; break;
-        case THREAD_NATIVE: threadState = NATIVE_THREAD; break;
-        default: threadState = SUSPENDED_THREAD;
+        case THREAD_NATIVE: return; // Something went wrong. Skip this thread.
+        default: threadState = SUSPENDED_THREAD; // includes PAGING
     }
 
     /*
@@ -213,13 +223,15 @@
         return;
     }
 
+    MethodState methodState = LEAF_METHOD;
     while (true) {
         StackSaveArea* saveArea = SAVEAREA_FROM_FP(currentFrame);
 
         const Method* method = saveArea->method;
         // Count the method now. We'll validate later that it's a real Method*.
         if (method != NULL) {
-            countMethod(set, method, threadType, threadState);
+            countMethod(set, method, threadType, threadState, methodState);
+            methodState = CALLING_METHOD;
         }
 
         void* callerFrame = saveArea->prevFrame;
@@ -398,7 +410,8 @@
 
         size += 2; // method name size
         size += wrapper->methodNameLength;
-        size += THREAD_TYPE_SIZE * THREAD_STATE_SIZE * 2; // sample counts
+        // sample counts
+        size += THREAD_TYPE_SIZE * THREAD_STATE_SIZE * METHOD_STATE_SIZE * 2;
         wrapper = wrapper->next;
     } while (wrapper != NULL);
 
@@ -451,11 +464,15 @@
                 wrapper->methodNameLength);
 
         // Sample counts.
-        u2 (*counts)[THREAD_STATE_SIZE] = wrapper->methodCount->counts;
-        int type, state;
+        u2 (*counts)[THREAD_STATE_SIZE][METHOD_STATE_SIZE]
+                = wrapper->methodCount->counts;
+        int type, threadState, methodState;
         for (type = 0; type < THREAD_TYPE_SIZE; type++)
-            for (state = 0; state < THREAD_STATE_SIZE; state++)
-                writeShort(offset, counts[type][state]);
+            for (threadState = 0; threadState < THREAD_STATE_SIZE;
+                    threadState++)
+                for (methodState = 0; methodState < METHOD_STATE_SIZE;
+                        methodState++)
+                    writeShort(offset, counts[type][threadState][methodState]);
 
         methodCount++;
         wrapper = wrapper->next;
@@ -489,13 +506,16 @@
      *  MethodEntry:
      *    method name length (2 bytes)
      *    UTF-8 method name
-     *    Counts (for event thread)
-     *    Counts (for other threads)
+     *    CountsByThreadState (for event thread)
+     *    CountsByThreadState (for other threads)
      *
-     *  Counts:
-     *    running count (2 bytes)
-     *    native count (2 bytes)
-     *    suspended count (2 bytes)
+     *  CountsByThreadState:
+     *    CountsByMethodState (for running threads)
+     *    CountsByMethodState (for suspended threads)
+     *
+     *  CountsByMethodState:
+     *    as calling method (2 bytes)
+     *    as leaf method (2 bytes)
      */
 
     SampleSet* set = (SampleSet*) args[0];
@@ -591,6 +611,17 @@
 }
 
 /**
+ * Frees native memory.
+ */
+static void Dalvik_dalvik_system_SamplingProfiler_free(const u4* args,
+        JValue* pResult) {
+    SampleSet* set = (SampleSet*) args[0];
+    free(set->entries);
+    free(set);
+    RETURN_VOID();
+}
+
+/**
  * Identifies the event thread.
  */
 static void Dalvik_dalvik_system_SamplingProfiler_setEventThread(const u4* args,
@@ -608,6 +639,7 @@
     { "size", "(I)I", Dalvik_dalvik_system_SamplingProfiler_size },
     { "sample", "(I)I", Dalvik_dalvik_system_SamplingProfiler_sample },
     { "snapshot", "(I)[B", Dalvik_dalvik_system_SamplingProfiler_snapshot },
+    { "free", "(I)V", Dalvik_dalvik_system_SamplingProfiler_free },
     { "allocate", "()I", Dalvik_dalvik_system_SamplingProfiler_allocate },
     { "setEventThread", "(ILjava/lang/Thread;)V",
             Dalvik_dalvik_system_SamplingProfiler_setEventThread },