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: <parent's absolute
- * path> + "/" + <node's name>. 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: <parent's
+ * absolute path> + "/" + <node's name>. 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 @@
* <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
* </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 @@
* <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
* </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>
* <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
* </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 "/<unnamed>". 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 "/<unnamed>". 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
- * "remaining" 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 > 0, it is guaranteed that the resulting array
- * contains at most n entries.
+ * <li>For n > 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 < 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 < 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 },