dexPaths);
+ }
}
diff --git a/dalvik/src/main/java/dalvik/system/BlockGuard.java b/dalvik/src/main/java/dalvik/system/BlockGuard.java
index b9de236c0..6426bd821 100644
--- a/dalvik/src/main/java/dalvik/system/BlockGuard.java
+++ b/dalvik/src/main/java/dalvik/system/BlockGuard.java
@@ -65,6 +65,11 @@ public interface Policy {
*/
void onNetwork();
+ /**
+ * Called on unbuffered input/ouput operations.
+ */
+ void onUnbufferedIO();
+
/**
* Returns the policy bitmask, for shipping over Binder calls
* to remote threads/processes and reinstantiating the policy
@@ -118,6 +123,7 @@ public String getMessage() {
public void onWriteToDisk() {}
public void onReadFromDisk() {}
public void onNetwork() {}
+ public void onUnbufferedIO() {}
public int getPolicyMask() {
return 0;
}
diff --git a/dalvik/src/main/java/dalvik/system/CloseGuard.java b/dalvik/src/main/java/dalvik/system/CloseGuard.java
index a45ffa10d..e718ee785 100644
--- a/dalvik/src/main/java/dalvik/system/CloseGuard.java
+++ b/dalvik/src/main/java/dalvik/system/CloseGuard.java
@@ -117,6 +117,16 @@ public final class CloseGuard {
*/
private static volatile Reporter REPORTER = new DefaultReporter();
+ /**
+ * The default {@link Tracker}.
+ */
+ private static final DefaultTracker DEFAULT_TRACKER = new DefaultTracker();
+
+ /**
+ * Hook for customizing how CloseGuard issues are tracked.
+ */
+ private static volatile Tracker currentTracker = DEFAULT_TRACKER;
+
/**
* Returns a CloseGuard instance. If CloseGuard is enabled, {@code
* #open(String)} can be used to set up the instance to warn on
@@ -138,6 +148,13 @@ public static void setEnabled(boolean enabled) {
ENABLED = enabled;
}
+ /**
+ * True if CloseGuard mechanism is enabled.
+ */
+ public static boolean isEnabled() {
+ return ENABLED;
+ }
+
/**
* Used to replace default Reporter used to warn of CloseGuard
* violations. Must be non-null.
@@ -156,6 +173,32 @@ public static Reporter getReporter() {
return REPORTER;
}
+ /**
+ * Sets the {@link Tracker} that is notified when resources are allocated and released.
+ *
+ * This is only intended for use by {@code dalvik.system.CloseGuardSupport} class and so
+ * MUST NOT be used for any other purposes.
+ *
+ * @throws NullPointerException if tracker is null
+ */
+ public static void setTracker(Tracker tracker) {
+ if (tracker == null) {
+ throw new NullPointerException("tracker == null");
+ }
+ currentTracker = tracker;
+ }
+
+ /**
+ * Returns {@link #setTracker(Tracker) last Tracker that was set}, or otherwise a default
+ * Tracker that does nothing.
+ *
+ *
This is only intended for use by {@code dalvik.system.CloseGuardSupport} class and so
+ * MUST NOT be used for any other purposes.
+ */
+ public static Tracker getTracker() {
+ return currentTracker;
+ }
+
private CloseGuard() {}
/**
@@ -178,6 +221,7 @@ public void open(String closer) {
}
String message = "Explicit termination method '" + closer + "' not called";
allocationSite = new Throwable(message);
+ currentTracker.open(allocationSite);
}
private Throwable allocationSite;
@@ -187,6 +231,7 @@ public void open(String closer) {
* finalization.
*/
public void close() {
+ currentTracker.close(allocationSite);
allocationSite = null;
}
@@ -208,11 +253,36 @@ public void warnIfOpen() {
REPORTER.report(message, allocationSite);
}
+ /**
+ * Interface to allow customization of tracking behaviour.
+ *
+ *
This is only intended for use by {@code dalvik.system.CloseGuardSupport} class and so
+ * MUST NOT be used for any other purposes.
+ */
+ public interface Tracker {
+ void open(Throwable allocationSite);
+ void close(Throwable allocationSite);
+ }
+
+ /**
+ * Default tracker which does nothing special and simply leaves it up to the GC to detect a
+ * leak.
+ */
+ private static final class DefaultTracker implements Tracker {
+ @Override
+ public void open(Throwable allocationSite) {
+ }
+
+ @Override
+ public void close(Throwable allocationSite) {
+ }
+ }
+
/**
* Interface to allow customization of reporting behavior.
*/
- public static interface Reporter {
- public void report (String message, Throwable allocationSite);
+ public interface Reporter {
+ void report (String message, Throwable allocationSite);
}
/**
diff --git a/dalvik/src/main/java/dalvik/system/DexFile.java b/dalvik/src/main/java/dalvik/system/DexFile.java
index f1ec29da7..2a95450da 100644
--- a/dalvik/src/main/java/dalvik/system/DexFile.java
+++ b/dalvik/src/main/java/dalvik/system/DexFile.java
@@ -21,7 +21,9 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import libcore.io.Libcore;
@@ -41,7 +43,6 @@ public final class DexFile {
private Object mCookie;
private Object mInternalCookie;
private final String mFileName;
- private final CloseGuard guard = CloseGuard.get();
/**
* Opens a DEX file from a given File object. This will usually be a ZIP/JAR
@@ -113,10 +114,15 @@ public DexFile(String fileName) throws IOException {
mCookie = openDexFile(fileName, null, 0, loader, elements);
mInternalCookie = mCookie;
mFileName = fileName;
- guard.open("close");
//System.out.println("DEX FILE cookie is " + mCookie + " fileName=" + fileName);
}
+ DexFile(ByteBuffer buf) throws IOException {
+ mCookie = openInMemoryDexFile(buf);
+ mInternalCookie = mCookie;
+ mFileName = null;
+ }
+
/**
* Opens a DEX file from a given filename, using a specified file
* to hold the optimized data.
@@ -148,6 +154,7 @@ private DexFile(String sourceName, String outputName, int flags, ClassLoader loa
}
mCookie = openDexFile(sourceName, outputName, flags, loader, elements);
+ mInternalCookie = mCookie;
mFileName = sourceName;
//System.out.println("DEX FILE cookie is " + mCookie + " sourceName=" + sourceName + " outputName=" + outputName);
}
@@ -231,7 +238,11 @@ public String getName() {
}
@Override public String toString() {
- return getName();
+ if (mFileName != null) {
+ return getName();
+ } else {
+ return "InMemoryDexFile[cookie=" + Arrays.toString((long[]) mCookie) + "]";
+ }
}
/**
@@ -250,7 +261,6 @@ public void close() throws IOException {
if (closeDexFile(mInternalCookie)) {
mInternalCookie = null;
}
- guard.close();
mCookie = null;
}
}
@@ -322,13 +332,13 @@ public Enumeration entries() {
/*
* Helper class.
*/
- private class DFEnum implements Enumeration {
+ private static class DFEnum implements Enumeration {
private int mIndex;
private String[] mNameList;
DFEnum(DexFile df) {
mIndex = 0;
- mNameList = getClassNameList(mCookie);
+ mNameList = getClassNameList(df.mCookie);
}
public boolean hasMoreElements() {
@@ -349,9 +359,6 @@ public String nextElement() {
*/
@Override protected void finalize() throws Throwable {
try {
- if (guard != null) {
- guard.warnIfOpen();
- }
if (mInternalCookie != null && !closeDexFile(mInternalCookie)) {
throw new AssertionError("Failed to close dex file in finalizer.");
}
@@ -379,6 +386,17 @@ private static Object openDexFile(String sourceName, String outputName, int flag
elements);
}
+ private static Object openInMemoryDexFile(ByteBuffer buf) throws IOException {
+ if (buf.isDirect()) {
+ return createCookieWithDirectBuffer(buf, buf.position(), buf.limit());
+ } else {
+ return createCookieWithArray(buf.array(), buf.position(), buf.limit());
+ }
+ }
+
+ private static native Object createCookieWithDirectBuffer(ByteBuffer buf, int start, int end);
+ private static native Object createCookieWithArray(byte[] buf, int start, int end);
+
/*
* Returns true if the dex file is backed by a valid oat file.
*/
@@ -418,6 +436,8 @@ public static native boolean isDexOptNeeded(String fileName)
throws FileNotFoundException, IOException;
/**
+ * No dexopt should (or can) be done to update the apk/jar.
+ *
* See {@link #getDexOptNeeded(String, String, int)}.
*
* @hide
@@ -425,48 +445,43 @@ public static native boolean isDexOptNeeded(String fileName)
public static final int NO_DEXOPT_NEEDED = 0;
/**
+ * dex2oat should be run to update the apk/jar from scratch.
+ *
* See {@link #getDexOptNeeded(String, String, int)}.
*
* @hide
*/
- public static final int DEX2OAT_NEEDED = 1;
+ public static final int DEX2OAT_FROM_SCRATCH = 1;
/**
+ * dex2oat should be run to update the apk/jar because the existing code
+ * is out of date with respect to the boot image.
+ *
* See {@link #getDexOptNeeded(String, String, int)}.
*
* @hide
*/
- public static final int PATCHOAT_NEEDED = 2;
+ public static final int DEX2OAT_FOR_BOOT_IMAGE = 2;
/**
+ * dex2oat should be run to update the apk/jar because the existing code
+ * is out of date with respect to the target compiler filter.
+ *
* See {@link #getDexOptNeeded(String, String, int)}.
*
* @hide
*/
- public static final int SELF_PATCHOAT_NEEDED = 3;
+ public static final int DEX2OAT_FOR_FILTER = 3;
/**
- * Returns whether the given filter is a valid filter.
+ * dex2oat should be run to update the apk/jar because the existing code
+ * is not relocated to match the boot image.
*
- * @hide
- */
- public native static boolean isValidCompilerFilter(String filter);
-
- /**
- * Returns whether the given filter is based on profiles.
+ * See {@link #getDexOptNeeded(String, String, int)}.
*
* @hide
*/
- public native static boolean isProfileGuidedCompilerFilter(String filter);
-
- /**
- * Returns the version of the compiler filter that is not based on profiles.
- * If the input is not a valid filter, or the filter is already not based on
- * profiles, this returns the input.
- *
- * @hide
- */
- public native static String getNonProfileGuidedCompilerFilter(String filter);
+ public static final int DEX2OAT_FOR_RELOCATION = 4;
/**
* Returns the VM's opinion of what kind of dexopt is needed to make the
@@ -479,12 +494,11 @@ public static native boolean isDexOptNeeded(String fileName)
* @param newProfile flag that describes whether a profile corresponding
* to the dex file has been recently updated and should be considered
* in the state of the file.
- * @return NO_DEXOPT_NEEDED if the apk/jar is already up to date.
- * DEX2OAT_NEEDED if dex2oat should be called on the apk/jar file.
- * PATCHOAT_NEEDED if patchoat should be called on the apk/jar
- * file to patch the odex file along side the apk/jar.
- * SELF_PATCHOAT_NEEDED if selfpatchoat should be called on the
- * apk/jar file to patch the oat file in the dalvik cache.
+ * @return NO_DEXOPT_NEEDED, or DEX2OAT_*. See documentation
+ * of the particular status code for more information on its
+ * meaning. Returns a positive status code if the status refers to
+ * the oat file in the oat location. Returns a negative status
+ * code if the status refers to the oat file in the odex location.
* @throws java.io.FileNotFoundException if fileName is not readable,
* not a file, or not present.
* @throws java.io.IOException if fileName is not a valid apk/jar file or
@@ -507,4 +521,36 @@ public static native int getDexOptNeeded(String fileName,
*/
public static native String getDexFileStatus(String fileName, String instructionSet)
throws FileNotFoundException;
+
+ /**
+ * Returns the full file path of the optimized dex file {@code fileName}. The returned string
+ * is the full file name including path of optimized dex file, if it exists.
+ * @hide
+ */
+ public static native String getDexFileOutputPath(String fileName, String instructionSet)
+ throws FileNotFoundException;
+
+ /**
+ * Returns whether the given filter is a valid filter.
+ *
+ * @hide
+ */
+ public native static boolean isValidCompilerFilter(String filter);
+
+ /**
+ * Returns whether the given filter is based on profiles.
+ *
+ * @hide
+ */
+ public native static boolean isProfileGuidedCompilerFilter(String filter);
+
+ /**
+ * Returns the version of the compiler filter that is not based on profiles.
+ * If the input is not a valid filter, or the filter is already not based on
+ * profiles, this returns the input.
+ *
+ * @hide
+ */
+ public native static String getNonProfileGuidedCompilerFilter(String filter);
+
}
diff --git a/dalvik/src/main/java/dalvik/system/DexPathList.java b/dalvik/src/main/java/dalvik/system/DexPathList.java
index 48cb792f6..3693bb2e2 100644
--- a/dalvik/src/main/java/dalvik/system/DexPathList.java
+++ b/dalvik/src/main/java/dalvik/system/DexPathList.java
@@ -22,15 +22,15 @@
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
-import java.util.zip.ZipEntry;
+import libcore.io.ClassPathURLStreamHandler;
import libcore.io.IoUtils;
import libcore.io.Libcore;
-import libcore.io.ClassPathURLStreamHandler;
import static android.system.OsConstants.S_ISDIR;
@@ -62,7 +62,7 @@
private Element[] dexElements;
/** List of native library path elements. */
- private final Element[] nativeLibraryPathElements;
+ private final NativeLibraryElement[] nativeLibraryPathElements;
/** List of application native library directories. */
private final List nativeLibraryDirectories;
@@ -75,6 +75,42 @@
*/
private IOException[] dexElementsSuppressedExceptions;
+ /**
+ * Construct an instance.
+ *
+ * @param definingContext the context in which any as-yet unresolved
+ * classes should be defined
+ *
+ * @param dexFiles the bytebuffers containing the dex files that we should load classes from.
+ */
+ public DexPathList(ClassLoader definingContext, ByteBuffer[] dexFiles) {
+ if (definingContext == null) {
+ throw new NullPointerException("definingContext == null");
+ }
+ if (dexFiles == null) {
+ throw new NullPointerException("dexFiles == null");
+ }
+ if (Arrays.stream(dexFiles).anyMatch(v -> v == null)) {
+ throw new NullPointerException("dexFiles contains a null Buffer!");
+ }
+
+ this.definingContext = definingContext;
+ // TODO It might be useful to let in-memory dex-paths have native libraries.
+ this.nativeLibraryDirectories = Collections.emptyList();
+ this.systemNativeLibraryDirectories =
+ splitPaths(System.getProperty("java.library.path"), true);
+ this.nativeLibraryPathElements = makePathElements(this.systemNativeLibraryDirectories);
+
+ ArrayList suppressedExceptions = new ArrayList();
+ this.dexElements = makeInMemoryDexElements(dexFiles, suppressedExceptions);
+ if (suppressedExceptions.size() > 0) {
+ this.dexElementsSuppressedExceptions =
+ suppressedExceptions.toArray(new IOException[suppressedExceptions.size()]);
+ } else {
+ dexElementsSuppressedExceptions = null;
+ }
+ }
+
/**
* Constructs an instance.
*
@@ -84,11 +120,6 @@
* {@code File.pathSeparator}
* @param librarySearchPath list of native library directory path elements,
* separated by {@code File.pathSeparator}
- * @param libraryPermittedPath is path containing permitted directories for
- * linker isolated namespaces (in addition to librarySearchPath which is allowed
- * implicitly). Note that this path does not affect the search order for the library
- * and intended for white-listing additional paths when loading native libraries
- * by absolute path.
* @param optimizedDirectory directory where optimized {@code .dex} files
* should be found and written to, or {@code null} to use the default
* system directory for same
@@ -142,9 +173,7 @@ public DexPathList(ClassLoader definingContext, String dexPath,
List allNativeLibraryDirectories = new ArrayList<>(nativeLibraryDirectories);
allNativeLibraryDirectories.addAll(systemNativeLibraryDirectories);
- this.nativeLibraryPathElements = makePathElements(allNativeLibraryDirectories,
- suppressedExceptions,
- definingContext);
+ this.nativeLibraryPathElements = makePathElements(allNativeLibraryDirectories);
if (suppressedExceptions.size() > 0) {
this.dexElementsSuppressedExceptions =
@@ -253,98 +282,84 @@ private static List splitPaths(String searchPath, boolean directoriesOnly)
return result;
}
+ private static Element[] makeInMemoryDexElements(ByteBuffer[] dexFiles,
+ List suppressedExceptions) {
+ Element[] elements = new Element[dexFiles.length];
+ int elementPos = 0;
+ for (ByteBuffer buf : dexFiles) {
+ try {
+ DexFile dex = new DexFile(buf);
+ elements[elementPos++] = new Element(dex);
+ } catch (IOException suppressed) {
+ System.logE("Unable to load dex file: " + buf, suppressed);
+ suppressedExceptions.add(suppressed);
+ }
+ }
+ if (elementPos != elements.length) {
+ elements = Arrays.copyOf(elements, elementPos);
+ }
+ return elements;
+ }
+
/**
* Makes an array of dex/resource path elements, one per element of
* the given array.
*/
private static Element[] makeDexElements(List files, File optimizedDirectory,
- List suppressedExceptions,
- ClassLoader loader) {
- return makeElements(files, optimizedDirectory, suppressedExceptions, false, loader);
- }
-
- /**
- * Makes an array of directory/zip path elements, one per element of the given array.
- */
- private static Element[] makePathElements(List files,
- List suppressedExceptions,
- ClassLoader loader) {
- return makeElements(files, null, suppressedExceptions, true, loader);
- }
-
- /*
- * TODO (dimitry): Revert after apps stops relying on the existence of this
- * method (see http://b/21957414 and http://b/26317852 for details)
- */
- private static Element[] makePathElements(List files, File optimizedDirectory,
- List suppressedExceptions) {
- return makeElements(files, optimizedDirectory, suppressedExceptions, false, null);
- }
-
- private static Element[] makeElements(List files, File optimizedDirectory,
- List suppressedExceptions,
- boolean ignoreDexFiles,
- ClassLoader loader) {
- Element[] elements = new Element[files.size()];
- int elementsPos = 0;
- /*
- * Open all files and load the (direct or contained) dex files
- * up front.
- */
- for (File file : files) {
- File zip = null;
- File dir = new File("");
- DexFile dex = null;
- String path = file.getPath();
- String name = file.getName();
-
- if (path.contains(zipSeparator)) {
- String split[] = path.split(zipSeparator, 2);
- zip = new File(split[0]);
- dir = new File(split[1]);
- } else if (file.isDirectory()) {
- // We support directories for looking up resources and native libraries.
- // Looking up resources in directories is useful for running libcore tests.
- elements[elementsPos++] = new Element(file, true, null, null);
- } else if (file.isFile()) {
- if (!ignoreDexFiles && name.endsWith(DEX_SUFFIX)) {
- // Raw dex file (not inside a zip/jar).
- try {
- dex = loadDexFile(file, optimizedDirectory, loader, elements);
- } catch (IOException suppressed) {
- System.logE("Unable to load dex file: " + file, suppressed);
- suppressedExceptions.add(suppressed);
- }
- } else {
- zip = file;
-
- if (!ignoreDexFiles) {
- try {
- dex = loadDexFile(file, optimizedDirectory, loader, elements);
- } catch (IOException suppressed) {
- /*
- * IOException might get thrown "legitimately" by the DexFile constructor if
- * the zip file turns out to be resource-only (that is, no classes.dex file
- * in it).
- * Let dex == null and hang on to the exception to add to the tea-leaves for
- * when findClass returns null.
- */
- suppressedExceptions.add(suppressed);
- }
- }
- }
- } else {
- System.logW("ClassLoader referenced unknown path: " + file);
- }
-
- if ((zip != null) || (dex != null)) {
- elements[elementsPos++] = new Element(dir, false, zip, dex);
- }
- }
- if (elementsPos != elements.length) {
- elements = Arrays.copyOf(elements, elementsPos);
- }
- return elements;
+ List suppressedExceptions, ClassLoader loader) {
+ Element[] elements = new Element[files.size()];
+ int elementsPos = 0;
+ /*
+ * Open all files and load the (direct or contained) dex files up front.
+ */
+ for (File file : files) {
+ if (file.isDirectory()) {
+ // We support directories for looking up resources. Looking up resources in
+ // directories is useful for running libcore tests.
+ elements[elementsPos++] = new Element(file);
+ } else if (file.isFile()) {
+ String name = file.getName();
+
+ if (name.endsWith(DEX_SUFFIX)) {
+ // Raw dex file (not inside a zip/jar).
+ try {
+ DexFile dex = loadDexFile(file, optimizedDirectory, loader, elements);
+ if (dex != null) {
+ elements[elementsPos++] = new Element(dex, null);
+ }
+ } catch (IOException suppressed) {
+ System.logE("Unable to load dex file: " + file, suppressed);
+ suppressedExceptions.add(suppressed);
+ }
+ } else {
+ DexFile dex = null;
+ try {
+ dex = loadDexFile(file, optimizedDirectory, loader, elements);
+ } catch (IOException suppressed) {
+ /*
+ * IOException might get thrown "legitimately" by the DexFile constructor if
+ * the zip file turns out to be resource-only (that is, no classes.dex file
+ * in it).
+ * Let dex == null and hang on to the exception to add to the tea-leaves for
+ * when findClass returns null.
+ */
+ suppressedExceptions.add(suppressed);
+ }
+
+ if (dex == null) {
+ elements[elementsPos++] = new Element(file);
+ } else {
+ elements[elementsPos++] = new Element(dex, file);
+ }
+ }
+ } else {
+ System.logW("ClassLoader referenced unknown path: " + file);
+ }
+ }
+ if (elementsPos != elements.length) {
+ elements = Arrays.copyOf(elements, elementsPos);
+ }
+ return elements;
}
/**
@@ -398,6 +413,42 @@ private static String optimizedPathFor(File path,
return result.getPath();
}
+ /*
+ * TODO (dimitry): Revert after apps stops relying on the existence of this
+ * method (see http://b/21957414 and http://b/26317852 for details)
+ */
+ @SuppressWarnings("unused")
+ private static Element[] makePathElements(List files, File optimizedDirectory,
+ List suppressedExceptions) {
+ return makeDexElements(files, optimizedDirectory, suppressedExceptions, null);
+ }
+
+ /**
+ * Makes an array of directory/zip path elements for the native library search path, one per
+ * element of the given array.
+ */
+ private static NativeLibraryElement[] makePathElements(List files) {
+ NativeLibraryElement[] elements = new NativeLibraryElement[files.size()];
+ int elementsPos = 0;
+ for (File file : files) {
+ String path = file.getPath();
+
+ if (path.contains(zipSeparator)) {
+ String split[] = path.split(zipSeparator, 2);
+ File zip = new File(split[0]);
+ String dir = split[1];
+ elements[elementsPos++] = new NativeLibraryElement(zip, dir);
+ } else if (file.isDirectory()) {
+ // We support directories for looking up native libraries.
+ elements[elementsPos++] = new NativeLibraryElement(file);
+ }
+ }
+ if (elementsPos != elements.length) {
+ elements = Arrays.copyOf(elements, elementsPos);
+ }
+ return elements;
+ }
+
/**
* Finds the named class in one of the dex files pointed at by
* this instance. This will find the one in the earliest listed
@@ -410,17 +461,14 @@ private static String optimizedPathFor(File path,
* @return the named class or {@code null} if the class is not
* found in any of the dex files
*/
- public Class findClass(String name, List suppressed) {
+ public Class> findClass(String name, List suppressed) {
for (Element element : dexElements) {
- DexFile dex = element.dexFile;
-
- if (dex != null) {
- Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
- if (clazz != null) {
- return clazz;
- }
+ Class> clazz = element.findClass(name, definingContext, suppressed);
+ if (clazz != null) {
+ return clazz;
}
}
+
if (dexElementsSuppressedExceptions != null) {
suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
}
@@ -476,7 +524,7 @@ public Enumeration findResources(String name) {
public String findLibrary(String libraryName) {
String fileName = System.mapLibraryName(libraryName);
- for (Element element : nativeLibraryPathElements) {
+ for (NativeLibraryElement element : nativeLibraryPathElements) {
String path = element.findNativeLibrary(fileName);
if (path != null) {
@@ -488,32 +536,108 @@ public String findLibrary(String libraryName) {
}
/**
- * Element of the dex/resource/native library path
+ * Returns the list of all individual dex files paths from the current list.
+ * The list will contain only file paths (i.e. no directories).
+ */
+ /*package*/ List getDexPaths() {
+ List dexPaths = new ArrayList();
+ for (Element e : dexElements) {
+ String dexPath = e.getDexPath();
+ if (dexPath != null) {
+ // Add the element to the list only if it is a file. A null dex path signals the
+ // element is a resource directory or an in-memory dex file.
+ dexPaths.add(dexPath);
+ }
+ }
+ return dexPaths;
+ }
+
+ /**
+ * Element of the dex/resource path. Note: should be called DexElement, but apps reflect on
+ * this.
*/
/*package*/ static class Element {
- private final File dir;
- private final boolean isDirectory;
- private final File zip;
+ /**
+ * A file denoting a zip file (in case of a resource jar or a dex jar), or a directory
+ * (only when dexFile is null).
+ */
+ private final File path;
+
private final DexFile dexFile;
private ClassPathURLStreamHandler urlHandler;
private boolean initialized;
- public Element(File dir, boolean isDirectory, File zip, DexFile dexFile) {
- this.dir = dir;
- this.isDirectory = isDirectory;
- this.zip = zip;
+ /**
+ * Element encapsulates a dex file. This may be a plain dex file (in which case dexZipPath
+ * should be null), or a jar (in which case dexZipPath should denote the zip file).
+ */
+ public Element(DexFile dexFile, File dexZipPath) {
+ this.dexFile = dexFile;
+ this.path = dexZipPath;
+ }
+
+ public Element(DexFile dexFile) {
this.dexFile = dexFile;
+ this.path = null;
+ }
+
+ public Element(File path) {
+ this.path = path;
+ this.dexFile = null;
+ }
+
+ /**
+ * Constructor for a bit of backwards compatibility. Some apps use reflection into
+ * internal APIs. Warn, and emulate old behavior if we can. See b/33399341.
+ *
+ * @deprecated The Element class has been split. Use new Element constructors for
+ * classes and resources, and NativeLibraryElement for the library
+ * search path.
+ */
+ @Deprecated
+ public Element(File dir, boolean isDirectory, File zip, DexFile dexFile) {
+ System.err.println("Warning: Using deprecated Element constructor. Do not use internal"
+ + " APIs, this constructor will be removed in the future.");
+ if (dir != null && (zip != null || dexFile != null)) {
+ throw new IllegalArgumentException("Using dir and zip|dexFile no longer"
+ + " supported.");
+ }
+ if (isDirectory && (zip != null || dexFile != null)) {
+ throw new IllegalArgumentException("Unsupported argument combination.");
+ }
+ if (dir != null) {
+ this.path = dir;
+ this.dexFile = null;
+ } else {
+ this.path = zip;
+ this.dexFile = dexFile;
+ }
}
- @Override public String toString() {
- if (isDirectory) {
- return "directory \"" + dir + "\"";
- } else if (zip != null) {
- return "zip file \"" + zip + "\"" +
- (dir != null && !dir.getPath().isEmpty() ? ", dir \"" + dir + "\"" : "");
+ /*
+ * Returns the dex path of this element or null if the element refers to a directory.
+ */
+ private String getDexPath() {
+ if (path != null) {
+ return path.isDirectory() ? null : path.getAbsolutePath();
+ } else if (dexFile != null) {
+ // DexFile.getName() returns the path of the dex file.
+ return dexFile.getName();
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ if (dexFile == null) {
+ return (path.isDirectory() ? "directory \"" : "zip file \"") + path + "\"";
} else {
+ if (path == null) {
return "dex file \"" + dexFile + "\"";
+ } else {
+ return "zip file \"" + path + "\"";
+ }
}
}
@@ -522,14 +646,13 @@ public synchronized void maybeInit() {
return;
}
- initialized = true;
-
- if (isDirectory || zip == null) {
+ if (path == null || path.isDirectory()) {
+ initialized = true;
return;
}
try {
- urlHandler = new ClassPathURLStreamHandler(zip.getPath());
+ urlHandler = new ClassPathURLStreamHandler(path.getPath());
} catch (IOException ioe) {
/*
* Note: ZipException (a subclass of IOException)
@@ -537,40 +660,35 @@ public synchronized void maybeInit() {
* (e.g. if the file isn't actually a zip/jar
* file).
*/
- System.logE("Unable to open zip file: " + zip, ioe);
+ System.logE("Unable to open zip file: " + path, ioe);
urlHandler = null;
}
- }
- public String findNativeLibrary(String name) {
- maybeInit();
-
- if (isDirectory) {
- String path = new File(dir, name).getPath();
- if (IoUtils.canOpenReadOnly(path)) {
- return path;
- }
- } else if (urlHandler != null) {
- // Having a urlHandler means the element has a zip file.
- // In this case Android supports loading the library iff
- // it is stored in the zip uncompressed.
-
- String entryName = new File(dir, name).getPath();
- if (urlHandler.isEntryStored(entryName)) {
- return zip.getPath() + zipSeparator + entryName;
- }
- }
+ // Mark this element as initialized only after we've successfully created
+ // the associated ClassPathURLStreamHandler. That way, we won't leave this
+ // element in an inconsistent state if an exception is thrown during initialization.
+ //
+ // See b/35633614.
+ initialized = true;
+ }
- return null;
+ public Class> findClass(String name, ClassLoader definingContext,
+ List suppressed) {
+ return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
+ : null;
}
public URL findResource(String name) {
maybeInit();
+ if (urlHandler != null) {
+ return urlHandler.getEntryUrlOrNull(name);
+ }
+
// We support directories so we can run tests and/or legacy code
// that uses Class.getResource.
- if (isDirectory) {
- File resourceFile = new File(dir, name);
+ if (path != null && path.isDirectory()) {
+ File resourceFile = new File(path, name);
if (resourceFile.exists()) {
try {
return resourceFile.toURI().toURL();
@@ -580,12 +698,105 @@ public URL findResource(String name) {
}
}
- if (urlHandler == null) {
- /* This element has no zip/jar file.
+ return null;
+ }
+ }
+
+ /**
+ * Element of the native library path
+ */
+ /*package*/ static class NativeLibraryElement {
+ /**
+ * A file denoting a directory or zip file.
+ */
+ private final File path;
+
+ /**
+ * If path denotes a zip file, this denotes a base path inside the zip.
+ */
+ private final String zipDir;
+
+ private ClassPathURLStreamHandler urlHandler;
+ private boolean initialized;
+
+ public NativeLibraryElement(File dir) {
+ this.path = dir;
+ this.zipDir = null;
+
+ // We should check whether path is a directory, but that is non-eliminatable overhead.
+ }
+
+ public NativeLibraryElement(File zip, String zipDir) {
+ this.path = zip;
+ this.zipDir = zipDir;
+
+ // Simple check that should be able to be eliminated by inlining. We should also
+ // check whether path is a file, but that is non-eliminatable overhead.
+ if (zipDir == null) {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ @Override
+ public String toString() {
+ if (zipDir == null) {
+ return "directory \"" + path + "\"";
+ } else {
+ return "zip file \"" + path + "\"" +
+ (!zipDir.isEmpty() ? ", dir \"" + zipDir + "\"" : "");
+ }
+ }
+
+ public synchronized void maybeInit() {
+ if (initialized) {
+ return;
+ }
+
+ if (zipDir == null) {
+ initialized = true;
+ return;
+ }
+
+ try {
+ urlHandler = new ClassPathURLStreamHandler(path.getPath());
+ } catch (IOException ioe) {
+ /*
+ * Note: ZipException (a subclass of IOException)
+ * might get thrown by the ZipFile constructor
+ * (e.g. if the file isn't actually a zip/jar
+ * file).
*/
- return null;
+ System.logE("Unable to open zip file: " + path, ioe);
+ urlHandler = null;
}
- return urlHandler.getEntryUrlOrNull(name);
+
+ // Mark this element as initialized only after we've successfully created
+ // the associated ClassPathURLStreamHandler. That way, we won't leave this
+ // element in an inconsistent state if an exception is thrown during initialization.
+ //
+ // See b/35633614.
+ initialized = true;
+ }
+
+ public String findNativeLibrary(String name) {
+ maybeInit();
+
+ if (zipDir == null) {
+ String entryPath = new File(path, name).getPath();
+ if (IoUtils.canOpenReadOnly(entryPath)) {
+ return entryPath;
+ }
+ } else if (urlHandler != null) {
+ // Having a urlHandler means the element has a zip file.
+ // In this case Android supports loading the library iff
+ // it is stored in the zip uncompressed.
+ String entryName = zipDir + '/' + name;
+ if (urlHandler.isEntryStored(entryName)) {
+ return path.getPath() + zipSeparator + entryName;
+ }
+ }
+
+ return null;
}
}
}
diff --git a/dalvik/src/main/java/dalvik/system/EmulatedStackFrame.java b/dalvik/src/main/java/dalvik/system/EmulatedStackFrame.java
new file mode 100644
index 000000000..b479d6fd8
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/EmulatedStackFrame.java
@@ -0,0 +1,524 @@
+/*
+ * Copyright (C) 2016 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.lang.invoke.MethodType;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Provides typed (read-only) access to method arguments and a slot to store a return value.
+ *
+ * Used to implement method handle transforms. See {@link java.lang.invoke.Transformers}.
+ *
+ * @hide
+ */
+public class EmulatedStackFrame {
+ /**
+ * The type of this stack frame, i.e, the types of its arguments and the type of its
+ * return value.
+ */
+ private final MethodType type;
+
+ /**
+ * The type of the callsite that produced this stack frame. This contains the types of
+ * the original arguments, before any conversions etc. were performed.
+ */
+ private final MethodType callsiteType;
+
+ /**
+ * All reference arguments and reference return values that belong to this argument array.
+ *
+ * If the return type is a reference, it will be the last element of this array.
+ */
+ private final Object[] references;
+
+ /**
+ * Contains all primitive values on the stack. Primitive values always take 4 or 8 bytes of
+ * space and all {@code short}, {@code char} and {@code boolean} arguments are promoted to ints.
+ *
+ * Reference values do not appear on the stack frame but they appear (in order)
+ * in the {@code references} array. No additional slots or space for reference arguments or
+ * return values are reserved in the stackFrame.
+ *
+ * By convention, if the return value is a primitive, it will occupy the last 4 or 8 bytes
+ * of the stack frame, depending on the type.
+ *
+ * The size of this array is known at the time of creation of this {@code EmulatedStackFrame}
+ * and is determined by the {@code MethodType} of the frame.
+ *
+ * Example :
+ *
+ * Function : String foo(String a, String b, int c, long d) { }
+ *
+ * EmulatedStackFrame :
+ * references = { a, b, [return_value] }
+ * stackFrame = { c0, c1, c2, c3, d0, d1, d2, d3, d4, d5, d6, d7 }
+ *
+ * Function : int foo(String a)
+ *
+ * EmulatedStackFrame :
+ * references = { a }
+ * stackFrame = { rv0, rv1, rv2, rv3 } // rv is the return value.
+ *
+ *
+ *
+ */
+ private final byte[] stackFrame;
+
+ private EmulatedStackFrame(MethodType type, MethodType callsiteType, Object[] references,
+ byte[] stackFrame) {
+ this.type = type;
+ this.callsiteType = callsiteType;
+ this.references = references;
+ this.stackFrame = stackFrame;
+ }
+
+ /**
+ * Returns the {@code MethodType} that the frame was created for.
+ */
+ public final MethodType getMethodType() { return type; }
+
+ /**
+ * Returns the {@code MethodType} corresponding to the callsite of the
+ */
+ public final MethodType getCallsiteType() { return callsiteType; }
+
+ /**
+ * Represents a range of arguments on an {@code EmulatedStackFrame}.
+ *
+ * @hide
+ */
+ public static final class Range {
+ public final int referencesStart;
+ public final int numReferences;
+
+ public final int stackFrameStart;
+ public final int numBytes;
+
+ private Range(int referencesStart, int numReferences, int stackFrameStart, int numBytes) {
+ this.referencesStart = referencesStart;
+ this.numReferences = numReferences;
+ this.stackFrameStart = stackFrameStart;
+ this.numBytes = numBytes;
+ }
+
+ public static Range all(MethodType frameType) {
+ return of(frameType, 0, frameType.parameterCount());
+ }
+
+ public static Range of(MethodType frameType, int startArg, int endArg) {
+ final Class>[] ptypes = frameType.ptypes();
+
+ int referencesStart = 0;
+ int numReferences = 0;
+ int stackFrameStart = 0;
+ int numBytes = 0;
+
+ for (int i = 0; i < startArg; ++i) {
+ Class> cl = ptypes[i];
+ if (!cl.isPrimitive()) {
+ referencesStart++;
+ } else {
+ stackFrameStart += getSize(cl);
+ }
+ }
+
+ for (int i = startArg; i < endArg; ++i) {
+ Class> cl = ptypes[i];
+ if (!cl.isPrimitive()) {
+ numReferences++;
+ } else {
+ numBytes += getSize(cl);
+ }
+ }
+
+ return new Range(referencesStart, numReferences, stackFrameStart, numBytes);
+ }
+ }
+
+ /**
+ * Creates an emulated stack frame for a given {@code MethodType}.
+ */
+ public static EmulatedStackFrame create(MethodType frameType) {
+ int numRefs = 0;
+ int frameSize = 0;
+ for (Class> ptype : frameType.ptypes()) {
+ if (!ptype.isPrimitive()) {
+ numRefs++;
+ } else {
+ frameSize += getSize(ptype);
+ }
+ }
+
+ final Class> rtype = frameType.rtype();
+ if (!rtype.isPrimitive()) {
+ numRefs++;
+ } else {
+ frameSize += getSize(rtype);
+ }
+
+ return new EmulatedStackFrame(frameType, frameType, new Object[numRefs],
+ new byte[frameSize]);
+ }
+
+ /**
+ * Sets the {@code idx} to {@code reference}. Type checks are performed.
+ */
+ public void setReference(int idx, Object reference) {
+ final Class>[] ptypes = type.ptypes();
+ if (idx < 0 || idx >= ptypes.length) {
+ throw new IllegalArgumentException("Invalid index: " + idx);
+ }
+
+ if (reference != null && !ptypes[idx].isInstance(reference)) {
+ throw new IllegalStateException("reference is not of type: " + type.ptypes()[idx]);
+ }
+
+ references[idx] = reference;
+ }
+
+ /**
+ * Gets the reference at {@code idx}, checking that it's of type {@code referenceType}.
+ */
+ public T getReference(int idx, Class referenceType) {
+ if (referenceType != type.ptypes()[idx]) {
+ throw new IllegalArgumentException("Argument: " + idx +
+ " is of type " + type.ptypes()[idx] + " expected " + referenceType + "");
+ }
+
+ return (T) references[idx];
+ }
+
+ /**
+ * Copies a specified range of arguments, given by {@code fromRange} to a specified
+ * EmulatedStackFrame {@code other}, with references starting at {@code referencesStart}
+ * and primitives starting at {@code primitivesStart}.
+ */
+ public void copyRangeTo(EmulatedStackFrame other, Range fromRange, int referencesStart,
+ int primitivesStart) {
+ if (fromRange.numReferences > 0) {
+ System.arraycopy(references, fromRange.referencesStart,
+ other.references, referencesStart, fromRange.numReferences);
+ }
+
+ if (fromRange.numBytes > 0) {
+ System.arraycopy(stackFrame, fromRange.stackFrameStart,
+ other.stackFrame, primitivesStart, fromRange.numBytes);
+ }
+ }
+
+ /**
+ * Copies the return value from this stack frame to {@code other}.
+ */
+ public void copyReturnValueTo(EmulatedStackFrame other) {
+ final Class> returnType = type.returnType();
+ if (!returnType.isPrimitive()) {
+ other.references[other.references.length - 1] = references[references.length - 1];
+ } else if (!is64BitPrimitive(returnType)) {
+ System.arraycopy(stackFrame, stackFrame.length - 4,
+ other.stackFrame, other.stackFrame.length - 4, 4);
+ } else {
+ System.arraycopy(stackFrame, stackFrame.length - 8,
+ other.stackFrame, other.stackFrame.length - 8, 8);
+ }
+ }
+
+ public void setReturnValueTo(Object reference) {
+ final Class> returnType = type.returnType();
+ if (returnType.isPrimitive()) {
+ throw new IllegalStateException("return type is not a reference type: " + returnType);
+ }
+
+ if (reference != null && !returnType.isInstance(reference)) {
+ throw new IllegalArgumentException("reference is not of type " + returnType);
+ }
+
+ references[references.length - 1] = reference;
+ }
+
+ /**
+ * Returns true iff. the input {@code type} needs 64 bits (8 bytes) of storage on an
+ * {@code EmulatedStackFrame}.
+ */
+ private static boolean is64BitPrimitive(Class> type) {
+ return type == double.class || type == long.class;
+ }
+
+ /**
+ * Returns the size (in bytes) occupied by a given primitive type on an
+ * {@code EmulatedStackFrame}.
+ */
+ public static int getSize(Class> type) {
+ if (!type.isPrimitive()) {
+ throw new IllegalArgumentException("type.isPrimitive() == false: " + type);
+ }
+
+ if (is64BitPrimitive(type)) {
+ return 8;
+ } else {
+ return 4;
+ }
+ }
+
+ /**
+ * Base class for readers and writers to stack frames.
+ *
+ * @hide
+ */
+ public static class StackFrameAccessor {
+ /**
+ * The current offset into the references array.
+ */
+ protected int referencesOffset;
+
+ /**
+ * The index of the current argument being processed. For a function of arity N,
+ * values [0, N) correspond to input arguments, and the special index {@code -2}
+ * maps to the return value. All other indices are invalid.
+ */
+ protected int argumentIdx;
+
+ /**
+ * Wrapper for {@code EmulatedStackFrame.this.stackFrame}.
+ */
+ protected ByteBuffer frameBuf;
+
+ /**
+ * The number of arguments that this stack frame expects.
+ */
+ private int numArgs;
+
+ /**
+ * The stack frame we're currently accessing.
+ */
+ protected EmulatedStackFrame frame;
+
+ /**
+ * The value of {@code argumentIdx} when this accessor's cursor is pointing to the
+ * frame's return value.
+ */
+ private static final int RETURN_VALUE_IDX = -2;
+
+ protected StackFrameAccessor() {
+ referencesOffset = 0;
+ argumentIdx = 0;
+
+ frameBuf = null;
+ numArgs = 0;
+ }
+
+ /**
+ * Attaches this accessor to a given {@code EmulatedStackFrame} to read or write
+ * values to it. Also resets all state associated with the current accessor.
+ */
+ public StackFrameAccessor attach(EmulatedStackFrame stackFrame) {
+ return attach(stackFrame, 0 /* argumentIdx */, 0 /* referencesOffset */,
+ 0 /* frameOffset */);
+ }
+
+ public StackFrameAccessor attach(EmulatedStackFrame stackFrame, int argumentIdx,
+ int referencesOffset, int frameOffset) {
+ frame = stackFrame;
+ frameBuf = ByteBuffer.wrap(frame.stackFrame).order(ByteOrder.LITTLE_ENDIAN);
+ numArgs = frame.type.ptypes().length;
+ if (frameOffset != 0) {
+ frameBuf.position(frameOffset);
+ }
+
+ this.referencesOffset = referencesOffset;
+ this.argumentIdx = argumentIdx;
+
+ return this;
+ }
+
+ protected void checkType(Class> type) {
+ if (argumentIdx >= numArgs || argumentIdx == (RETURN_VALUE_IDX + 1)) {
+ throw new IllegalArgumentException("Invalid argument index: " + argumentIdx);
+ }
+
+ final Class> expectedType = (argumentIdx == RETURN_VALUE_IDX) ?
+ frame.type.rtype() : frame.type.ptypes()[argumentIdx];
+
+ if (expectedType != type) {
+ throw new IllegalArgumentException("Incorrect type: " + type +
+ ", expected: " + expectedType);
+ }
+ }
+
+ /**
+ * Positions the cursor at the return value location, either in the references array
+ * or in the stack frame array. The next put* or next* call will result in a read or
+ * write to the return value.
+ */
+ public void makeReturnValueAccessor() {
+ Class> rtype = frame.type.rtype();
+ argumentIdx = RETURN_VALUE_IDX;
+
+ // Position the cursor appropriately. The return value is either the last element
+ // of the references array, or the last 4 or 8 bytes of the stack frame.
+ if (rtype.isPrimitive()) {
+ frameBuf.position(frameBuf.capacity() - getSize(rtype));
+ } else {
+ referencesOffset = frame.references.length - 1;
+ }
+ }
+
+ public static void copyNext(StackFrameReader reader, StackFrameWriter writer,
+ Class> type) {
+ if (!type.isPrimitive()) {
+ writer.putNextReference(reader.nextReference(type), type);
+ } else if (type == boolean.class) {
+ writer.putNextBoolean(reader.nextBoolean());
+ } else if (type == byte.class) {
+ writer.putNextByte(reader.nextByte());
+ } else if (type == char.class) {
+ writer.putNextChar(reader.nextChar());
+ } else if (type == short.class) {
+ writer.putNextShort(reader.nextShort());
+ } else if (type == int.class) {
+ writer.putNextInt(reader.nextInt());
+ } else if (type == long.class) {
+ writer.putNextLong(reader.nextLong());
+ } else if (type == float.class) {
+ writer.putNextFloat(reader.nextFloat());
+ } else if (type == double.class) {
+ writer.putNextDouble(reader.nextDouble());
+ }
+ }
+ }
+
+ /**
+ * Provides sequential write access to an emulated stack frame. Allows writes to
+ * argument slots as well as return value slots.
+ */
+ public static class StackFrameWriter extends StackFrameAccessor {
+ public void putNextByte(byte value) {
+ checkType(byte.class);
+ argumentIdx++;
+ frameBuf.putInt(value);
+ }
+
+ public void putNextInt(int value) {
+ checkType(int.class);
+ argumentIdx++;
+ frameBuf.putInt(value);
+ }
+
+ public void putNextLong(long value) {
+ checkType(long.class);
+ argumentIdx++;
+ frameBuf.putLong(value);
+ }
+
+ public void putNextChar(char value) {
+ checkType(char.class);
+ argumentIdx++;
+ frameBuf.putInt((int) value);
+ }
+
+ public void putNextBoolean(boolean value) {
+ checkType(boolean.class);
+ argumentIdx++;
+ frameBuf.putInt(value ? 1 : 0);
+ }
+
+ public void putNextShort(short value) {
+ checkType(short.class);
+ argumentIdx++;
+ frameBuf.putInt((int) value);
+ }
+
+ public void putNextFloat(float value) {
+ checkType(float.class);
+ argumentIdx++;
+ frameBuf.putFloat(value);
+ }
+
+ public void putNextDouble(double value) {
+ checkType(double.class);
+ argumentIdx++;
+ frameBuf.putDouble(value);
+ }
+
+ public void putNextReference(Object value, Class> expectedType) {
+ checkType(expectedType);
+ argumentIdx++;
+ frame.references[referencesOffset++] = value;
+ }
+ }
+
+ /**
+ * Provides sequential read access to an emulated stack frame. Allows reads to
+ * argument slots as well as to return value slots.
+ */
+ public static class StackFrameReader extends StackFrameAccessor {
+ public byte nextByte() {
+ checkType(byte.class);
+ argumentIdx++;
+ return (byte) frameBuf.getInt();
+ }
+
+ public int nextInt() {
+ checkType(int.class);
+ argumentIdx++;
+ return frameBuf.getInt();
+ }
+
+ public long nextLong() {
+ checkType(long.class);
+ argumentIdx++;
+ return frameBuf.getLong();
+ }
+
+ public char nextChar() {
+ checkType(char.class);
+ argumentIdx++;
+ return (char) frameBuf.getInt();
+ }
+
+ public boolean nextBoolean() {
+ checkType(boolean.class);
+ argumentIdx++;
+ return (frameBuf.getInt() != 0);
+ }
+
+ public short nextShort() {
+ checkType(short.class);
+ argumentIdx++;
+ return (short) frameBuf.getInt();
+ }
+
+ public float nextFloat() {
+ checkType(float.class);
+ argumentIdx++;
+ return frameBuf.getFloat();
+ }
+
+ public double nextDouble() {
+ checkType(double.class);
+ argumentIdx++;
+ return frameBuf.getDouble();
+ }
+
+ public T nextReference(Class expectedType) {
+ checkType(expectedType);
+ argumentIdx++;
+ return (T) frame.references[referencesOffset++];
+ }
+ }
+}
diff --git a/dalvik/src/main/java/dalvik/system/InMemoryDexClassLoader.java b/dalvik/src/main/java/dalvik/system/InMemoryDexClassLoader.java
new file mode 100644
index 000000000..0fa1e45a7
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/InMemoryDexClassLoader.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2016 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.nio.ByteBuffer;
+
+/**
+ * A {@link ClassLoader} implementation that loads classes from a
+ * buffer containing a DEX file. This can be used to execute code that
+ * has not been written to the local file system.
+ */
+public final class InMemoryDexClassLoader extends BaseDexClassLoader {
+ /**
+ * Create an in-memory DEX class loader with the given dex buffers.
+ *
+ * @param dexBuffers array of buffers containing DEX files between
+ * buffer.position() and buffer.limit() .
+ * @param parent the parent class loader for delegation.
+ * @hide
+ */
+ public InMemoryDexClassLoader(ByteBuffer[] dexBuffers, ClassLoader parent) {
+ super(dexBuffers, parent);
+ }
+
+ /**
+ * Creates a new in-memory DEX class loader.
+ *
+ * @param dexBuffer buffer containing DEX file contents between
+ * buffer.position() and buffer.limit() .
+ * @param parent the parent class loader for delegation.
+ */
+ public InMemoryDexClassLoader(ByteBuffer dexBuffer, ClassLoader parent) {
+ this(new ByteBuffer[] { dexBuffer }, parent);
+ }
+}
diff --git a/dalvik/src/main/java/dalvik/system/VMDebug.java b/dalvik/src/main/java/dalvik/system/VMDebug.java
index 23d740783..85b52f8e9 100644
--- a/dalvik/src/main/java/dalvik/system/VMDebug.java
+++ b/dalvik/src/main/java/dalvik/system/VMDebug.java
@@ -16,6 +16,7 @@
package dalvik.system;
+import dalvik.annotation.optimization.FastNative;
import java.io.FileDescriptor;
import java.io.IOException;
import java.util.HashMap;
@@ -106,6 +107,7 @@ private VMDebug() {}
*
* @return the time in milliseconds, or -1 if the debugger is not connected
*/
+ @FastNative
public static native long lastDebuggerActivity();
/**
@@ -114,6 +116,7 @@ private VMDebug() {}
*
* @return true if debugging is enabled
*/
+ @FastNative
public static native boolean isDebuggingEnabled();
/**
@@ -121,6 +124,7 @@ private VMDebug() {}
*
* @return true if (and only if) a debugger is connected
*/
+ @FastNative
public static native boolean isDebuggerConnected();
/**
@@ -172,11 +176,26 @@ public static void startMethodTracing(String traceFileName, int bufferSize, int
* FileDescriptor in which the trace is written. The file name is also
* supplied simply for logging. Makes a dup of the file descriptor.
*/
- public static void startMethodTracing(String traceFileName, FileDescriptor fd, int bufferSize, int flags, boolean samplingEnabled, int intervalUs) {
+ public static void startMethodTracing(String traceFileName, FileDescriptor fd, int bufferSize,
+ int flags, boolean samplingEnabled, int intervalUs) {
+ startMethodTracing(traceFileName, fd, bufferSize, flags, samplingEnabled, intervalUs,
+ false);
+ }
+
+ /**
+ * Like startMethodTracing(String, int, int), but taking an already-opened
+ * FileDescriptor in which the trace is written. The file name is also
+ * supplied simply for logging. Makes a dup of the file descriptor.
+ * Streams tracing data to the file if streamingOutput is true.
+ */
+ public static void startMethodTracing(String traceFileName, FileDescriptor fd, int bufferSize,
+ int flags, boolean samplingEnabled, int intervalUs,
+ boolean streamingOutput) {
if (fd == null) {
throw new NullPointerException("fd == null");
}
- startMethodTracingFd(traceFileName, fd, checkBufferSize(bufferSize), flags, samplingEnabled, intervalUs);
+ startMethodTracingFd(traceFileName, fd, checkBufferSize(bufferSize), flags,
+ samplingEnabled, intervalUs, streamingOutput);
}
/**
@@ -200,7 +219,7 @@ private static int checkBufferSize(int bufferSize) {
}
private static native void startMethodTracingDdmsImpl(int bufferSize, int flags, boolean samplingEnabled, int intervalUs);
- private static native void startMethodTracingFd(String traceFileName, FileDescriptor fd, int bufferSize, int flags, boolean samplingEnabled, int intervalUs);
+ private static native void startMethodTracingFd(String traceFileName, FileDescriptor fd, int bufferSize, int flags, boolean samplingEnabled, int intervalUs, boolean streamingOutput);
private static native void startMethodTracingFilename(String traceFileName, int bufferSize, int flags, boolean samplingEnabled, int intervalUs);
/**
@@ -236,6 +255,7 @@ private static int checkBufferSize(int bufferSize) {
* @return the CPU usage. A value of -1 means the system does not support
* this feature.
*/
+ @FastNative
public static native long threadCpuTimeNanos();
/**
@@ -276,6 +296,7 @@ public static int setGlobalAllocationLimit(int limit) {
/**
* Dumps a list of loaded class to the log file.
*/
+ @FastNative
public static native void printLoadedClasses(int flags);
/**
@@ -283,6 +304,7 @@ public static int setGlobalAllocationLimit(int limit) {
*
* @return the number of loaded classes
*/
+ @FastNative
public static native int getLoadedClassCount();
/**
@@ -461,4 +483,11 @@ public static Map getRuntimeStats() {
private static native String getRuntimeStatInternal(int statId);
private static native String[] getRuntimeStatsInternal();
+
+ /**
+ * Attaches an agent to the VM.
+ *
+ * @param agent The path to the agent .so file plus optional agent arguments.
+ */
+ public static native void attachAgent(String agent) throws IOException;
}
diff --git a/dalvik/src/main/java/org/apache/harmony/dalvik/NativeTestTarget.java b/dalvik/src/main/java/org/apache/harmony/dalvik/NativeTestTarget.java
index 5daf6a02f..a9efabe88 100644
--- a/dalvik/src/main/java/org/apache/harmony/dalvik/NativeTestTarget.java
+++ b/dalvik/src/main/java/org/apache/harmony/dalvik/NativeTestTarget.java
@@ -16,6 +16,9 @@
package org.apache.harmony.dalvik;
+import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.FastNative;
+
/**
* Methods used to test calling into native code. The methods in this
* class are all effectively no-ops and may be used to test the mechanisms
@@ -25,16 +28,42 @@ public final class NativeTestTarget {
public NativeTestTarget() {
}
- public static native synchronized void emptyJniStaticSynchronizedMethod0();
+ /**
+ * This is used to benchmark dalvik's inline natives.
+ */
+ public static void emptyInlineMethod() {
+ }
+
+ /**
+ * This is used to benchmark dalvik's inline natives.
+ */
+ public static native void emptyInternalStaticMethod();
+ // Synchronized methods. Test normal JNI only.
+ public static native synchronized void emptyJniStaticSynchronizedMethod0();
public native synchronized void emptyJniSynchronizedMethod0();
+ // Static methods without object parameters. Test all optimization combinations.
+
+ // Normal native.
public static native void emptyJniStaticMethod0();
+ // Normal native.
+ public static native void emptyJniStaticMethod6(int a, int b, int c, int d, int e, int f);
- public native void emptyJniMethod0();
+ @FastNative
+ public static native void emptyJniStaticMethod0_Fast();
+ @FastNative
+ public static native void emptyJniStaticMethod6_Fast(int a, int b, int c, int d, int e, int f);
- public static native void emptyJniStaticMethod6(int a, int b, int c, int d, int e, int f);
+ @CriticalNative
+ public static native void emptyJniStaticMethod0_Critical();
+ @CriticalNative
+ public static native void emptyJniStaticMethod6_Critical(int a, int b, int c, int d, int e, int f);
+ // Instance methods or methods with object parameters. Test {Normal, @FastNative} combinations.
+ // Normal native.
+ public native void emptyJniMethod0();
+ // Normal native.
public native void emptyJniMethod6(int a, int b, int c, int d, int e, int f);
/**
@@ -43,20 +72,30 @@ public NativeTestTarget() {
* parsing the signature. All six values should be null
* references.
*/
+ // Normal native.
public static native void emptyJniStaticMethod6L(String a, String[] b,
int[][] c, Object d, Object[] e, Object[][][][] f);
+ // Normal native.
public native void emptyJniMethod6L(String a, String[] b,
int[][] c, Object d, Object[] e, Object[][][][] f);
- /**
- * This is used to benchmark dalvik's inline natives.
- */
- public static void emptyInlineMethod() {
- }
+ @FastNative
+ public native void emptyJniMethod0_Fast();
+ @FastNative
+ public native void emptyJniMethod6_Fast(int a, int b, int c, int d, int e, int f);
/**
- * This is used to benchmark dalvik's inline natives.
+ * This is an empty native static method with six args, hooked up
+ * using JNI. These have more complex args to show the cost of
+ * parsing the signature. All six values should be null
+ * references.
*/
- public static native void emptyInternalStaticMethod();
+ @FastNative
+ public static native void emptyJniStaticMethod6L_Fast(String a, String[] b,
+ int[][] c, Object d, Object[] e, Object[][][][] f);
+
+ @FastNative
+ public native void emptyJniMethod6L_Fast(String a, String[] b,
+ int[][] c, Object d, Object[] e, Object[][][][] f);
}
diff --git a/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmServer.java b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmServer.java
index 7717fd999..5a2c06dff 100644
--- a/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmServer.java
+++ b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmServer.java
@@ -16,6 +16,7 @@
package org.apache.harmony.dalvik.ddmc;
+import dalvik.annotation.optimization.FastNative;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
@@ -97,6 +98,7 @@ public static void sendChunk(Chunk chunk) {
}
/* send a chunk to the DDM server */
+ @FastNative
native private static void nativeSendChunk(int type, byte[] data,
int offset, int length);
diff --git a/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmVmInternal.java b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmVmInternal.java
index 01293b057..786efe7f1 100644
--- a/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmVmInternal.java
+++ b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmVmInternal.java
@@ -16,6 +16,8 @@
package org.apache.harmony.dalvik.ddmc;
+import dalvik.annotation.optimization.FastNative;
+
/**
* Declarations for some VM-internal DDM stuff.
*/
@@ -40,6 +42,7 @@ private DdmVmInternal() {}
* @return true on success. false if 'when' is bad or if there was
* an internal error.
*/
+ @FastNative
native public static boolean heapInfoNotify(int when);
/**
@@ -74,11 +77,13 @@ native public static boolean heapSegmentNotify(int when, int what,
* Return a boolean indicating whether or not the "recent allocation"
* feature is currently enabled.
*/
+ @FastNative
native public static boolean getRecentAllocationStatus();
/**
* Fill a buffer with data on recent heap allocations.
*/
+ @FastNative
native public static byte[] getRecentAllocations();
}
diff --git a/dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.cpp b/dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.cpp
index 52f22a80a..9a934f6f9 100644
--- a/dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.cpp
+++ b/dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.cpp
@@ -19,25 +19,62 @@
#include "JNIHelp.h"
#include "JniConstants.h"
+static void NativeTestTarget_emptyJniStaticSynchronizedMethod0(JNIEnv*, jclass) { }
+static void NativeTestTarget_emptyJniSynchronizedMethod0(JNIEnv*, jclass) { }
+
+static JNINativeMethod gMethods_NormalOnly[] = {
+ NATIVE_METHOD(NativeTestTarget, emptyJniStaticSynchronizedMethod0, "()V"),
+ NATIVE_METHOD(NativeTestTarget, emptyJniSynchronizedMethod0, "()V"),
+};
+
+
static void NativeTestTarget_emptyJniMethod0(JNIEnv*, jobject) { }
-static void NativeTestTarget_emptyJniMethod6(JNIEnv*, jclass, int, int, int, int, int, int) { }
-static void NativeTestTarget_emptyJniMethod6L(JNIEnv*, jclass, jobject, jarray, jarray, jobject, jarray, jarray) { }
+static void NativeTestTarget_emptyJniMethod6(JNIEnv*, jobject, int, int, int, int, int, int) { }
+static void NativeTestTarget_emptyJniMethod6L(JNIEnv*, jobject, jobject, jarray, jarray, jobject, jarray, jarray) { }
+static void NativeTestTarget_emptyJniStaticMethod6L(JNIEnv*, jclass, jobject, jarray, jarray, jobject, jarray, jarray) { }
+
static void NativeTestTarget_emptyJniStaticMethod0(JNIEnv*, jclass) { }
static void NativeTestTarget_emptyJniStaticMethod6(JNIEnv*, jclass, int, int, int, int, int, int) { }
-static void NativeTestTarget_emptyJniStaticMethod6L(JNIEnv*, jclass, jobject, jarray, jarray, jobject, jarray, jarray) { }
-static void NativeTestTarget_emptyJniStaticSynchronizedMethod0(JNIEnv*, jclass) { }
-static void NativeTestTarget_emptyJniSynchronizedMethod0(JNIEnv*, jclass) { }
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(NativeTestTarget, emptyJniMethod0, "()V"),
NATIVE_METHOD(NativeTestTarget, emptyJniMethod6, "(IIIIII)V"),
NATIVE_METHOD(NativeTestTarget, emptyJniMethod6L, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
+ NATIVE_METHOD(NativeTestTarget, emptyJniStaticMethod6L, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
NATIVE_METHOD(NativeTestTarget, emptyJniStaticMethod0, "()V"),
NATIVE_METHOD(NativeTestTarget, emptyJniStaticMethod6, "(IIIIII)V"),
- NATIVE_METHOD(NativeTestTarget, emptyJniStaticMethod6L, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
- NATIVE_METHOD(NativeTestTarget, emptyJniStaticSynchronizedMethod0, "()V"),
- NATIVE_METHOD(NativeTestTarget, emptyJniSynchronizedMethod0, "()V"),
+};
+
+static void NativeTestTarget_emptyJniMethod0_Fast(JNIEnv*, jobject) { }
+static void NativeTestTarget_emptyJniMethod6_Fast(JNIEnv*, jobject, int, int, int, int, int, int) { }
+static void NativeTestTarget_emptyJniMethod6L_Fast(JNIEnv*, jobject, jobject, jarray, jarray, jobject, jarray, jarray) { }
+static void NativeTestTarget_emptyJniStaticMethod6L_Fast(JNIEnv*, jclass, jobject, jarray, jarray, jobject, jarray, jarray) { }
+
+static void NativeTestTarget_emptyJniStaticMethod0_Fast(JNIEnv*, jclass) { }
+static void NativeTestTarget_emptyJniStaticMethod6_Fast(JNIEnv*, jclass, int, int, int, int, int, int) { }
+
+static JNINativeMethod gMethods_Fast[] = {
+ NATIVE_METHOD(NativeTestTarget, emptyJniMethod0_Fast, "()V"),
+ NATIVE_METHOD(NativeTestTarget, emptyJniMethod6_Fast, "(IIIIII)V"),
+ NATIVE_METHOD(NativeTestTarget, emptyJniMethod6L_Fast, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
+ NATIVE_METHOD(NativeTestTarget, emptyJniStaticMethod6L_Fast, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
+ NATIVE_METHOD(NativeTestTarget, emptyJniStaticMethod0_Fast, "()V"),
+ NATIVE_METHOD(NativeTestTarget, emptyJniStaticMethod6_Fast, "(IIIIII)V"),
+};
+
+
+static void NativeTestTarget_emptyJniStaticMethod0_Critical() { }
+static void NativeTestTarget_emptyJniStaticMethod6_Critical( int, int, int, int, int, int) { }
+
+static JNINativeMethod gMethods_Critical[] = {
+ NATIVE_METHOD(NativeTestTarget, emptyJniStaticMethod0_Critical, "()V"),
+ NATIVE_METHOD(NativeTestTarget, emptyJniStaticMethod6_Critical, "(IIIIII)V"),
};
int register_org_apache_harmony_dalvik_NativeTestTarget(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "org/apache/harmony/dalvik/NativeTestTarget", gMethods, NELEM(gMethods));
+ jniRegisterNativeMethods(env, "org/apache/harmony/dalvik/NativeTestTarget", gMethods_NormalOnly, NELEM(gMethods_NormalOnly));
+ jniRegisterNativeMethods(env, "org/apache/harmony/dalvik/NativeTestTarget", gMethods, NELEM(gMethods));
+ jniRegisterNativeMethods(env, "org/apache/harmony/dalvik/NativeTestTarget", gMethods_Fast, NELEM(gMethods_Fast));
+ jniRegisterNativeMethods(env, "org/apache/harmony/dalvik/NativeTestTarget", gMethods_Critical, NELEM(gMethods_Critical));
+
+ return 0;
}
diff --git a/dalvik/src/test/java/dalvik/system/CloseGuardMonitor.java b/dalvik/src/test/java/dalvik/system/CloseGuardMonitor.java
deleted file mode 100644
index b5bf380e2..000000000
--- a/dalvik/src/test/java/dalvik/system/CloseGuardMonitor.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2014 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 dalvik.system.CloseGuard.Reporter;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.lang.ref.WeakReference;
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/**
- * Provides support for detecting issues found by {@link CloseGuard} from within tests.
- *
- * This is a best effort as it relies on both {@link CloseGuard} being enabled and being able to
- * force a GC and finalization, none of which are directly controllable by this.
- *
- *
This is loaded using reflection by the AbstractResourceLeakageDetectorTestCase class as that
- * class needs to run on the reference implementation which does not have this class. It implements
- * {@link Runnable} because that is simpler than trying to manage a specialized interface.
- *
- * @hide
- */
-public class CloseGuardMonitor implements Runnable {
- /**
- * The {@link Reporter} instance used to receive warnings from {@link CloseGuard}.
- */
- private final Reporter closeGuardReporter;
-
- /**
- * The list of allocation sites that {@link CloseGuard} has reported as not being released.
- *
- *
Is thread safe as this will be called during finalization and so there are no guarantees
- * as to whether it will be called concurrently or not.
- */
- private final List closeGuardAllocationSites = new CopyOnWriteArrayList<>();
-
- /**
- * Default constructor required for reflection.
- */
- public CloseGuardMonitor() {
- System.logI("Creating CloseGuard monitor");
-
- // Save current reporter.
- closeGuardReporter = CloseGuard.getReporter();
-
- // Override the reporter with our own which collates the allocation sites.
- CloseGuard.setReporter(new Reporter() {
- @Override
- public void report(String message, Throwable allocationSite) {
- // Ignore message as it's always the same.
- closeGuardAllocationSites.add(allocationSite);
- }
- });
- }
-
- /**
- * Check to see whether any resources monitored by {@link CloseGuard} were not released before
- * they were garbage collected.
- */
- @Override
- public void run() {
- // Create a weak reference to an object so that we can detect when it is garbage collected.
- WeakReference reference = new WeakReference<>(new Object());
-
- try {
- // 'Force' a GC and finalize to cause CloseGuards to report warnings. Doesn't loop
- // forever as there are no guarantees that the following code does anything at all so
- // don't want a potential infinite loop.
- Runtime runtime = Runtime.getRuntime();
- for (int i = 0; i < 20; ++i) {
- runtime.gc();
- System.runFinalization();
- try {
- Thread.sleep(1);
- } catch (InterruptedException e) {
- throw new AssertionError(e);
- }
-
- // Check to see if the weak reference has been garbage collected.
- if (reference.get() == null) {
- System.logI("Sentry object has been freed so assuming CloseGuards have reported"
- + " any resource leakages");
- break;
- }
- }
- } finally {
- // Restore the reporter.
- CloseGuard.setReporter(closeGuardReporter);
- }
-
- if (!closeGuardAllocationSites.isEmpty()) {
- StringWriter writer = new StringWriter();
- PrintWriter printWriter = new PrintWriter(writer);
- int i = 0;
- for (Throwable allocationSite : closeGuardAllocationSites) {
- printWriter.print(++i);
- printWriter.print(") ");
- allocationSite.printStackTrace(printWriter);
- printWriter.println(" --------------------------------");
- }
- throw new AssertionError("Potential resource leakage detected:\n" + writer);
- }
- }
-}
diff --git a/dalvik/src/test/java/dalvik/system/CloseGuardTest.java b/dalvik/src/test/java/dalvik/system/CloseGuardTest.java
new file mode 100644
index 000000000..a1d1f42b6
--- /dev/null
+++ b/dalvik/src/test/java/dalvik/system/CloseGuardTest.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2016 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 org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * Tests {@link CloseGuard}.
+ */
+public class CloseGuardTest {
+
+ /**
+ * Resets the {@link CloseGuard#ENABLED} state back to the value it had when the test started.
+ */
+ @Rule
+ public TestRule rule = this::preserveEnabledState;
+
+ private Statement preserveEnabledState(final Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ boolean oldEnabledState = CloseGuard.isEnabled();
+ try {
+ base.evaluate();
+ } finally {
+ CloseGuard.setEnabled(oldEnabledState);
+ }
+ }
+ };
+ }
+
+ @Test
+ public void testEnabled_NotOpen() throws Throwable {
+ CloseGuard.setEnabled(true);
+ ResourceOwner owner = new ResourceOwner();
+ assertUnreleasedResources(owner, 0);
+ }
+
+ @Test
+ public void testEnabled_OpenNotClosed() throws Throwable {
+ CloseGuard.setEnabled(true);
+ ResourceOwner owner = new ResourceOwner();
+ owner.open();
+ assertUnreleasedResources(owner, 1);
+ }
+
+ @Test
+ public void testEnabled_OpenThenClosed() throws Throwable {
+ CloseGuard.setEnabled(true);
+ ResourceOwner owner = new ResourceOwner();
+ owner.open();
+ owner.close();
+ assertUnreleasedResources(owner, 0);
+ }
+
+ @Test
+ public void testEnabledWhenCreated_DisabledWhenOpen() throws Throwable {
+ CloseGuard.setEnabled(true);
+ ResourceOwner owner = new ResourceOwner();
+ CloseGuard.setEnabled(false);
+ owner.open();
+
+ // Although the resource was not released it should not report it because CloseGuard was
+ // not enabled when the CloseGuard was opened.
+ assertUnreleasedResources(owner, 0);
+ }
+
+ @Test
+ public void testEnabledWhenOpened_DisabledWhenFinalized() throws Throwable {
+ CloseGuard.setEnabled(true);
+ ResourceOwner owner = new ResourceOwner();
+ owner.open();
+ CloseGuard.setEnabled(false);
+
+ // Although the resource was not released it should not report it because CloseGuard was
+ // not enabled when the CloseGuard was finalized.
+ assertUnreleasedResources(owner, 0);
+ }
+
+ @Test
+ public void testDisabled_NotOpen() throws Throwable {
+ CloseGuard.setEnabled(false);
+ ResourceOwner owner = new ResourceOwner();
+ assertUnreleasedResources(owner, 0);
+ }
+
+ @Test
+ public void testDisabled_OpenNotClosed() throws Throwable {
+ CloseGuard.setEnabled(false);
+ ResourceOwner owner = new ResourceOwner();
+ owner.open();
+ assertUnreleasedResources(owner, 0);
+ }
+
+ @Test
+ public void testDisabled_OpenThenClosed() throws Throwable {
+ CloseGuard.setEnabled(false);
+ ResourceOwner owner = new ResourceOwner();
+ owner.open();
+ owner.close();
+ assertUnreleasedResources(owner, 0);
+ }
+
+ @Test
+ public void testDisabledWhenCreated_EnabledWhenOpen() throws Throwable {
+ CloseGuard.setEnabled(false);
+ ResourceOwner owner = new ResourceOwner();
+ CloseGuard.setEnabled(true);
+ owner.open();
+
+ // Although the resource was not released it should not report it because CloseGuard was
+ // not enabled when the CloseGuard was created.
+ assertUnreleasedResources(owner, 0);
+ }
+
+ private void assertUnreleasedResources(ResourceOwner owner, int expectedCount)
+ throws Throwable {
+ try {
+ CloseGuardSupport.getFinalizerChecker().accept(owner, expectedCount);
+ } finally {
+ // Close the resource so that CloseGuard does not generate a warning for real when it
+ // is actually finalized.
+ owner.close();
+ }
+ }
+
+ /**
+ * A test user of {@link CloseGuard}.
+ */
+ private static class ResourceOwner {
+
+ private final CloseGuard closeGuard;
+
+ ResourceOwner() {
+ closeGuard = CloseGuard.get();
+ }
+
+ public void open() {
+ closeGuard.open("close");
+ }
+
+ public void close() {
+ closeGuard.close();
+ }
+
+ /**
+ * Make finalize public so that it can be tested directly without relying on garbage
+ * collection to trigger it.
+ */
+ @Override
+ public void finalize() throws Throwable {
+ closeGuard.warnIfOpen();
+ super.finalize();
+ }
+ }
+}
diff --git a/dalvik/test-rules/src/main/java/dalvik/system/CloseGuardSupport.java b/dalvik/test-rules/src/main/java/dalvik/system/CloseGuardSupport.java
new file mode 100644
index 000000000..7871795b6
--- /dev/null
+++ b/dalvik/test-rules/src/main/java/dalvik/system/CloseGuardSupport.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2016 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.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * Provides support for testing classes that use {@link CloseGuard} in order to detect resource
+ * leakages.
+ *
+ * This class should not be used directly by tests as that will prevent them from being
+ * compilable and testable on OpenJDK platform. Instead they should use
+ * {@code libcore.junit.util.ResourceLeakageDetector} which accesses the capabilities of this using
+ * reflection and if it cannot find it (because it is running on OpenJDK) then it will just skip
+ * leakage detection.
+ *
+ *
This provides two entry points that are accessed reflectively:
+ *
+ *
+ * The {@link #getRule()} method. This returns a {@link TestRule} that will fail a test if it
+ * detects any resources that were allocated during the test but were not released.
+ *
+ *
This only tracks resources that were allocated on the test thread, although it does not care
+ * what thread they were released on. This avoids flaky false positives where a background thread
+ * allocates a resource during a test but releases it after the test.
+ *
+ *
It is still possible to have a false positive in the case where the test causes a caching
+ * mechanism to open a resource and hold it open past the end of the test. In that case if there is
+ * no way to clear the cached data then it should be relatively simple to move the code that invokes
+ * the caching mechanism to outside the scope of this rule. i.e.
+ *
+ *
{@code
+ * @Rule
+ * public final TestRule ruleChain = org.junit.rules.RuleChain
+ * .outerRule(new ...invoke caching mechanism...)
+ * .around(CloseGuardSupport.getRule());
+ * }
+ *
+ *
+ * The {@link #getFinalizerChecker()} method. This returns a {@link BiConsumer} that takes an
+ * object that owns resources and an expected number of unreleased resources. It will call the
+ * {@link Object#finalize()} method on the object using reflection and throw an
+ * {@link AssertionError} if the number of reported unreleased resources does not match the
+ * expected number.
+ *
+ *
+ */
+public class CloseGuardSupport {
+
+ private static final TestRule CLOSE_GUARD_RULE = new FailTestWhenResourcesNotClosedRule();
+
+ /**
+ * Get a {@link TestRule} that will detect when resources that use the {@link CloseGuard}
+ * mechanism are not cleaned up properly by a test.
+ *
+ * If the {@link CloseGuard} mechanism is not supported, e.g. on OpenJDK, then the returned
+ * rule does nothing.
+ */
+ public static TestRule getRule() {
+ return CLOSE_GUARD_RULE;
+ }
+
+ private CloseGuardSupport() {
+ }
+
+ /**
+ * Fails a test when resources are not cleaned up properly.
+ */
+ private static class FailTestWhenResourcesNotClosedRule implements TestRule {
+ /**
+ * Returns a {@link Statement} that will fail the test if it ends with unreleased resources.
+ * @param base the test to be run.
+ */
+ public Statement apply(Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ // Get the previous tracker so that it can be restored afterwards.
+ CloseGuard.Tracker previousTracker = CloseGuard.getTracker();
+ // Get the previous enabled state so that it can be restored afterwards.
+ boolean previousEnabled = CloseGuard.isEnabled();
+ TestCloseGuardTracker tracker = new TestCloseGuardTracker();
+ Throwable thrown = null;
+ try {
+ // Set the test tracker and enable close guard detection.
+ CloseGuard.setTracker(tracker);
+ CloseGuard.setEnabled(true);
+ base.evaluate();
+ } catch (Throwable throwable) {
+ // Catch and remember the throwable so that it can be rethrown in the
+ // finally block.
+ thrown = throwable;
+ } finally {
+ // Restore the previous tracker and enabled state.
+ CloseGuard.setEnabled(previousEnabled);
+ CloseGuard.setTracker(previousTracker);
+
+ Collection allocationSites =
+ tracker.getAllocationSitesForUnreleasedResources();
+ if (!allocationSites.isEmpty()) {
+ if (thrown == null) {
+ thrown = new IllegalStateException(
+ "Unreleased resources found in test");
+ }
+ for (Throwable allocationSite : allocationSites) {
+ thrown.addSuppressed(allocationSite);
+ }
+ }
+ if (thrown != null) {
+ throw thrown;
+ }
+ }
+ }
+ };
+ }
+ }
+
+ /**
+ * A tracker that keeps a record of the allocation sites for all resources allocated but not
+ * yet released.
+ *
+ * It only tracks resources allocated for the test thread.
+ */
+ private static class TestCloseGuardTracker implements CloseGuard.Tracker {
+
+ /**
+ * A set would be preferable but this is the closest that matches the concurrency
+ * requirements for the use case which prioritise speed of addition and removal over
+ * iteration and access.
+ */
+ private final Set allocationSites =
+ Collections.newSetFromMap(new ConcurrentHashMap<>());
+
+ private final Thread testThread = Thread.currentThread();
+
+ @Override
+ public void open(Throwable allocationSite) {
+ if (Thread.currentThread() == testThread) {
+ allocationSites.add(allocationSite);
+ }
+ }
+
+ @Override
+ public void close(Throwable allocationSite) {
+ // Closing the resource twice could pass null into here.
+ if (allocationSite != null) {
+ allocationSites.remove(allocationSite);
+ }
+ }
+
+ /**
+ * Get the collection of allocation sites for any unreleased resources.
+ */
+ Collection getAllocationSitesForUnreleasedResources() {
+ return new ArrayList<>(allocationSites);
+ }
+ }
+
+ private static final BiConsumer FINALIZER_CHECKER
+ = new BiConsumer() {
+ @Override
+ public void accept(Object resourceOwner, Integer expectedCount) {
+ finalizerChecker(resourceOwner, expectedCount);
+ }
+ };
+
+ /**
+ * Get access to a {@link BiConsumer} that will determine how many unreleased resources the
+ * first parameter owns and throw a {@link AssertionError} if that does not match the
+ * expected number of resources specified by the second parameter.
+ *
+ * This uses a {@link BiConsumer} as it is a standard interface that is available in all
+ * environments. That helps avoid the caller from having compile time dependencies on this
+ * class which will not be available on OpenJDK.
+ */
+ public static BiConsumer getFinalizerChecker() {
+ return FINALIZER_CHECKER;
+ }
+
+ /**
+ * Checks that the supplied {@code resourceOwner} has overridden the {@link Object#finalize()}
+ * method and uses {@link CloseGuard#warnIfOpen()} correctly to detect when the resource is
+ * not released.
+ *
+ * @param resourceOwner the owner of the resource protected by {@link CloseGuard}.
+ * @param expectedCount the expected number of unreleased resources to be held by the owner.
+ *
+ */
+ private static void finalizerChecker(Object resourceOwner, int expectedCount) {
+ Class> clazz = resourceOwner.getClass();
+ Method finalizer = null;
+ while (clazz != null && clazz != Object.class) {
+ try {
+ finalizer = clazz.getDeclaredMethod("finalize");
+ break;
+ } catch (NoSuchMethodException e) {
+ // Carry on up the class hierarchy.
+ clazz = clazz.getSuperclass();
+ }
+ }
+
+ if (finalizer == null) {
+ // No finalizer method could be found.
+ throw new AssertionError("Class " + resourceOwner.getClass().getName()
+ + " does not have a finalize() method");
+ }
+
+ // Make the method accessible.
+ finalizer.setAccessible(true);
+
+ CloseGuard.Reporter oldReporter = CloseGuard.getReporter();
+ try {
+ CollectingReporter reporter = new CollectingReporter();
+ CloseGuard.setReporter(reporter);
+
+ // Invoke the finalizer to cause it to get CloseGuard to report a problem if it has
+ // not yet been closed.
+ try {
+ finalizer.invoke(resourceOwner);
+ } catch (ReflectiveOperationException e) {
+ throw new AssertionError(
+ "Could not invoke the finalizer() method on " + resourceOwner, e);
+ }
+
+ reporter.assertUnreleasedResources(expectedCount);
+ } finally {
+ CloseGuard.setReporter(oldReporter);
+ }
+ }
+
+ /**
+ * A {@link CloseGuard.Reporter} that collects any reports about unreleased resources.
+ */
+ private static class CollectingReporter implements CloseGuard.Reporter {
+
+ private final Thread callingThread = Thread.currentThread();
+
+ private final List unreleasedResourceAllocationSites = new ArrayList<>();
+
+ @Override
+ public void report(String message, Throwable allocationSite) {
+ // Only care about resources that are not reported on this thread.
+ if (callingThread == Thread.currentThread()) {
+ unreleasedResourceAllocationSites.add(allocationSite);
+ }
+ }
+
+ void assertUnreleasedResources(int expectedCount) {
+ int unreleasedResourceCount = unreleasedResourceAllocationSites.size();
+ if (unreleasedResourceCount == expectedCount) {
+ return;
+ }
+
+ AssertionError error = new AssertionError(
+ "Expected " + expectedCount + " unreleased resources, found "
+ + unreleasedResourceCount + "; see suppressed exceptions for details");
+ for (Throwable unreleasedResourceAllocationSite : unreleasedResourceAllocationSites) {
+ error.addSuppressed(unreleasedResourceAllocationSite);
+ }
+ throw error;
+ }
+ }
+}
diff --git a/dalvik/test-rules/src/test/java/dalvik/system/CloseGuardSupportTest.java b/dalvik/test-rules/src/test/java/dalvik/system/CloseGuardSupportTest.java
new file mode 100644
index 000000000..fe05710b2
--- /dev/null
+++ b/dalvik/test-rules/src/test/java/dalvik/system/CloseGuardSupportTest.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2016 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.Collections;
+import java.util.List;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.RunWith;
+import org.junit.runner.notification.Failure;
+import org.junit.runners.JUnit4;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+@RunWith(JUnit4.class)
+public class CloseGuardSupportTest {
+
+ @Test
+ public void testDoesReleaseResource() {
+ List failures = JUnitCore.runClasses(DoesReleaseResource.class).getFailures();
+ assertEquals(Collections.emptyList(), failures);
+ }
+
+ public static class DoesReleaseResource {
+ @Rule public TestRule rule = CloseGuardSupport.getRule();
+ @Test public void test() {
+ CloseGuard closeGuard = CloseGuard.get();
+ closeGuard.open("test resource");
+ closeGuard.close();
+ }
+ }
+
+ @Test
+ public void testDoesReleaseResourceTwice() {
+ List failures = JUnitCore.runClasses(DoesReleaseResourceTwice.class).getFailures();
+ assertEquals(Collections.emptyList(), failures);
+ }
+
+ public static class DoesReleaseResourceTwice {
+ @Rule public TestRule rule = CloseGuardSupport.getRule();
+ @Test public void test() {
+ CloseGuard closeGuard = CloseGuard.get();
+ closeGuard.open("test resource");
+ closeGuard.close();
+ closeGuard.close();
+ }
+ }
+
+ @Test
+ public void testDoesNotReleaseResource() {
+ List failures = JUnitCore.runClasses(DoesNotReleaseResource.class).getFailures();
+ assertEquals("Failure count", 1, failures.size());
+ Failure failure = failures.get(0);
+ checkResourceNotReleased(failure, "Unreleased resources found in test");
+ }
+
+ public static class DoesNotReleaseResource {
+ @Rule public TestRule rule = CloseGuardSupport.getRule();
+ @Test public void test() {
+ CloseGuard closeGuard = CloseGuard.get();
+ closeGuard.open("test resource");
+ }
+ }
+
+ @Test
+ public void testDoesNotReleaseResourceDueToFailure() {
+ List failures = JUnitCore
+ .runClasses(DoesNotReleaseResourceDueToFailure.class)
+ .getFailures();
+ assertEquals("Failure count", 1, failures.size());
+ Failure failure = failures.get(0);
+ checkResourceNotReleased(failure, "failure");
+ }
+
+ public static class DoesNotReleaseResourceDueToFailure {
+ @Rule public TestRule rule = CloseGuardSupport.getRule();
+ @Test public void test() {
+ CloseGuard closeGuard = CloseGuard.get();
+ closeGuard.open("test resource");
+ fail("failure");
+ }
+ }
+
+ @Test
+ public void testResourceOwnerDoesNotOverrideFinalize() {
+ List failures = JUnitCore
+ .runClasses(ResourceOwnerDoesNotOverrideFinalize.class)
+ .getFailures();
+ assertEquals("Failure count", 1, failures.size());
+ Failure failure = failures.get(0);
+ assertEquals("Class java.lang.String does not have a finalize() method",
+ failure.getMessage());
+ }
+
+ public static class ResourceOwnerDoesNotOverrideFinalize {
+ @Rule public TestRule rule = CloseGuardSupport.getRule();
+ @Test
+ public void test() {
+ CloseGuardSupport.getFinalizerChecker().accept("not resource owner", 0);
+ }
+ }
+
+ @Test
+ public void testResourceOwnerOverridesFinalizeButDoesNotReportLeak() {
+ List failures = JUnitCore
+ .runClasses(ResourceOwnerOverridesFinalizeButDoesNotReportLeak.class)
+ .getFailures();
+ assertEquals("Failure count", 1, failures.size());
+ Failure failure = failures.get(0);
+ assertEquals("Expected 1 unreleased resources, found 0;"
+ + " see suppressed exceptions for details",
+ failure.getMessage());
+ }
+
+ public static class ResourceOwnerOverridesFinalizeButDoesNotReportLeak {
+ @Rule public TestRule rule = CloseGuardSupport.getRule();
+ @Test
+ public void test() {
+ CloseGuardSupport.getFinalizerChecker().accept(new Object() {
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ }
+ }, 1);
+ }
+ }
+
+ @Test
+ public void testResourceOwnerOverridesFinalizeAndReportsLeak() {
+ List failures = JUnitCore
+ .runClasses(ResourceOwnerOverridesFinalizeAndReportsLeak.class)
+ .getFailures();
+ assertEquals("Failure count", 1, failures.size());
+ Failure failure = failures.get(0);
+ checkResourceNotReleased(failure, "Unreleased resources found in test");
+ }
+
+ public static class ResourceOwnerOverridesFinalizeAndReportsLeak {
+ @Rule public TestRule rule = CloseGuardSupport.getRule();
+ @Test
+ public void test() {
+ CloseGuardSupport.getFinalizerChecker().accept(new Object() {
+ private CloseGuard guard = CloseGuard.get();
+ {
+ guard.open("test resource");
+ }
+ @Override
+ protected void finalize() throws Throwable {
+ guard.warnIfOpen();
+ super.finalize();
+ }
+ }, 1);
+ }
+ }
+
+ private void checkResourceNotReleased(Failure failure, String expectedMessage) {
+ @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+ Throwable exception = failure.getException();
+ assertEquals(expectedMessage, exception.getMessage());
+ Throwable[] suppressed = exception.getSuppressed();
+ assertEquals("Suppressed count", 1, suppressed.length);
+ exception = suppressed[0];
+ assertEquals("Explicit termination method 'test resource' not called",
+ exception.getMessage());
+ }
+}
diff --git a/dex/src/main/java/com/android/dex/Annotation.java b/dex/src/main/java/com/android/dex/Annotation.java
deleted file mode 100644
index e5ef9783b..000000000
--- a/dex/src/main/java/com/android/dex/Annotation.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex;
-
-import static com.android.dex.EncodedValueReader.ENCODED_ANNOTATION;
-
-/**
- * An annotation.
- */
-public final class Annotation implements Comparable {
- private final Dex dex;
- private final byte visibility;
- private final EncodedValue encodedAnnotation;
-
- public Annotation(Dex dex, byte visibility, EncodedValue encodedAnnotation) {
- this.dex = dex;
- this.visibility = visibility;
- this.encodedAnnotation = encodedAnnotation;
- }
-
- public byte getVisibility() {
- return visibility;
- }
-
- public EncodedValueReader getReader() {
- return new EncodedValueReader(encodedAnnotation, ENCODED_ANNOTATION);
- }
-
- public int getTypeIndex() {
- EncodedValueReader reader = getReader();
- reader.readAnnotation();
- return reader.getAnnotationType();
- }
-
- public void writeTo(Dex.Section out) {
- out.writeByte(visibility);
- encodedAnnotation.writeTo(out);
- }
-
- @Override public int compareTo(Annotation other) {
- return encodedAnnotation.compareTo(other.encodedAnnotation);
- }
-
- @Override public String toString() {
- return dex == null
- ? visibility + " " + getTypeIndex()
- : visibility + " " + dex.typeNames().get(getTypeIndex());
- }
-}
diff --git a/dex/src/main/java/com/android/dex/ClassData.java b/dex/src/main/java/com/android/dex/ClassData.java
deleted file mode 100644
index 840756c5b..000000000
--- a/dex/src/main/java/com/android/dex/ClassData.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex;
-
-public final class ClassData {
- private final Field[] staticFields;
- private final Field[] instanceFields;
- private final Method[] directMethods;
- private final Method[] virtualMethods;
-
- public ClassData(Field[] staticFields, Field[] instanceFields,
- Method[] directMethods, Method[] virtualMethods) {
- this.staticFields = staticFields;
- this.instanceFields = instanceFields;
- this.directMethods = directMethods;
- this.virtualMethods = virtualMethods;
- }
-
- public Field[] getStaticFields() {
- return staticFields;
- }
-
- public Field[] getInstanceFields() {
- return instanceFields;
- }
-
- public Method[] getDirectMethods() {
- return directMethods;
- }
-
- public Method[] getVirtualMethods() {
- return virtualMethods;
- }
-
- public Field[] allFields() {
- Field[] result = new Field[staticFields.length + instanceFields.length];
- System.arraycopy(staticFields, 0, result, 0, staticFields.length);
- System.arraycopy(instanceFields, 0, result, staticFields.length, instanceFields.length);
- return result;
- }
-
- public Method[] allMethods() {
- Method[] result = new Method[directMethods.length + virtualMethods.length];
- System.arraycopy(directMethods, 0, result, 0, directMethods.length);
- System.arraycopy(virtualMethods, 0, result, directMethods.length, virtualMethods.length);
- return result;
- }
-
- public static class Field {
- private final int fieldIndex;
- private final int accessFlags;
-
- public Field(int fieldIndex, int accessFlags) {
- this.fieldIndex = fieldIndex;
- this.accessFlags = accessFlags;
- }
-
- public int getFieldIndex() {
- return fieldIndex;
- }
-
- public int getAccessFlags() {
- return accessFlags;
- }
- }
-
- public static class Method {
- private final int methodIndex;
- private final int accessFlags;
- private final int codeOffset;
-
- public Method(int methodIndex, int accessFlags, int codeOffset) {
- this.methodIndex = methodIndex;
- this.accessFlags = accessFlags;
- this.codeOffset = codeOffset;
- }
-
- public int getMethodIndex() {
- return methodIndex;
- }
-
- public int getAccessFlags() {
- return accessFlags;
- }
-
- public int getCodeOffset() {
- return codeOffset;
- }
- }
-}
diff --git a/dex/src/main/java/com/android/dex/ClassDef.java b/dex/src/main/java/com/android/dex/ClassDef.java
deleted file mode 100644
index b3225ec0e..000000000
--- a/dex/src/main/java/com/android/dex/ClassDef.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex;
-
-/**
- * A type definition.
- */
-public final class ClassDef {
- public static final int NO_INDEX = -1;
- private final Dex buffer;
- private final int offset;
- private final int typeIndex;
- private final int accessFlags;
- private final int supertypeIndex;
- private final int interfacesOffset;
- private final int sourceFileIndex;
- private final int annotationsOffset;
- private final int classDataOffset;
- private final int staticValuesOffset;
-
- public ClassDef(Dex buffer, int offset, int typeIndex, int accessFlags,
- int supertypeIndex, int interfacesOffset, int sourceFileIndex,
- int annotationsOffset, int classDataOffset, int staticValuesOffset) {
- this.buffer = buffer;
- this.offset = offset;
- this.typeIndex = typeIndex;
- this.accessFlags = accessFlags;
- this.supertypeIndex = supertypeIndex;
- this.interfacesOffset = interfacesOffset;
- this.sourceFileIndex = sourceFileIndex;
- this.annotationsOffset = annotationsOffset;
- this.classDataOffset = classDataOffset;
- this.staticValuesOffset = staticValuesOffset;
- }
-
- public int getOffset() {
- return offset;
- }
-
- public int getTypeIndex() {
- return typeIndex;
- }
-
- public int getSupertypeIndex() {
- return supertypeIndex;
- }
-
- public int getInterfacesOffset() {
- return interfacesOffset;
- }
-
- public short[] getInterfaces() {
- return buffer.readTypeList(interfacesOffset).getTypes();
- }
-
- public int getAccessFlags() {
- return accessFlags;
- }
-
- public int getSourceFileIndex() {
- return sourceFileIndex;
- }
-
- public int getAnnotationsOffset() {
- return annotationsOffset;
- }
-
- public int getClassDataOffset() {
- return classDataOffset;
- }
-
- public int getStaticValuesOffset() {
- return staticValuesOffset;
- }
-
- @Override public String toString() {
- if (buffer == null) {
- return typeIndex + " " + supertypeIndex;
- }
-
- StringBuilder result = new StringBuilder();
- result.append(buffer.typeNames().get(typeIndex));
- if (supertypeIndex != NO_INDEX) {
- result.append(" extends ").append(buffer.typeNames().get(supertypeIndex));
- }
- return result.toString();
- }
-}
diff --git a/dex/src/main/java/com/android/dex/Code.java b/dex/src/main/java/com/android/dex/Code.java
deleted file mode 100644
index 9258af795..000000000
--- a/dex/src/main/java/com/android/dex/Code.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex;
-
-public final class Code {
- private final int registersSize;
- private final int insSize;
- private final int outsSize;
- private final int debugInfoOffset;
- private final short[] instructions;
- private final Try[] tries;
- private final CatchHandler[] catchHandlers;
-
- public Code(int registersSize, int insSize, int outsSize, int debugInfoOffset,
- short[] instructions, Try[] tries, CatchHandler[] catchHandlers) {
- this.registersSize = registersSize;
- this.insSize = insSize;
- this.outsSize = outsSize;
- this.debugInfoOffset = debugInfoOffset;
- this.instructions = instructions;
- this.tries = tries;
- this.catchHandlers = catchHandlers;
- }
-
- public int getRegistersSize() {
- return registersSize;
- }
-
- public int getInsSize() {
- return insSize;
- }
-
- public int getOutsSize() {
- return outsSize;
- }
-
- public int getDebugInfoOffset() {
- return debugInfoOffset;
- }
-
- public short[] getInstructions() {
- return instructions;
- }
-
- public Try[] getTries() {
- return tries;
- }
-
- public CatchHandler[] getCatchHandlers() {
- return catchHandlers;
- }
-
- public static class Try {
- final int startAddress;
- final int instructionCount;
- final int catchHandlerIndex;
-
- Try(int startAddress, int instructionCount, int catchHandlerIndex) {
- this.startAddress = startAddress;
- this.instructionCount = instructionCount;
- this.catchHandlerIndex = catchHandlerIndex;
- }
-
- public int getStartAddress() {
- return startAddress;
- }
-
- public int getInstructionCount() {
- return instructionCount;
- }
-
- /**
- * Returns this try's catch handler index . Note that
- * this is distinct from the its catch handler offset .
- */
- public int getCatchHandlerIndex() {
- return catchHandlerIndex;
- }
- }
-
- public static class CatchHandler {
- final int[] typeIndexes;
- final int[] addresses;
- final int catchAllAddress;
- final int offset;
-
- public CatchHandler(int[] typeIndexes, int[] addresses, int catchAllAddress, int offset) {
- this.typeIndexes = typeIndexes;
- this.addresses = addresses;
- this.catchAllAddress = catchAllAddress;
- this.offset = offset;
- }
-
- public int[] getTypeIndexes() {
- return typeIndexes;
- }
-
- public int[] getAddresses() {
- return addresses;
- }
-
- public int getCatchAllAddress() {
- return catchAllAddress;
- }
-
- public int getOffset() {
- return offset;
- }
- }
-}
diff --git a/dex/src/main/java/com/android/dex/Dex.java b/dex/src/main/java/com/android/dex/Dex.java
deleted file mode 100644
index ea9b627b2..000000000
--- a/dex/src/main/java/com/android/dex/Dex.java
+++ /dev/null
@@ -1,983 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex;
-
-import com.android.dex.Code.CatchHandler;
-import com.android.dex.Code.Try;
-import com.android.dex.util.ByteInput;
-import com.android.dex.util.ByteOutput;
-import com.android.dex.util.FileUtils;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UTFDataFormatException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.AbstractList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.RandomAccess;
-import java.util.zip.Adler32;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-
-/**
- * The bytes of a dex file in memory for reading and writing. All int offsets
- * are unsigned.
- */
-public final class Dex {
- private static final int CHECKSUM_OFFSET = 8;
- private static final int CHECKSUM_SIZE = 4;
- private static final int SIGNATURE_OFFSET = CHECKSUM_OFFSET + CHECKSUM_SIZE;
- private static final int SIGNATURE_SIZE = 20;
- // Provided as a convenience to avoid a memory allocation to benefit Dalvik.
- // Note: libcore.util.EmptyArray cannot be accessed when this code isn't run on Dalvik.
- static final short[] EMPTY_SHORT_ARRAY = new short[0];
-
- private ByteBuffer data;
- private final TableOfContents tableOfContents = new TableOfContents();
- private int nextSectionStart = 0;
- private final StringTable strings = new StringTable();
- private final TypeIndexToDescriptorIndexTable typeIds = new TypeIndexToDescriptorIndexTable();
- private final TypeIndexToDescriptorTable typeNames = new TypeIndexToDescriptorTable();
- private final ProtoIdTable protoIds = new ProtoIdTable();
- private final FieldIdTable fieldIds = new FieldIdTable();
- private final MethodIdTable methodIds = new MethodIdTable();
-
- /**
- * Creates a new dex that reads from {@code data}. It is an error to modify
- * {@code data} after using it to create a dex buffer.
- */
- public Dex(byte[] data) throws IOException {
- this(ByteBuffer.wrap(data));
- }
-
- private Dex(ByteBuffer data) throws IOException {
- this.data = data;
- this.data.order(ByteOrder.LITTLE_ENDIAN);
- this.tableOfContents.readFrom(this);
- }
-
- /**
- * Creates a new empty dex of the specified size.
- */
- public Dex(int byteCount) throws IOException {
- this.data = ByteBuffer.wrap(new byte[byteCount]);
- this.data.order(ByteOrder.LITTLE_ENDIAN);
- }
-
- /**
- * Creates a new dex buffer of the dex in {@code in}, and closes {@code in}.
- */
- public Dex(InputStream in) throws IOException {
- loadFrom(in);
- }
-
- /**
- * Creates a new dex buffer from the dex file {@code file}.
- */
- public Dex(File file) throws IOException {
- if (FileUtils.hasArchiveSuffix(file.getName())) {
- ZipFile zipFile = new ZipFile(file);
- ZipEntry entry = zipFile.getEntry(DexFormat.DEX_IN_JAR_NAME);
- if (entry != null) {
- loadFrom(zipFile.getInputStream(entry));
- zipFile.close();
- } else {
- throw new DexException("Expected " + DexFormat.DEX_IN_JAR_NAME + " in " + file);
- }
- } else if (file.getName().endsWith(".dex")) {
- loadFrom(new FileInputStream(file));
- } else {
- throw new DexException("unknown output extension: " + file);
- }
- }
-
- /**
- * Creates a new dex from the contents of {@code bytes}. This API supports
- * both {@code .dex} and {@code .odex} input. Calling this constructor
- * transfers ownership of {@code bytes} to the returned Dex: it is an error
- * to access the buffer after calling this method.
- */
- public static Dex create(ByteBuffer data) throws IOException {
- data.order(ByteOrder.LITTLE_ENDIAN);
-
- // if it's an .odex file, set position and limit to the .dex section
- if (data.get(0) == 'd'
- && data.get(1) == 'e'
- && data.get(2) == 'y'
- && data.get(3) == '\n') {
- data.position(8);
- int offset = data.getInt();
- int length = data.getInt();
- data.position(offset);
- data.limit(offset + length);
- data = data.slice();
- }
-
- return new Dex(data);
- }
-
- private void loadFrom(InputStream in) throws IOException {
- ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
- byte[] buffer = new byte[8192];
-
- int count;
- while ((count = in.read(buffer)) != -1) {
- bytesOut.write(buffer, 0, count);
- }
- in.close();
-
- this.data = ByteBuffer.wrap(bytesOut.toByteArray());
- this.data.order(ByteOrder.LITTLE_ENDIAN);
- this.tableOfContents.readFrom(this);
- }
-
- private static void checkBounds(int index, int length) {
- if (index < 0 || index >= length) {
- throw new IndexOutOfBoundsException("index:" + index + ", length=" + length);
- }
- }
-
- public void writeTo(OutputStream out) throws IOException {
- byte[] buffer = new byte[8192];
- ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe
- data.clear();
- while (data.hasRemaining()) {
- int count = Math.min(buffer.length, data.remaining());
- data.get(buffer, 0, count);
- out.write(buffer, 0, count);
- }
- }
-
- public void writeTo(File dexOut) throws IOException {
- OutputStream out = new FileOutputStream(dexOut);
- writeTo(out);
- out.close();
- }
-
- public TableOfContents getTableOfContents() {
- return tableOfContents;
- }
-
- public Section open(int position) {
- if (position < 0 || position >= data.capacity()) {
- throw new IllegalArgumentException("position=" + position
- + " length=" + data.capacity());
- }
- ByteBuffer sectionData = data.duplicate();
- sectionData.order(ByteOrder.LITTLE_ENDIAN); // necessary?
- sectionData.position(position);
- sectionData.limit(data.capacity());
- return new Section("section", sectionData);
- }
-
- public Section appendSection(int maxByteCount, String name) {
- if ((maxByteCount & 3) != 0) {
- throw new IllegalStateException("Not four byte aligned!");
- }
- int limit = nextSectionStart + maxByteCount;
- ByteBuffer sectionData = data.duplicate();
- sectionData.order(ByteOrder.LITTLE_ENDIAN); // necessary?
- sectionData.position(nextSectionStart);
- sectionData.limit(limit);
- Section result = new Section(name, sectionData);
- nextSectionStart = limit;
- return result;
- }
-
- public int getLength() {
- return data.capacity();
- }
-
- public int getNextSectionStart() {
- return nextSectionStart;
- }
-
- /**
- * Returns a copy of the the bytes of this dex.
- */
- public byte[] getBytes() {
- ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe
- byte[] result = new byte[data.capacity()];
- data.position(0);
- data.get(result);
- return result;
- }
-
- public List strings() {
- return strings;
- }
-
- public List typeIds() {
- return typeIds;
- }
-
- public List typeNames() {
- return typeNames;
- }
-
- public List protoIds() {
- return protoIds;
- }
-
- public List fieldIds() {
- return fieldIds;
- }
-
- public List methodIds() {
- return methodIds;
- }
-
- public Iterable classDefs() {
- return new ClassDefIterable();
- }
-
- public TypeList readTypeList(int offset) {
- if (offset == 0) {
- return TypeList.EMPTY;
- }
- return open(offset).readTypeList();
- }
-
- public ClassData readClassData(ClassDef classDef) {
- int offset = classDef.getClassDataOffset();
- if (offset == 0) {
- throw new IllegalArgumentException("offset == 0");
- }
- return open(offset).readClassData();
- }
-
- public Code readCode(ClassData.Method method) {
- int offset = method.getCodeOffset();
- if (offset == 0) {
- throw new IllegalArgumentException("offset == 0");
- }
- return open(offset).readCode();
- }
-
- /**
- * Returns the signature of all but the first 32 bytes of this dex. The
- * first 32 bytes of dex files are not specified to be included in the
- * signature.
- */
- public byte[] computeSignature() throws IOException {
- MessageDigest digest;
- try {
- digest = MessageDigest.getInstance("SHA-1");
- } catch (NoSuchAlgorithmException e) {
- throw new AssertionError();
- }
- byte[] buffer = new byte[8192];
- ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe
- data.limit(data.capacity());
- data.position(SIGNATURE_OFFSET + SIGNATURE_SIZE);
- while (data.hasRemaining()) {
- int count = Math.min(buffer.length, data.remaining());
- data.get(buffer, 0, count);
- digest.update(buffer, 0, count);
- }
- return digest.digest();
- }
-
- /**
- * Returns the checksum of all but the first 12 bytes of {@code dex}.
- */
- public int computeChecksum() throws IOException {
- Adler32 adler32 = new Adler32();
- byte[] buffer = new byte[8192];
- ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe
- data.limit(data.capacity());
- data.position(CHECKSUM_OFFSET + CHECKSUM_SIZE);
- while (data.hasRemaining()) {
- int count = Math.min(buffer.length, data.remaining());
- data.get(buffer, 0, count);
- adler32.update(buffer, 0, count);
- }
- return (int) adler32.getValue();
- }
-
- /**
- * Generates the signature and checksum of the dex file {@code out} and
- * writes them to the file.
- */
- public void writeHashes() throws IOException {
- open(SIGNATURE_OFFSET).write(computeSignature());
- open(CHECKSUM_OFFSET).writeInt(computeChecksum());
- }
-
- /**
- * Look up a field id name index from a field index. Cheaper than:
- * {@code fieldIds().get(fieldDexIndex).getNameIndex();}
- */
- public int nameIndexFromFieldIndex(int fieldIndex) {
- checkBounds(fieldIndex, tableOfContents.fieldIds.size);
- int position = tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * fieldIndex);
- position += SizeOf.USHORT; // declaringClassIndex
- position += SizeOf.USHORT; // typeIndex
- return data.getInt(position); // nameIndex
- }
-
- public int findStringIndex(String s) {
- return Collections.binarySearch(strings, s);
- }
-
- public int findTypeIndex(String descriptor) {
- return Collections.binarySearch(typeNames, descriptor);
- }
-
- public int findFieldIndex(FieldId fieldId) {
- return Collections.binarySearch(fieldIds, fieldId);
- }
-
- public int findMethodIndex(MethodId methodId) {
- return Collections.binarySearch(methodIds, methodId);
- }
-
- public int findClassDefIndexFromTypeIndex(int typeIndex) {
- checkBounds(typeIndex, tableOfContents.typeIds.size);
- if (!tableOfContents.classDefs.exists()) {
- return -1;
- }
- for (int i = 0; i < tableOfContents.classDefs.size; i++) {
- if (typeIndexFromClassDefIndex(i) == typeIndex) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Look up a field id type index from a field index. Cheaper than:
- * {@code fieldIds().get(fieldDexIndex).getTypeIndex();}
- */
- public int typeIndexFromFieldIndex(int fieldIndex) {
- checkBounds(fieldIndex, tableOfContents.fieldIds.size);
- int position = tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * fieldIndex);
- position += SizeOf.USHORT; // declaringClassIndex
- return data.getShort(position) & 0xFFFF; // typeIndex
- }
-
- /**
- * Look up a method id declaring class index from a method index. Cheaper than:
- * {@code methodIds().get(methodIndex).getDeclaringClassIndex();}
- */
- public int declaringClassIndexFromMethodIndex(int methodIndex) {
- checkBounds(methodIndex, tableOfContents.methodIds.size);
- int position = tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * methodIndex);
- return data.getShort(position) & 0xFFFF; // declaringClassIndex
- }
-
- /**
- * Look up a method id name index from a method index. Cheaper than:
- * {@code methodIds().get(methodIndex).getNameIndex();}
- */
- public int nameIndexFromMethodIndex(int methodIndex) {
- checkBounds(methodIndex, tableOfContents.methodIds.size);
- int position = tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * methodIndex);
- position += SizeOf.USHORT; // declaringClassIndex
- position += SizeOf.USHORT; // protoIndex
- return data.getInt(position); // nameIndex
- }
-
- /**
- * Look up a parameter type ids from a method index. Cheaper than:
- * {@code readTypeList(protoIds.get(methodIds().get(methodDexIndex).getProtoIndex()).getParametersOffset()).getTypes();}
- */
- public short[] parameterTypeIndicesFromMethodIndex(int methodIndex) {
- checkBounds(methodIndex, tableOfContents.methodIds.size);
- int position = tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * methodIndex);
- position += SizeOf.USHORT; // declaringClassIndex
- int protoIndex = data.getShort(position) & 0xFFFF;
- checkBounds(protoIndex, tableOfContents.protoIds.size);
- position = tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * protoIndex);
- position += SizeOf.UINT; // shortyIndex
- position += SizeOf.UINT; // returnTypeIndex
- int parametersOffset = data.getInt(position);
- if (parametersOffset == 0) {
- return EMPTY_SHORT_ARRAY;
- }
- position = parametersOffset;
- int size = data.getInt(position);
- if (size <= 0) {
- throw new AssertionError("Unexpected parameter type list size: " + size);
- }
- position += SizeOf.UINT;
- short[] types = new short[size];
- for (int i = 0; i < size; i++) {
- types[i] = data.getShort(position);
- position += SizeOf.USHORT;
- }
- return types;
- }
-
- /**
- * Look up a method id return type index from a method index. Cheaper than:
- * {@code protoIds().get(methodIds().get(methodDexIndex).getProtoIndex()).getReturnTypeIndex();}
- */
- public int returnTypeIndexFromMethodIndex(int methodIndex) {
- checkBounds(methodIndex, tableOfContents.methodIds.size);
- int position = tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * methodIndex);
- position += SizeOf.USHORT; // declaringClassIndex
- int protoIndex = data.getShort(position) & 0xFFFF;
- checkBounds(protoIndex, tableOfContents.protoIds.size);
- position = tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * protoIndex);
- position += SizeOf.UINT; // shortyIndex
- return data.getInt(position); // returnTypeIndex
- }
-
- /**
- * Look up a descriptor index from a type index. Cheaper than:
- * {@code open(tableOfContents.typeIds.off + (index * SizeOf.TYPE_ID_ITEM)).readInt();}
- */
- public int descriptorIndexFromTypeIndex(int typeIndex) {
- checkBounds(typeIndex, tableOfContents.typeIds.size);
- int position = tableOfContents.typeIds.off + (SizeOf.TYPE_ID_ITEM * typeIndex);
- return data.getInt(position);
- }
-
- /**
- * Look up a type index index from a class def index.
- */
- public int typeIndexFromClassDefIndex(int classDefIndex) {
- checkBounds(classDefIndex, tableOfContents.classDefs.size);
- int position = tableOfContents.classDefs.off + (SizeOf.CLASS_DEF_ITEM * classDefIndex);
- return data.getInt(position);
- }
-
- /**
- * Look up an annotation directory offset from a class def index.
- */
- public int annotationDirectoryOffsetFromClassDefIndex(int classDefIndex) {
- checkBounds(classDefIndex, tableOfContents.classDefs.size);
- int position = tableOfContents.classDefs.off + (SizeOf.CLASS_DEF_ITEM * classDefIndex);
- position += SizeOf.UINT; // type
- position += SizeOf.UINT; // accessFlags
- position += SizeOf.UINT; // superType
- position += SizeOf.UINT; // interfacesOffset
- position += SizeOf.UINT; // sourceFileIndex
- return data.getInt(position);
- }
-
- /**
- * Look up interface types indices from a return type index from a method index. Cheaper than:
- * {@code ...getClassDef(classDefIndex).getInterfaces();}
- */
- public short[] interfaceTypeIndicesFromClassDefIndex(int classDefIndex) {
- checkBounds(classDefIndex, tableOfContents.classDefs.size);
- int position = tableOfContents.classDefs.off + (SizeOf.CLASS_DEF_ITEM * classDefIndex);
- position += SizeOf.UINT; // type
- position += SizeOf.UINT; // accessFlags
- position += SizeOf.UINT; // superType
- int interfacesOffset = data.getInt(position);
- if (interfacesOffset == 0) {
- return EMPTY_SHORT_ARRAY;
- }
- position = interfacesOffset;
- int size = data.getInt(position);
- if (size <= 0) {
- throw new AssertionError("Unexpected interfaces list size: " + size);
- }
- position += SizeOf.UINT;
- short[] types = new short[size];
- for (int i = 0; i < size; i++) {
- types[i] = data.getShort(position);
- position += SizeOf.USHORT;
- }
- return types;
- }
-
- public final class Section implements ByteInput, ByteOutput {
- private final String name;
- private final ByteBuffer data;
- private final int initialPosition;
-
- private Section(String name, ByteBuffer data) {
- this.name = name;
- this.data = data;
- this.initialPosition = data.position();
- }
-
- public int getPosition() {
- return data.position();
- }
-
- public int readInt() {
- return data.getInt();
- }
-
- public short readShort() {
- return data.getShort();
- }
-
- public int readUnsignedShort() {
- return readShort() & 0xffff;
- }
-
- public byte readByte() {
- return data.get();
- }
-
- public byte[] readByteArray(int length) {
- byte[] result = new byte[length];
- data.get(result);
- return result;
- }
-
- public short[] readShortArray(int length) {
- if (length == 0) {
- return EMPTY_SHORT_ARRAY;
- }
- short[] result = new short[length];
- for (int i = 0; i < length; i++) {
- result[i] = readShort();
- }
- return result;
- }
-
- public int readUleb128() {
- return Leb128.readUnsignedLeb128(this);
- }
-
- public int readUleb128p1() {
- return Leb128.readUnsignedLeb128(this) - 1;
- }
-
- public int readSleb128() {
- return Leb128.readSignedLeb128(this);
- }
-
- public void writeUleb128p1(int i) {
- writeUleb128(i + 1);
- }
-
- public TypeList readTypeList() {
- int size = readInt();
- short[] types = readShortArray(size);
- alignToFourBytes();
- return new TypeList(Dex.this, types);
- }
-
- public String readString() {
- int offset = readInt();
- int savedPosition = data.position();
- int savedLimit = data.limit();
- data.position(offset);
- data.limit(data.capacity());
- try {
- int expectedLength = readUleb128();
- String result = Mutf8.decode(this, new char[expectedLength]);
- if (result.length() != expectedLength) {
- throw new DexException("Declared length " + expectedLength
- + " doesn't match decoded length of " + result.length());
- }
- return result;
- } catch (UTFDataFormatException e) {
- throw new DexException(e);
- } finally {
- data.position(savedPosition);
- data.limit(savedLimit);
- }
- }
-
- public FieldId readFieldId() {
- int declaringClassIndex = readUnsignedShort();
- int typeIndex = readUnsignedShort();
- int nameIndex = readInt();
- return new FieldId(Dex.this, declaringClassIndex, typeIndex, nameIndex);
- }
-
- public MethodId readMethodId() {
- int declaringClassIndex = readUnsignedShort();
- int protoIndex = readUnsignedShort();
- int nameIndex = readInt();
- return new MethodId(Dex.this, declaringClassIndex, protoIndex, nameIndex);
- }
-
- public ProtoId readProtoId() {
- int shortyIndex = readInt();
- int returnTypeIndex = readInt();
- int parametersOffset = readInt();
- return new ProtoId(Dex.this, shortyIndex, returnTypeIndex, parametersOffset);
- }
-
- public ClassDef readClassDef() {
- int offset = getPosition();
- int type = readInt();
- int accessFlags = readInt();
- int supertype = readInt();
- int interfacesOffset = readInt();
- int sourceFileIndex = readInt();
- int annotationsOffset = readInt();
- int classDataOffset = readInt();
- int staticValuesOffset = readInt();
- return new ClassDef(Dex.this, offset, type, accessFlags, supertype,
- interfacesOffset, sourceFileIndex, annotationsOffset, classDataOffset,
- staticValuesOffset);
- }
-
- private Code readCode() {
- int registersSize = readUnsignedShort();
- int insSize = readUnsignedShort();
- int outsSize = readUnsignedShort();
- int triesSize = readUnsignedShort();
- int debugInfoOffset = readInt();
- int instructionsSize = readInt();
- short[] instructions = readShortArray(instructionsSize);
- Try[] tries;
- CatchHandler[] catchHandlers;
- if (triesSize > 0) {
- if (instructions.length % 2 == 1) {
- readShort(); // padding
- }
-
- /*
- * We can't read the tries until we've read the catch handlers.
- * Unfortunately they're in the opposite order in the dex file
- * so we need to read them out-of-order.
- */
- Section triesSection = open(data.position());
- skip(triesSize * SizeOf.TRY_ITEM);
- catchHandlers = readCatchHandlers();
- tries = triesSection.readTries(triesSize, catchHandlers);
- } else {
- tries = new Try[0];
- catchHandlers = new CatchHandler[0];
- }
- return new Code(registersSize, insSize, outsSize, debugInfoOffset, instructions,
- tries, catchHandlers);
- }
-
- private CatchHandler[] readCatchHandlers() {
- int baseOffset = data.position();
- int catchHandlersSize = readUleb128();
- CatchHandler[] result = new CatchHandler[catchHandlersSize];
- for (int i = 0; i < catchHandlersSize; i++) {
- int offset = data.position() - baseOffset;
- result[i] = readCatchHandler(offset);
- }
- return result;
- }
-
- private Try[] readTries(int triesSize, CatchHandler[] catchHandlers) {
- Try[] result = new Try[triesSize];
- for (int i = 0; i < triesSize; i++) {
- int startAddress = readInt();
- int instructionCount = readUnsignedShort();
- int handlerOffset = readUnsignedShort();
- int catchHandlerIndex = findCatchHandlerIndex(catchHandlers, handlerOffset);
- result[i] = new Try(startAddress, instructionCount, catchHandlerIndex);
- }
- return result;
- }
-
- private int findCatchHandlerIndex(CatchHandler[] catchHandlers, int offset) {
- for (int i = 0; i < catchHandlers.length; i++) {
- CatchHandler catchHandler = catchHandlers[i];
- if (catchHandler.getOffset() == offset) {
- return i;
- }
- }
- throw new IllegalArgumentException();
- }
-
- private CatchHandler readCatchHandler(int offset) {
- int size = readSleb128();
- int handlersCount = Math.abs(size);
- int[] typeIndexes = new int[handlersCount];
- int[] addresses = new int[handlersCount];
- for (int i = 0; i < handlersCount; i++) {
- typeIndexes[i] = readUleb128();
- addresses[i] = readUleb128();
- }
- int catchAllAddress = size <= 0 ? readUleb128() : -1;
- return new CatchHandler(typeIndexes, addresses, catchAllAddress, offset);
- }
-
- private ClassData readClassData() {
- int staticFieldsSize = readUleb128();
- int instanceFieldsSize = readUleb128();
- int directMethodsSize = readUleb128();
- int virtualMethodsSize = readUleb128();
- ClassData.Field[] staticFields = readFields(staticFieldsSize);
- ClassData.Field[] instanceFields = readFields(instanceFieldsSize);
- ClassData.Method[] directMethods = readMethods(directMethodsSize);
- ClassData.Method[] virtualMethods = readMethods(virtualMethodsSize);
- return new ClassData(staticFields, instanceFields, directMethods, virtualMethods);
- }
-
- private ClassData.Field[] readFields(int count) {
- ClassData.Field[] result = new ClassData.Field[count];
- int fieldIndex = 0;
- for (int i = 0; i < count; i++) {
- fieldIndex += readUleb128(); // field index diff
- int accessFlags = readUleb128();
- result[i] = new ClassData.Field(fieldIndex, accessFlags);
- }
- return result;
- }
-
- private ClassData.Method[] readMethods(int count) {
- ClassData.Method[] result = new ClassData.Method[count];
- int methodIndex = 0;
- for (int i = 0; i < count; i++) {
- methodIndex += readUleb128(); // method index diff
- int accessFlags = readUleb128();
- int codeOff = readUleb128();
- result[i] = new ClassData.Method(methodIndex, accessFlags, codeOff);
- }
- return result;
- }
-
- /**
- * Returns a byte array containing the bytes from {@code start} to this
- * section's current position.
- */
- private byte[] getBytesFrom(int start) {
- int end = data.position();
- byte[] result = new byte[end - start];
- data.position(start);
- data.get(result);
- return result;
- }
-
- public Annotation readAnnotation() {
- byte visibility = readByte();
- int start = data.position();
- new EncodedValueReader(this, EncodedValueReader.ENCODED_ANNOTATION).skipValue();
- return new Annotation(Dex.this, visibility, new EncodedValue(getBytesFrom(start)));
- }
-
- public EncodedValue readEncodedArray() {
- int start = data.position();
- new EncodedValueReader(this, EncodedValueReader.ENCODED_ARRAY).skipValue();
- return new EncodedValue(getBytesFrom(start));
- }
-
- public void skip(int count) {
- if (count < 0) {
- throw new IllegalArgumentException();
- }
- data.position(data.position() + count);
- }
-
- /**
- * Skips bytes until the position is aligned to a multiple of 4.
- */
- public void alignToFourBytes() {
- data.position((data.position() + 3) & ~3);
- }
-
- /**
- * Writes 0x00 until the position is aligned to a multiple of 4.
- */
- public void alignToFourBytesWithZeroFill() {
- while ((data.position() & 3) != 0) {
- data.put((byte) 0);
- }
- }
-
- public void assertFourByteAligned() {
- if ((data.position() & 3) != 0) {
- throw new IllegalStateException("Not four byte aligned!");
- }
- }
-
- public void write(byte[] bytes) {
- this.data.put(bytes);
- }
-
- public void writeByte(int b) {
- data.put((byte) b);
- }
-
- public void writeShort(short i) {
- data.putShort(i);
- }
-
- public void writeUnsignedShort(int i) {
- short s = (short) i;
- if (i != (s & 0xffff)) {
- throw new IllegalArgumentException("Expected an unsigned short: " + i);
- }
- writeShort(s);
- }
-
- public void write(short[] shorts) {
- for (short s : shorts) {
- writeShort(s);
- }
- }
-
- public void writeInt(int i) {
- data.putInt(i);
- }
-
- public void writeUleb128(int i) {
- try {
- Leb128.writeUnsignedLeb128(this, i);
- } catch (ArrayIndexOutOfBoundsException e) {
- throw new DexException("Section limit " + data.limit() + " exceeded by " + name);
- }
- }
-
- public void writeSleb128(int i) {
- try {
- Leb128.writeSignedLeb128(this, i);
- } catch (ArrayIndexOutOfBoundsException e) {
- throw new DexException("Section limit " + data.limit() + " exceeded by " + name);
- }
- }
-
- public void writeStringData(String value) {
- try {
- int length = value.length();
- writeUleb128(length);
- write(Mutf8.encode(value));
- writeByte(0);
- } catch (UTFDataFormatException e) {
- throw new AssertionError();
- }
- }
-
- public void writeTypeList(TypeList typeList) {
- short[] types = typeList.getTypes();
- writeInt(types.length);
- for (short type : types) {
- writeShort(type);
- }
- alignToFourBytesWithZeroFill();
- }
-
- /**
- * Returns the number of bytes remaining in this section.
- */
- public int remaining() {
- return data.remaining();
- }
-
- /**
- * Returns the number of bytes used by this section.
- */
- public int used() {
- return data.position() - initialPosition;
- }
- }
-
- private final class StringTable extends AbstractList implements RandomAccess {
- @Override public String get(int index) {
- checkBounds(index, tableOfContents.stringIds.size);
- return open(tableOfContents.stringIds.off + (index * SizeOf.STRING_ID_ITEM))
- .readString();
- }
- @Override public int size() {
- return tableOfContents.stringIds.size;
- }
- }
-
- private final class TypeIndexToDescriptorIndexTable extends AbstractList
- implements RandomAccess {
- @Override public Integer get(int index) {
- return descriptorIndexFromTypeIndex(index);
- }
- @Override public int size() {
- return tableOfContents.typeIds.size;
- }
- }
-
- private final class TypeIndexToDescriptorTable extends AbstractList
- implements RandomAccess {
- @Override public String get(int index) {
- return strings.get(descriptorIndexFromTypeIndex(index));
- }
- @Override public int size() {
- return tableOfContents.typeIds.size;
- }
- }
-
- private final class ProtoIdTable extends AbstractList implements RandomAccess {
- @Override public ProtoId get(int index) {
- checkBounds(index, tableOfContents.protoIds.size);
- return open(tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * index))
- .readProtoId();
- }
- @Override public int size() {
- return tableOfContents.protoIds.size;
- }
- }
-
- private final class FieldIdTable extends AbstractList implements RandomAccess {
- @Override public FieldId get(int index) {
- checkBounds(index, tableOfContents.fieldIds.size);
- return open(tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * index))
- .readFieldId();
- }
- @Override public int size() {
- return tableOfContents.fieldIds.size;
- }
- }
-
- private final class MethodIdTable extends AbstractList implements RandomAccess {
- @Override public MethodId get(int index) {
- checkBounds(index, tableOfContents.methodIds.size);
- return open(tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * index))
- .readMethodId();
- }
- @Override public int size() {
- return tableOfContents.methodIds.size;
- }
- }
-
- private final class ClassDefIterator implements Iterator {
- private final Dex.Section in = open(tableOfContents.classDefs.off);
- private int count = 0;
-
- @Override
- public boolean hasNext() {
- return count < tableOfContents.classDefs.size;
- }
- @Override
- public ClassDef next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- count++;
- return in.readClassDef();
- }
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
- }
-
- private final class ClassDefIterable implements Iterable {
- public Iterator iterator() {
- return !tableOfContents.classDefs.exists()
- ? Collections.emptySet().iterator()
- : new ClassDefIterator();
- }
- }
-}
diff --git a/dex/src/main/java/com/android/dex/DexException.java b/dex/src/main/java/com/android/dex/DexException.java
deleted file mode 100644
index ee0af18f9..000000000
--- a/dex/src/main/java/com/android/dex/DexException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex;
-
-import com.android.dex.util.ExceptionWithContext;
-
-/**
- * Thrown when there's a format problem reading, writing, or generally
- * processing a dex file.
- */
-public class DexException extends ExceptionWithContext {
- public DexException(String message) {
- super(message);
- }
-
- public DexException(Throwable cause) {
- super(cause);
- }
-}
diff --git a/dex/src/main/java/com/android/dex/DexFormat.java b/dex/src/main/java/com/android/dex/DexFormat.java
deleted file mode 100644
index c598eee03..000000000
--- a/dex/src/main/java/com/android/dex/DexFormat.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex;
-
-/**
- * Constants that show up in and are otherwise related to {@code .dex}
- * files, and helper methods for same.
- */
-public final class DexFormat {
- private DexFormat() {}
-
- /**
- * API level to target in order to produce the most modern file
- * format
- */
- public static final int API_CURRENT = 24;
-
- /** API level to target in order to suppress extended opcode usage */
- public static final int API_NO_EXTENDED_OPCODES = 13;
-
- /**
- * file name of the primary {@code .dex} file inside an
- * application or library {@code .jar} file
- */
- public static final String DEX_IN_JAR_NAME = "classes.dex";
-
- /** common prefix for all dex file "magic numbers" */
- public static final String MAGIC_PREFIX = "dex\n";
-
- /** common suffix for all dex file "magic numbers" */
- public static final String MAGIC_SUFFIX = "\0";
-
- /**
- * Dex file version number for dalvik.
- *
- * Note: Dex version 36 was loadable in some versions of Dalvik but was never fully supported or
- * completed and is not considered a valid dex file format.
- *
- */
- public static final String VERSION_CURRENT = "037";
-
- /** dex file version number for API level 13 and earlier */
- public static final String VERSION_FOR_API_13 = "035";
-
- /**
- * value used to indicate endianness of file contents
- */
- public static final int ENDIAN_TAG = 0x12345678;
-
- /**
- * Maximum addressable field or method index.
- * The largest addressable member is 0xffff, in the "instruction formats" spec as field@CCCC or
- * meth@CCCC.
- */
- public static final int MAX_MEMBER_IDX = 0xFFFF;
-
- /**
- * Maximum addressable type index.
- * The largest addressable type is 0xffff, in the "instruction formats" spec as type@CCCC.
- */
- public static final int MAX_TYPE_IDX = 0xFFFF;
-
- /**
- * Returns the API level corresponding to the given magic number,
- * or {@code -1} if the given array is not a well-formed dex file
- * magic number.
- */
- public static int magicToApi(byte[] magic) {
- if (magic.length != 8) {
- return -1;
- }
-
- if ((magic[0] != 'd') || (magic[1] != 'e') || (magic[2] != 'x') || (magic[3] != '\n') ||
- (magic[7] != '\0')) {
- return -1;
- }
-
- String version = "" + ((char) magic[4]) + ((char) magic[5]) +((char) magic[6]);
-
- if (version.equals(VERSION_CURRENT)) {
- return API_CURRENT;
- } else if (version.equals(VERSION_FOR_API_13)) {
- return API_NO_EXTENDED_OPCODES;
- }
-
- return -1;
- }
-
- /**
- * Returns the magic number corresponding to the given target API level.
- */
- public static String apiToMagic(int targetApiLevel) {
- String version;
-
- if (targetApiLevel >= API_CURRENT) {
- version = VERSION_CURRENT;
- } else {
- version = VERSION_FOR_API_13;
- }
-
- return MAGIC_PREFIX + version + MAGIC_SUFFIX;
- }
-
- public static boolean isSupportedDexMagic(byte[] magic) {
- int api = magicToApi(magic);
- return api == API_NO_EXTENDED_OPCODES || api == API_CURRENT;
- }
-}
diff --git a/dex/src/main/java/com/android/dex/DexIndexOverflowException.java b/dex/src/main/java/com/android/dex/DexIndexOverflowException.java
deleted file mode 100644
index 32262072b..000000000
--- a/dex/src/main/java/com/android/dex/DexIndexOverflowException.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2013 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 com.android.dex;
-
-/**
- * Thrown when there's an index overflow writing a dex file.
- */
-public final class DexIndexOverflowException extends DexException {
- public DexIndexOverflowException(String message) {
- super(message);
- }
-
- public DexIndexOverflowException(Throwable cause) {
- super(cause);
- }
-}
diff --git a/dex/src/main/java/com/android/dex/EncodedValue.java b/dex/src/main/java/com/android/dex/EncodedValue.java
deleted file mode 100644
index 8d0c3adcf..000000000
--- a/dex/src/main/java/com/android/dex/EncodedValue.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex;
-
-import com.android.dex.util.ByteArrayByteInput;
-import com.android.dex.util.ByteInput;
-
-/**
- * An encoded value or array.
- */
-public final class EncodedValue implements Comparable {
- private final byte[] data;
-
- public EncodedValue(byte[] data) {
- this.data = data;
- }
-
- public ByteInput asByteInput() {
- return new ByteArrayByteInput(data);
- }
-
- public byte[] getBytes() {
- return data;
- }
-
- public void writeTo(Dex.Section out) {
- out.write(data);
- }
-
- @Override public int compareTo(EncodedValue other) {
- int size = Math.min(data.length, other.data.length);
- for (int i = 0; i < size; i++) {
- if (data[i] != other.data[i]) {
- return (data[i] & 0xff) - (other.data[i] & 0xff);
- }
- }
- return data.length - other.data.length;
- }
-
- @Override public String toString() {
- return Integer.toHexString(data[0] & 0xff) + "...(" + data.length + ")";
- }
-}
diff --git a/dex/src/main/java/com/android/dex/EncodedValueCodec.java b/dex/src/main/java/com/android/dex/EncodedValueCodec.java
deleted file mode 100644
index 7fc172434..000000000
--- a/dex/src/main/java/com/android/dex/EncodedValueCodec.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex;
-
-import com.android.dex.util.ByteInput;
-import com.android.dex.util.ByteOutput;
-
-/**
- * Read and write {@code encoded_value} primitives.
- */
-public final class EncodedValueCodec {
- private EncodedValueCodec() {
- }
-
- /**
- * Writes a signed integral to {@code out}.
- */
- public static void writeSignedIntegralValue(ByteOutput out, int type, long value) {
- /*
- * Figure out how many bits are needed to represent the value,
- * including a sign bit: The bit count is subtracted from 65
- * and not 64 to account for the sign bit. The xor operation
- * has the effect of leaving non-negative values alone and
- * unary complementing negative values (so that a leading zero
- * count always returns a useful number for our present
- * purpose).
- */
- int requiredBits = 65 - Long.numberOfLeadingZeros(value ^ (value >> 63));
-
- // Round up the requiredBits to a number of bytes.
- int requiredBytes = (requiredBits + 0x07) >> 3;
-
- /*
- * Write the header byte, which includes the type and
- * requiredBytes - 1.
- */
- out.writeByte(type | ((requiredBytes - 1) << 5));
-
- // Write the value, per se.
- while (requiredBytes > 0) {
- out.writeByte((byte) value);
- value >>= 8;
- requiredBytes--;
- }
- }
-
- /**
- * Writes an unsigned integral to {@code out}.
- */
- public static void writeUnsignedIntegralValue(ByteOutput out, int type, long value) {
- // Figure out how many bits are needed to represent the value.
- int requiredBits = 64 - Long.numberOfLeadingZeros(value);
- if (requiredBits == 0) {
- requiredBits = 1;
- }
-
- // Round up the requiredBits to a number of bytes.
- int requiredBytes = (requiredBits + 0x07) >> 3;
-
- /*
- * Write the header byte, which includes the type and
- * requiredBytes - 1.
- */
- out.writeByte(type | ((requiredBytes - 1) << 5));
-
- // Write the value, per se.
- while (requiredBytes > 0) {
- out.writeByte((byte) value);
- value >>= 8;
- requiredBytes--;
- }
- }
-
- /**
- * Writes a right-zero-extended value to {@code out}.
- */
- public static void writeRightZeroExtendedValue(ByteOutput out, int type, long value) {
- // Figure out how many bits are needed to represent the value.
- int requiredBits = 64 - Long.numberOfTrailingZeros(value);
- if (requiredBits == 0) {
- requiredBits = 1;
- }
-
- // Round up the requiredBits to a number of bytes.
- int requiredBytes = (requiredBits + 0x07) >> 3;
-
- // Scootch the first bits to be written down to the low-order bits.
- value >>= 64 - (requiredBytes * 8);
-
- /*
- * Write the header byte, which includes the type and
- * requiredBytes - 1.
- */
- out.writeByte(type | ((requiredBytes - 1) << 5));
-
- // Write the value, per se.
- while (requiredBytes > 0) {
- out.writeByte((byte) value);
- value >>= 8;
- requiredBytes--;
- }
- }
-
- /**
- * Read a signed integer.
- *
- * @param zwidth byte count minus one
- */
- public static int readSignedInt(ByteInput in, int zwidth) {
- int result = 0;
- for (int i = zwidth; i >= 0; i--) {
- result = (result >>> 8) | ((in.readByte() & 0xff) << 24);
- }
- result >>= (3 - zwidth) * 8;
- return result;
- }
-
- /**
- * Read an unsigned integer.
- *
- * @param zwidth byte count minus one
- * @param fillOnRight true to zero fill on the right; false on the left
- */
- public static int readUnsignedInt(ByteInput in, int zwidth, boolean fillOnRight) {
- int result = 0;
- if (!fillOnRight) {
- for (int i = zwidth; i >= 0; i--) {
- result = (result >>> 8) | ((in.readByte() & 0xff) << 24);
- }
- result >>>= (3 - zwidth) * 8;
- } else {
- for (int i = zwidth; i >= 0; i--) {
- result = (result >>> 8) | ((in.readByte() & 0xff) << 24);
- }
- }
- return result;
- }
-
- /**
- * Read a signed long.
- *
- * @param zwidth byte count minus one
- */
- public static long readSignedLong(ByteInput in, int zwidth) {
- long result = 0;
- for (int i = zwidth; i >= 0; i--) {
- result = (result >>> 8) | ((in.readByte() & 0xffL) << 56);
- }
- result >>= (7 - zwidth) * 8;
- return result;
- }
-
- /**
- * Read an unsigned long.
- *
- * @param zwidth byte count minus one
- * @param fillOnRight true to zero fill on the right; false on the left
- */
- public static long readUnsignedLong(ByteInput in, int zwidth, boolean fillOnRight) {
- long result = 0;
- if (!fillOnRight) {
- for (int i = zwidth; i >= 0; i--) {
- result = (result >>> 8) | ((in.readByte() & 0xffL) << 56);
- }
- result >>>= (7 - zwidth) * 8;
- } else {
- for (int i = zwidth; i >= 0; i--) {
- result = (result >>> 8) | ((in.readByte() & 0xffL) << 56);
- }
- }
- return result;
- }
-}
diff --git a/dex/src/main/java/com/android/dex/EncodedValueReader.java b/dex/src/main/java/com/android/dex/EncodedValueReader.java
deleted file mode 100644
index 6f60538a2..000000000
--- a/dex/src/main/java/com/android/dex/EncodedValueReader.java
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex;
-
-import com.android.dex.util.ByteInput;
-
-/**
- * Pull parser for encoded values.
- */
-public final class EncodedValueReader {
- public static final int ENCODED_BYTE = 0x00;
- public static final int ENCODED_SHORT = 0x02;
- public static final int ENCODED_CHAR = 0x03;
- public static final int ENCODED_INT = 0x04;
- public static final int ENCODED_LONG = 0x06;
- public static final int ENCODED_FLOAT = 0x10;
- public static final int ENCODED_DOUBLE = 0x11;
- public static final int ENCODED_STRING = 0x17;
- public static final int ENCODED_TYPE = 0x18;
- public static final int ENCODED_FIELD = 0x19;
- public static final int ENCODED_ENUM = 0x1b;
- public static final int ENCODED_METHOD = 0x1a;
- public static final int ENCODED_ARRAY = 0x1c;
- public static final int ENCODED_ANNOTATION = 0x1d;
- public static final int ENCODED_NULL = 0x1e;
- public static final int ENCODED_BOOLEAN = 0x1f;
-
- /** placeholder type if the type is not yet known */
- private static final int MUST_READ = -1;
-
- protected final ByteInput in;
- private int type = MUST_READ;
- private int annotationType;
- private int arg;
-
- public EncodedValueReader(ByteInput in) {
- this.in = in;
- }
-
- public EncodedValueReader(EncodedValue in) {
- this(in.asByteInput());
- }
-
- /**
- * Creates a new encoded value reader whose only value is the specified
- * known type. This is useful for encoded values without a type prefix,
- * such as class_def_item's encoded_array or annotation_item's
- * encoded_annotation.
- */
- public EncodedValueReader(ByteInput in, int knownType) {
- this.in = in;
- this.type = knownType;
- }
-
- public EncodedValueReader(EncodedValue in, int knownType) {
- this(in.asByteInput(), knownType);
- }
-
- /**
- * Returns the type of the next value to read.
- */
- public int peek() {
- if (type == MUST_READ) {
- int argAndType = in.readByte() & 0xff;
- type = argAndType & 0x1f;
- arg = (argAndType & 0xe0) >> 5;
- }
- return type;
- }
-
- /**
- * Begins reading the elements of an array, returning the array's size. The
- * caller must follow up by calling a read method for each element in the
- * array. For example, this reads a byte array: {@code
- * int arraySize = readArray();
- * for (int i = 0, i < arraySize; i++) {
- * readByte();
- * }
- * }
- */
- public int readArray() {
- checkType(ENCODED_ARRAY);
- type = MUST_READ;
- return Leb128.readUnsignedLeb128(in);
- }
-
- /**
- * Begins reading the fields of an annotation, returning the number of
- * fields. The caller must follow up by making alternating calls to {@link
- * #readAnnotationName()} and another read method. For example, this reads
- * an annotation whose fields are all bytes: {@code
- * int fieldCount = readAnnotation();
- * int annotationType = getAnnotationType();
- * for (int i = 0; i < fieldCount; i++) {
- * readAnnotationName();
- * readByte();
- * }
- * }
- */
- public int readAnnotation() {
- checkType(ENCODED_ANNOTATION);
- type = MUST_READ;
- annotationType = Leb128.readUnsignedLeb128(in);
- return Leb128.readUnsignedLeb128(in);
- }
-
- /**
- * Returns the type of the annotation just returned by {@link
- * #readAnnotation()}. This method's value is undefined unless the most
- * recent call was to {@link #readAnnotation()}.
- */
- public int getAnnotationType() {
- return annotationType;
- }
-
- public int readAnnotationName() {
- return Leb128.readUnsignedLeb128(in);
- }
-
- public byte readByte() {
- checkType(ENCODED_BYTE);
- type = MUST_READ;
- return (byte) EncodedValueCodec.readSignedInt(in, arg);
- }
-
- public short readShort() {
- checkType(ENCODED_SHORT);
- type = MUST_READ;
- return (short) EncodedValueCodec.readSignedInt(in, arg);
- }
-
- public char readChar() {
- checkType(ENCODED_CHAR);
- type = MUST_READ;
- return (char) EncodedValueCodec.readUnsignedInt(in, arg, false);
- }
-
- public int readInt() {
- checkType(ENCODED_INT);
- type = MUST_READ;
- return EncodedValueCodec.readSignedInt(in, arg);
- }
-
- public long readLong() {
- checkType(ENCODED_LONG);
- type = MUST_READ;
- return EncodedValueCodec.readSignedLong(in, arg);
- }
-
- public float readFloat() {
- checkType(ENCODED_FLOAT);
- type = MUST_READ;
- return Float.intBitsToFloat(EncodedValueCodec.readUnsignedInt(in, arg, true));
- }
-
- public double readDouble() {
- checkType(ENCODED_DOUBLE);
- type = MUST_READ;
- return Double.longBitsToDouble(EncodedValueCodec.readUnsignedLong(in, arg, true));
- }
-
- public int readString() {
- checkType(ENCODED_STRING);
- type = MUST_READ;
- return EncodedValueCodec.readUnsignedInt(in, arg, false);
- }
-
- public int readType() {
- checkType(ENCODED_TYPE);
- type = MUST_READ;
- return EncodedValueCodec.readUnsignedInt(in, arg, false);
- }
-
- public int readField() {
- checkType(ENCODED_FIELD);
- type = MUST_READ;
- return EncodedValueCodec.readUnsignedInt(in, arg, false);
- }
-
- public int readEnum() {
- checkType(ENCODED_ENUM);
- type = MUST_READ;
- return EncodedValueCodec.readUnsignedInt(in, arg, false);
- }
-
- public int readMethod() {
- checkType(ENCODED_METHOD);
- type = MUST_READ;
- return EncodedValueCodec.readUnsignedInt(in, arg, false);
- }
-
- public void readNull() {
- checkType(ENCODED_NULL);
- type = MUST_READ;
- }
-
- public boolean readBoolean() {
- checkType(ENCODED_BOOLEAN);
- type = MUST_READ;
- return arg != 0;
- }
-
- /**
- * Skips a single value, including its nested values if it is an array or
- * annotation.
- */
- public void skipValue() {
- switch (peek()) {
- case ENCODED_BYTE:
- readByte();
- break;
- case ENCODED_SHORT:
- readShort();
- break;
- case ENCODED_CHAR:
- readChar();
- break;
- case ENCODED_INT:
- readInt();
- break;
- case ENCODED_LONG:
- readLong();
- break;
- case ENCODED_FLOAT:
- readFloat();
- break;
- case ENCODED_DOUBLE:
- readDouble();
- break;
- case ENCODED_STRING:
- readString();
- break;
- case ENCODED_TYPE:
- readType();
- break;
- case ENCODED_FIELD:
- readField();
- break;
- case ENCODED_ENUM:
- readEnum();
- break;
- case ENCODED_METHOD:
- readMethod();
- break;
- case ENCODED_ARRAY:
- for (int i = 0, size = readArray(); i < size; i++) {
- skipValue();
- }
- break;
- case ENCODED_ANNOTATION:
- for (int i = 0, size = readAnnotation(); i < size; i++) {
- readAnnotationName();
- skipValue();
- }
- break;
- case ENCODED_NULL:
- readNull();
- break;
- case ENCODED_BOOLEAN:
- readBoolean();
- break;
- default:
- throw new DexException("Unexpected type: " + Integer.toHexString(type));
- }
- }
-
- private void checkType(int expected) {
- if (peek() != expected) {
- throw new IllegalStateException(
- String.format("Expected %x but was %x", expected, peek()));
- }
- }
-}
diff --git a/dex/src/main/java/com/android/dex/FieldId.java b/dex/src/main/java/com/android/dex/FieldId.java
deleted file mode 100644
index 2f41708c8..000000000
--- a/dex/src/main/java/com/android/dex/FieldId.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex;
-
-import com.android.dex.util.Unsigned;
-
-public final class FieldId implements Comparable {
- private final Dex dex;
- private final int declaringClassIndex;
- private final int typeIndex;
- private final int nameIndex;
-
- public FieldId(Dex dex, int declaringClassIndex, int typeIndex, int nameIndex) {
- this.dex = dex;
- this.declaringClassIndex = declaringClassIndex;
- this.typeIndex = typeIndex;
- this.nameIndex = nameIndex;
- }
-
- public int getDeclaringClassIndex() {
- return declaringClassIndex;
- }
-
- public int getTypeIndex() {
- return typeIndex;
- }
-
- public int getNameIndex() {
- return nameIndex;
- }
-
- public int compareTo(FieldId other) {
- if (declaringClassIndex != other.declaringClassIndex) {
- return Unsigned.compare(declaringClassIndex, other.declaringClassIndex);
- }
- if (nameIndex != other.nameIndex) {
- return Unsigned.compare(nameIndex, other.nameIndex);
- }
- return Unsigned.compare(typeIndex, other.typeIndex); // should always be 0
- }
-
- public void writeTo(Dex.Section out) {
- out.writeUnsignedShort(declaringClassIndex);
- out.writeUnsignedShort(typeIndex);
- out.writeInt(nameIndex);
- }
-
- @Override public String toString() {
- if (dex == null) {
- return declaringClassIndex + " " + typeIndex + " " + nameIndex;
- }
- return dex.typeNames().get(typeIndex) + "." + dex.strings().get(nameIndex);
- }
-}
diff --git a/dex/src/main/java/com/android/dex/Leb128.java b/dex/src/main/java/com/android/dex/Leb128.java
deleted file mode 100644
index 1a82e383e..000000000
--- a/dex/src/main/java/com/android/dex/Leb128.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2008 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 com.android.dex;
-
-import com.android.dex.util.ByteInput;
-import com.android.dex.util.ByteOutput;
-
-/**
- * Reads and writes DWARFv3 LEB 128 signed and unsigned integers. See DWARF v3
- * section 7.6.
- */
-public final class Leb128 {
- private Leb128() {
- }
-
- /**
- * Gets the number of bytes in the unsigned LEB128 encoding of the
- * given value.
- *
- * @param value the value in question
- * @return its write size, in bytes
- */
- public static int unsignedLeb128Size(int value) {
- // TODO: This could be much cleverer.
-
- int remaining = value >> 7;
- int count = 0;
-
- while (remaining != 0) {
- remaining >>= 7;
- count++;
- }
-
- return count + 1;
- }
-
- /**
- * Gets the number of bytes in the signed LEB128 encoding of the
- * given value.
- *
- * @param value the value in question
- * @return its write size, in bytes
- */
- public static int signedLeb128Size(int value) {
- // TODO: This could be much cleverer.
-
- int remaining = value >> 7;
- int count = 0;
- boolean hasMore = true;
- int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1;
-
- while (hasMore) {
- hasMore = (remaining != end)
- || ((remaining & 1) != ((value >> 6) & 1));
-
- value = remaining;
- remaining >>= 7;
- count++;
- }
-
- return count;
- }
-
- /**
- * Reads an signed integer from {@code in}.
- */
- public static int readSignedLeb128(ByteInput in) {
- int result = 0;
- int cur;
- int count = 0;
- int signBits = -1;
-
- do {
- cur = in.readByte() & 0xff;
- result |= (cur & 0x7f) << (count * 7);
- signBits <<= 7;
- count++;
- } while (((cur & 0x80) == 0x80) && count < 5);
-
- if ((cur & 0x80) == 0x80) {
- throw new DexException("invalid LEB128 sequence");
- }
-
- // Sign extend if appropriate
- if (((signBits >> 1) & result) != 0 ) {
- result |= signBits;
- }
-
- return result;
- }
-
- /**
- * Reads an unsigned integer from {@code in}.
- */
- public static int readUnsignedLeb128(ByteInput in) {
- int result = 0;
- int cur;
- int count = 0;
-
- do {
- cur = in.readByte() & 0xff;
- result |= (cur & 0x7f) << (count * 7);
- count++;
- } while (((cur & 0x80) == 0x80) && count < 5);
-
- if ((cur & 0x80) == 0x80) {
- throw new DexException("invalid LEB128 sequence");
- }
-
- return result;
- }
-
- /**
- * Writes {@code value} as an unsigned integer to {@code out}, starting at
- * {@code offset}. Returns the number of bytes written.
- */
- public static void writeUnsignedLeb128(ByteOutput out, int value) {
- int remaining = value >>> 7;
-
- while (remaining != 0) {
- out.writeByte((byte) ((value & 0x7f) | 0x80));
- value = remaining;
- remaining >>>= 7;
- }
-
- out.writeByte((byte) (value & 0x7f));
- }
-
- /**
- * Writes {@code value} as a signed integer to {@code out}, starting at
- * {@code offset}. Returns the number of bytes written.
- */
- public static void writeSignedLeb128(ByteOutput out, int value) {
- int remaining = value >> 7;
- boolean hasMore = true;
- int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1;
-
- while (hasMore) {
- hasMore = (remaining != end)
- || ((remaining & 1) != ((value >> 6) & 1));
-
- out.writeByte((byte) ((value & 0x7f) | (hasMore ? 0x80 : 0)));
- value = remaining;
- remaining >>= 7;
- }
- }
-}
diff --git a/dex/src/main/java/com/android/dex/MethodId.java b/dex/src/main/java/com/android/dex/MethodId.java
deleted file mode 100644
index e51874026..000000000
--- a/dex/src/main/java/com/android/dex/MethodId.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex;
-
-import com.android.dex.util.Unsigned;
-
-public final class MethodId implements Comparable {
- private final Dex dex;
- private final int declaringClassIndex;
- private final int protoIndex;
- private final int nameIndex;
-
- public MethodId(Dex dex, int declaringClassIndex, int protoIndex, int nameIndex) {
- this.dex = dex;
- this.declaringClassIndex = declaringClassIndex;
- this.protoIndex = protoIndex;
- this.nameIndex = nameIndex;
- }
-
- public int getDeclaringClassIndex() {
- return declaringClassIndex;
- }
-
- public int getProtoIndex() {
- return protoIndex;
- }
-
- public int getNameIndex() {
- return nameIndex;
- }
-
- public int compareTo(MethodId other) {
- if (declaringClassIndex != other.declaringClassIndex) {
- return Unsigned.compare(declaringClassIndex, other.declaringClassIndex);
- }
- if (nameIndex != other.nameIndex) {
- return Unsigned.compare(nameIndex, other.nameIndex);
- }
- return Unsigned.compare(protoIndex, other.protoIndex);
- }
-
- public void writeTo(Dex.Section out) {
- out.writeUnsignedShort(declaringClassIndex);
- out.writeUnsignedShort(protoIndex);
- out.writeInt(nameIndex);
- }
-
- @Override public String toString() {
- if (dex == null) {
- return declaringClassIndex + " " + protoIndex + " " + nameIndex;
- }
- return dex.typeNames().get(declaringClassIndex)
- + "." + dex.strings().get(nameIndex)
- + dex.readTypeList(dex.protoIds().get(protoIndex).getParametersOffset());
- }
-}
diff --git a/dex/src/main/java/com/android/dex/Mutf8.java b/dex/src/main/java/com/android/dex/Mutf8.java
deleted file mode 100644
index c64da331b..000000000
--- a/dex/src/main/java/com/android/dex/Mutf8.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex;
-
-import com.android.dex.util.ByteInput;
-import java.io.UTFDataFormatException;
-
-/**
- * Modified UTF-8 as described in the dex file format spec.
- *
- * Derived from libcore's MUTF-8 encoder at java.nio.charset.ModifiedUtf8.
- */
-public final class Mutf8 {
- private Mutf8() {}
-
- /**
- * Decodes bytes from {@code in} into {@code out} until a delimiter 0x00 is
- * encountered. Returns a new string containing the decoded characters.
- */
- public static String decode(ByteInput in, char[] out) throws UTFDataFormatException {
- int s = 0;
- while (true) {
- char a = (char) (in.readByte() & 0xff);
- if (a == 0) {
- return new String(out, 0, s);
- }
- out[s] = a;
- if (a < '\u0080') {
- s++;
- } else if ((a & 0xe0) == 0xc0) {
- int b = in.readByte() & 0xff;
- if ((b & 0xC0) != 0x80) {
- throw new UTFDataFormatException("bad second byte");
- }
- out[s++] = (char) (((a & 0x1F) << 6) | (b & 0x3F));
- } else if ((a & 0xf0) == 0xe0) {
- int b = in.readByte() & 0xff;
- int c = in.readByte() & 0xff;
- if (((b & 0xC0) != 0x80) || ((c & 0xC0) != 0x80)) {
- throw new UTFDataFormatException("bad second or third byte");
- }
- out[s++] = (char) (((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F));
- } else {
- throw new UTFDataFormatException("bad byte");
- }
- }
- }
-
- /**
- * Returns the number of bytes the modified UTF8 representation of 's' would take.
- */
- private static long countBytes(String s, boolean shortLength) throws UTFDataFormatException {
- long result = 0;
- final int length = s.length();
- for (int i = 0; i < length; ++i) {
- char ch = s.charAt(i);
- if (ch != 0 && ch <= 127) { // U+0000 uses two bytes.
- ++result;
- } else if (ch <= 2047) {
- result += 2;
- } else {
- result += 3;
- }
- if (shortLength && result > 65535) {
- throw new UTFDataFormatException("String more than 65535 UTF bytes long");
- }
- }
- return result;
- }
-
- /**
- * Encodes the modified UTF-8 bytes corresponding to {@code s} into {@code
- * dst}, starting at {@code offset}.
- */
- public static void encode(byte[] dst, int offset, String s) {
- final int length = s.length();
- for (int i = 0; i < length; i++) {
- char ch = s.charAt(i);
- if (ch != 0 && ch <= 127) { // U+0000 uses two bytes.
- dst[offset++] = (byte) ch;
- } else if (ch <= 2047) {
- dst[offset++] = (byte) (0xc0 | (0x1f & (ch >> 6)));
- dst[offset++] = (byte) (0x80 | (0x3f & ch));
- } else {
- dst[offset++] = (byte) (0xe0 | (0x0f & (ch >> 12)));
- dst[offset++] = (byte) (0x80 | (0x3f & (ch >> 6)));
- dst[offset++] = (byte) (0x80 | (0x3f & ch));
- }
- }
- }
-
- /**
- * Returns an array containing the modified UTF-8 form of {@code s}.
- */
- public static byte[] encode(String s) throws UTFDataFormatException {
- int utfCount = (int) countBytes(s, true);
- byte[] result = new byte[utfCount];
- encode(result, 0, s);
- return result;
- }
-}
diff --git a/dex/src/main/java/com/android/dex/ProtoId.java b/dex/src/main/java/com/android/dex/ProtoId.java
deleted file mode 100644
index 9d9f484f2..000000000
--- a/dex/src/main/java/com/android/dex/ProtoId.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex;
-
-import com.android.dex.util.Unsigned;
-
-public final class ProtoId implements Comparable {
- private final Dex dex;
- private final int shortyIndex;
- private final int returnTypeIndex;
- private final int parametersOffset;
-
- public ProtoId(Dex dex, int shortyIndex, int returnTypeIndex, int parametersOffset) {
- this.dex = dex;
- this.shortyIndex = shortyIndex;
- this.returnTypeIndex = returnTypeIndex;
- this.parametersOffset = parametersOffset;
- }
-
- public int compareTo(ProtoId other) {
- if (returnTypeIndex != other.returnTypeIndex) {
- return Unsigned.compare(returnTypeIndex, other.returnTypeIndex);
- }
- return Unsigned.compare(parametersOffset, other.parametersOffset);
- }
-
- public int getShortyIndex() {
- return shortyIndex;
- }
-
- public int getReturnTypeIndex() {
- return returnTypeIndex;
- }
-
- public int getParametersOffset() {
- return parametersOffset;
- }
-
- public void writeTo(Dex.Section out) {
- out.writeInt(shortyIndex);
- out.writeInt(returnTypeIndex);
- out.writeInt(parametersOffset);
- }
-
- @Override public String toString() {
- if (dex == null) {
- return shortyIndex + " " + returnTypeIndex + " " + parametersOffset;
- }
-
- return dex.strings().get(shortyIndex)
- + ": " + dex.typeNames().get(returnTypeIndex)
- + " " + dex.readTypeList(parametersOffset);
- }
-}
diff --git a/dex/src/main/java/com/android/dex/SizeOf.java b/dex/src/main/java/com/android/dex/SizeOf.java
deleted file mode 100644
index 65fab565b..000000000
--- a/dex/src/main/java/com/android/dex/SizeOf.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex;
-
-public final class SizeOf {
- private SizeOf() {}
-
- public static final int UBYTE = 1;
- public static final int USHORT = 2;
- public static final int UINT = 4;
-
- public static final int SIGNATURE = UBYTE * 20;
-
- /**
- * magic ubyte[8]
- * checksum uint
- * signature ubyte[20]
- * file_size uint
- * header_size uint
- * endian_tag uint
- * link_size uint
- * link_off uint
- * map_off uint
- * string_ids_size uint
- * string_ids_off uint
- * type_ids_size uint
- * type_ids_off uint
- * proto_ids_size uint
- * proto_ids_off uint
- * field_ids_size uint
- * field_ids_off uint
- * method_ids_size uint
- * method_ids_off uint
- * class_defs_size uint
- * class_defs_off uint
- * data_size uint
- * data_off uint
- */
- public static final int HEADER_ITEM = (8 * UBYTE) + UINT + SIGNATURE + (20 * UINT); // 0x70
-
- /**
- * string_data_off uint
- */
- public static final int STRING_ID_ITEM = UINT;
-
- /**
- * descriptor_idx uint
- */
- public static final int TYPE_ID_ITEM = UINT;
-
- /**
- * type_idx ushort
- */
- public static final int TYPE_ITEM = USHORT;
-
- /**
- * shorty_idx uint
- * return_type_idx uint
- * return_type_idx uint
- */
- public static final int PROTO_ID_ITEM = UINT + UINT + UINT;
-
- /**
- * class_idx ushort
- * type_idx/proto_idx ushort
- * name_idx uint
- */
- public static final int MEMBER_ID_ITEM = USHORT + USHORT + UINT;
-
- /**
- * class_idx uint
- * access_flags uint
- * superclass_idx uint
- * interfaces_off uint
- * source_file_idx uint
- * annotations_off uint
- * class_data_off uint
- * static_values_off uint
- */
- public static final int CLASS_DEF_ITEM = 8 * UINT;
-
- /**
- * type ushort
- * unused ushort
- * size uint
- * offset uint
- */
- public static final int MAP_ITEM = USHORT + USHORT + UINT + UINT;
-
- /**
- * start_addr uint
- * insn_count ushort
- * handler_off ushort
- */
- public static final int TRY_ITEM = UINT + USHORT + USHORT;
-}
diff --git a/dex/src/main/java/com/android/dex/TableOfContents.java b/dex/src/main/java/com/android/dex/TableOfContents.java
deleted file mode 100644
index 583f19508..000000000
--- a/dex/src/main/java/com/android/dex/TableOfContents.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.util.Arrays;
-
-/**
- * The file header and map.
- */
-public final class TableOfContents {
-
- /*
- * TODO: factor out ID constants.
- */
-
- public final Section header = new Section(0x0000);
- public final Section stringIds = new Section(0x0001);
- public final Section typeIds = new Section(0x0002);
- public final Section protoIds = new Section(0x0003);
- public final Section fieldIds = new Section(0x0004);
- public final Section methodIds = new Section(0x0005);
- public final Section classDefs = new Section(0x0006);
- public final Section mapList = new Section(0x1000);
- public final Section typeLists = new Section(0x1001);
- public final Section annotationSetRefLists = new Section(0x1002);
- public final Section annotationSets = new Section(0x1003);
- public final Section classDatas = new Section(0x2000);
- public final Section codes = new Section(0x2001);
- public final Section stringDatas = new Section(0x2002);
- public final Section debugInfos = new Section(0x2003);
- public final Section annotations = new Section(0x2004);
- public final Section encodedArrays = new Section(0x2005);
- public final Section annotationsDirectories = new Section(0x2006);
- public final Section[] sections = {
- header, stringIds, typeIds, protoIds, fieldIds, methodIds, classDefs, mapList,
- typeLists, annotationSetRefLists, annotationSets, classDatas, codes, stringDatas,
- debugInfos, annotations, encodedArrays, annotationsDirectories
- };
-
- public int apiLevel;
- public int checksum;
- public byte[] signature;
- public int fileSize;
- public int linkSize;
- public int linkOff;
- public int dataSize;
- public int dataOff;
-
- public TableOfContents() {
- signature = new byte[20];
- }
-
- public void readFrom(Dex dex) throws IOException {
- readHeader(dex.open(0));
- readMap(dex.open(mapList.off));
- computeSizesFromOffsets();
- }
-
- private void readHeader(Dex.Section headerIn) throws UnsupportedEncodingException {
- byte[] magic = headerIn.readByteArray(8);
-
- if (!DexFormat.isSupportedDexMagic(magic)) {
- throw new DexException("Unexpected magic: " + Arrays.toString(magic));
- }
-
- apiLevel = DexFormat.magicToApi(magic);
- checksum = headerIn.readInt();
- signature = headerIn.readByteArray(20);
- fileSize = headerIn.readInt();
- int headerSize = headerIn.readInt();
- if (headerSize != SizeOf.HEADER_ITEM) {
- throw new DexException("Unexpected header: 0x" + Integer.toHexString(headerSize));
- }
- int endianTag = headerIn.readInt();
- if (endianTag != DexFormat.ENDIAN_TAG) {
- throw new DexException("Unexpected endian tag: 0x" + Integer.toHexString(endianTag));
- }
- linkSize = headerIn.readInt();
- linkOff = headerIn.readInt();
- mapList.off = headerIn.readInt();
- if (mapList.off == 0) {
- throw new DexException("Cannot merge dex files that do not contain a map");
- }
- stringIds.size = headerIn.readInt();
- stringIds.off = headerIn.readInt();
- typeIds.size = headerIn.readInt();
- typeIds.off = headerIn.readInt();
- protoIds.size = headerIn.readInt();
- protoIds.off = headerIn.readInt();
- fieldIds.size = headerIn.readInt();
- fieldIds.off = headerIn.readInt();
- methodIds.size = headerIn.readInt();
- methodIds.off = headerIn.readInt();
- classDefs.size = headerIn.readInt();
- classDefs.off = headerIn.readInt();
- dataSize = headerIn.readInt();
- dataOff = headerIn.readInt();
- }
-
- private void readMap(Dex.Section in) throws IOException {
- int mapSize = in.readInt();
- Section previous = null;
- for (int i = 0; i < mapSize; i++) {
- short type = in.readShort();
- in.readShort(); // unused
- Section section = getSection(type);
- int size = in.readInt();
- int offset = in.readInt();
-
- if ((section.size != 0 && section.size != size)
- || (section.off != -1 && section.off != offset)) {
- throw new DexException("Unexpected map value for 0x" + Integer.toHexString(type));
- }
-
- section.size = size;
- section.off = offset;
-
- if (previous != null && previous.off > section.off) {
- throw new DexException("Map is unsorted at " + previous + ", " + section);
- }
-
- previous = section;
- }
- Arrays.sort(sections);
- }
-
- public void computeSizesFromOffsets() {
- int end = dataOff + dataSize;
- for (int i = sections.length - 1; i >= 0; i--) {
- Section section = sections[i];
- if (section.off == -1) {
- continue;
- }
- if (section.off > end) {
- throw new DexException("Map is unsorted at " + section);
- }
- section.byteCount = end - section.off;
- end = section.off;
- }
- }
-
- private Section getSection(short type) {
- for (Section section : sections) {
- if (section.type == type) {
- return section;
- }
- }
- throw new IllegalArgumentException("No such map item: " + type);
- }
-
- public void writeHeader(Dex.Section out, int api) throws IOException {
- out.write(DexFormat.apiToMagic(api).getBytes("UTF-8"));
- out.writeInt(checksum);
- out.write(signature);
- out.writeInt(fileSize);
- out.writeInt(SizeOf.HEADER_ITEM);
- out.writeInt(DexFormat.ENDIAN_TAG);
- out.writeInt(linkSize);
- out.writeInt(linkOff);
- out.writeInt(mapList.off);
- out.writeInt(stringIds.size);
- out.writeInt(stringIds.off);
- out.writeInt(typeIds.size);
- out.writeInt(typeIds.off);
- out.writeInt(protoIds.size);
- out.writeInt(protoIds.off);
- out.writeInt(fieldIds.size);
- out.writeInt(fieldIds.off);
- out.writeInt(methodIds.size);
- out.writeInt(methodIds.off);
- out.writeInt(classDefs.size);
- out.writeInt(classDefs.off);
- out.writeInt(dataSize);
- out.writeInt(dataOff);
- }
-
- public void writeMap(Dex.Section out) throws IOException {
- int count = 0;
- for (Section section : sections) {
- if (section.exists()) {
- count++;
- }
- }
-
- out.writeInt(count);
- for (Section section : sections) {
- if (section.exists()) {
- out.writeShort(section.type);
- out.writeShort((short) 0);
- out.writeInt(section.size);
- out.writeInt(section.off);
- }
- }
- }
-
- public static class Section implements Comparable {
- public final short type;
- public int size = 0;
- public int off = -1;
- public int byteCount = 0;
-
- public Section(int type) {
- this.type = (short) type;
- }
-
- public boolean exists() {
- return size > 0;
- }
-
- public int compareTo(Section section) {
- if (off != section.off) {
- return off < section.off ? -1 : 1;
- }
- return 0;
- }
-
- @Override public String toString() {
- return String.format("Section[type=%#x,off=%#x,size=%#x]", type, off, size);
- }
- }
-}
diff --git a/dex/src/main/java/com/android/dex/TypeList.java b/dex/src/main/java/com/android/dex/TypeList.java
deleted file mode 100644
index 123e82c9a..000000000
--- a/dex/src/main/java/com/android/dex/TypeList.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex;
-
-import com.android.dex.util.Unsigned;
-
-public final class TypeList implements Comparable {
-
- public static final TypeList EMPTY = new TypeList(null, Dex.EMPTY_SHORT_ARRAY);
-
- private final Dex dex;
- private final short[] types;
-
- public TypeList(Dex dex, short[] types) {
- this.dex = dex;
- this.types = types;
- }
-
- public short[] getTypes() {
- return types;
- }
-
- @Override public int compareTo(TypeList other) {
- for (int i = 0; i < types.length && i < other.types.length; i++) {
- if (types[i] != other.types[i]) {
- return Unsigned.compare(types[i], other.types[i]);
- }
- }
- return Unsigned.compare(types.length, other.types.length);
- }
-
- @Override public String toString() {
- StringBuilder result = new StringBuilder();
- result.append("(");
- for (int i = 0, typesLength = types.length; i < typesLength; i++) {
- result.append(dex != null ? dex.typeNames().get(types[i]) : types[i]);
- }
- result.append(")");
- return result.toString();
- }
-}
diff --git a/dex/src/main/java/com/android/dex/util/ByteArrayByteInput.java b/dex/src/main/java/com/android/dex/util/ByteArrayByteInput.java
deleted file mode 100644
index 889a936c5..000000000
--- a/dex/src/main/java/com/android/dex/util/ByteArrayByteInput.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex.util;
-
-public final class ByteArrayByteInput implements ByteInput {
-
- private final byte[] bytes;
- private int position;
-
- public ByteArrayByteInput(byte... bytes) {
- this.bytes = bytes;
- }
-
- @Override public byte readByte() {
- return bytes[position++];
- }
-}
diff --git a/dex/src/main/java/com/android/dex/util/ByteInput.java b/dex/src/main/java/com/android/dex/util/ByteInput.java
deleted file mode 100644
index f1a719614..000000000
--- a/dex/src/main/java/com/android/dex/util/ByteInput.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex.util;
-
-/**
- * A byte source.
- */
-public interface ByteInput {
-
- /**
- * Returns a byte.
- *
- * @throws IndexOutOfBoundsException if all bytes have been read.
- */
- byte readByte();
-}
diff --git a/dex/src/main/java/com/android/dex/util/ByteOutput.java b/dex/src/main/java/com/android/dex/util/ByteOutput.java
deleted file mode 100644
index eb77040ec..000000000
--- a/dex/src/main/java/com/android/dex/util/ByteOutput.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex.util;
-
-/**
- * A byte sink.
- */
-public interface ByteOutput {
-
- /**
- * Writes a byte.
- *
- * @throws IndexOutOfBoundsException if all bytes have been written.
- */
- void writeByte(int i);
-}
diff --git a/dex/src/main/java/com/android/dex/util/ExceptionWithContext.java b/dex/src/main/java/com/android/dex/util/ExceptionWithContext.java
deleted file mode 100644
index 5dfd95474..000000000
--- a/dex/src/main/java/com/android/dex/util/ExceptionWithContext.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2007 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 com.android.dex.util;
-
-import java.io.PrintStream;
-import java.io.PrintWriter;
-
-/**
- * Exception which carries around structured context.
- */
-public class ExceptionWithContext extends RuntimeException {
- /** {@code non-null;} human-oriented context of the exception */
- private StringBuffer context;
-
- /**
- * Augments the given exception with the given context, and return the
- * result. The result is either the given exception if it was an
- * {@link ExceptionWithContext}, or a newly-constructed exception if it
- * was not.
- *
- * @param ex {@code non-null;} the exception to augment
- * @param str {@code non-null;} context to add
- * @return {@code non-null;} an appropriate instance
- */
- public static ExceptionWithContext withContext(Throwable ex, String str) {
- ExceptionWithContext ewc;
-
- if (ex instanceof ExceptionWithContext) {
- ewc = (ExceptionWithContext) ex;
- } else {
- ewc = new ExceptionWithContext(ex);
- }
-
- ewc.addContext(str);
- return ewc;
- }
-
- /**
- * Constructs an instance.
- *
- * @param message human-oriented message
- */
- public ExceptionWithContext(String message) {
- this(message, null);
- }
-
- /**
- * Constructs an instance.
- *
- * @param cause {@code null-ok;} exception that caused this one
- */
- public ExceptionWithContext(Throwable cause) {
- this(null, cause);
- }
-
- /**
- * Constructs an instance.
- *
- * @param message human-oriented message
- * @param cause {@code null-ok;} exception that caused this one
- */
- public ExceptionWithContext(String message, Throwable cause) {
- super((message != null) ? message :
- (cause != null) ? cause.getMessage() : null,
- cause);
-
- if (cause instanceof ExceptionWithContext) {
- String ctx = ((ExceptionWithContext) cause).context.toString();
- context = new StringBuffer(ctx.length() + 200);
- context.append(ctx);
- } else {
- context = new StringBuffer(200);
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public void printStackTrace(PrintStream out) {
- super.printStackTrace(out);
- out.println(context);
- }
-
- /** {@inheritDoc} */
- @Override
- public void printStackTrace(PrintWriter out) {
- super.printStackTrace(out);
- out.println(context);
- }
-
- /**
- * Adds a line of context to this instance.
- *
- * @param str {@code non-null;} new context
- */
- public void addContext(String str) {
- if (str == null) {
- throw new NullPointerException("str == null");
- }
-
- context.append(str);
- if (!str.endsWith("\n")) {
- context.append('\n');
- }
- }
-
- /**
- * Gets the context.
- *
- * @return {@code non-null;} the context
- */
- public String getContext() {
- return context.toString();
- }
-
- /**
- * Prints the message and context.
- *
- * @param out {@code non-null;} where to print to
- */
- public void printContext(PrintStream out) {
- out.println(getMessage());
- out.print(context);
- }
-
- /**
- * Prints the message and context.
- *
- * @param out {@code non-null;} where to print to
- */
- public void printContext(PrintWriter out) {
- out.println(getMessage());
- out.print(context);
- }
-}
diff --git a/dex/src/main/java/com/android/dex/util/FileUtils.java b/dex/src/main/java/com/android/dex/util/FileUtils.java
deleted file mode 100644
index 4cea95c59..000000000
--- a/dex/src/main/java/com/android/dex/util/FileUtils.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2007 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 com.android.dex.util;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-
-/**
- * File I/O utilities.
- */
-public final class FileUtils {
- private FileUtils() {
- }
-
- /**
- * Reads the named file, translating {@link IOException} to a
- * {@link RuntimeException} of some sort.
- *
- * @param fileName {@code non-null;} name of the file to read
- * @return {@code non-null;} contents of the file
- */
- public static byte[] readFile(String fileName) {
- File file = new File(fileName);
- return readFile(file);
- }
-
- /**
- * Reads the given file, translating {@link IOException} to a
- * {@link RuntimeException} of some sort.
- *
- * @param file {@code non-null;} the file to read
- * @return {@code non-null;} contents of the file
- */
- public static byte[] readFile(File file) {
- if (!file.exists()) {
- throw new RuntimeException(file + ": file not found");
- }
-
- if (!file.isFile()) {
- throw new RuntimeException(file + ": not a file");
- }
-
- if (!file.canRead()) {
- throw new RuntimeException(file + ": file not readable");
- }
-
- long longLength = file.length();
- int length = (int) longLength;
- if (length != longLength) {
- throw new RuntimeException(file + ": file too long");
- }
-
- byte[] result = new byte[length];
-
- try {
- FileInputStream in = new FileInputStream(file);
- int at = 0;
- while (length > 0) {
- int amt = in.read(result, at, length);
- if (amt == -1) {
- throw new RuntimeException(file + ": unexpected EOF");
- }
- at += amt;
- length -= amt;
- }
- in.close();
- } catch (IOException ex) {
- throw new RuntimeException(file + ": trouble reading", ex);
- }
-
- return result;
- }
-
- /**
- * Returns true if {@code fileName} names a .zip, .jar, or .apk.
- */
- public static boolean hasArchiveSuffix(String fileName) {
- return fileName.endsWith(".zip")
- || fileName.endsWith(".jar")
- || fileName.endsWith(".apk");
- }
-}
diff --git a/dex/src/main/java/com/android/dex/util/Unsigned.java b/dex/src/main/java/com/android/dex/util/Unsigned.java
deleted file mode 100644
index cb50d0a40..000000000
--- a/dex/src/main/java/com/android/dex/util/Unsigned.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex.util;
-
-/**
- * Unsigned arithmetic over Java's signed types.
- */
-public final class Unsigned {
- private Unsigned() {}
-
- public static int compare(short ushortA, short ushortB) {
- if (ushortA == ushortB) {
- return 0;
- }
- int a = ushortA & 0xFFFF;
- int b = ushortB & 0xFFFF;
- return a < b ? -1 : 1;
- }
-
- public static int compare(int uintA, int uintB) {
- if (uintA == uintB) {
- return 0;
- }
- long a = uintA & 0xFFFFFFFFL;
- long b = uintB & 0xFFFFFFFFL;
- return a < b ? -1 : 1;
- }
-}
diff --git a/dex/src/test/java/com/android/dex/EncodedValueReaderTest.java b/dex/src/test/java/com/android/dex/EncodedValueReaderTest.java
deleted file mode 100644
index a4ca37672..000000000
--- a/dex/src/test/java/com/android/dex/EncodedValueReaderTest.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2011 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 com.android.dex;
-
-import com.android.dex.util.ByteArrayByteInput;
-import junit.framework.TestCase;
-
-public final class EncodedValueReaderTest extends TestCase {
-
- public void testReadByte() {
- assertEquals((byte) 0x80, readerOf(0, 0x80).readByte());
- assertEquals((byte) 0xff, readerOf(0, 0xff).readByte());
- assertEquals((byte) 0x00, readerOf(0, 0x00).readByte());
- assertEquals((byte) 0x01, readerOf(0, 0x01).readByte());
- assertEquals((byte) 0x7f, readerOf(0, 0x7f).readByte());
- }
-
- public void testReadShort() {
- assertEquals((short) 0x8000, readerOf(34, 0x00, 0x80).readShort());
- assertEquals((short) 0, readerOf( 2, 0x00).readShort());
- assertEquals((short) 0xab, readerOf(34, 0xab, 0x00).readShort());
- assertEquals((short) 0xabcd, readerOf(34, 0xcd, 0xab).readShort());
- assertEquals((short) 0x7FFF, readerOf(34, 0xff, 0x7f).readShort());
- }
-
- public void testReadInt() {
- assertEquals(0x80000000, readerOf(100, 0x00, 0x00, 0x00, 0x80).readInt());
- assertEquals( 0x00, readerOf( 4, 0x00).readInt());
- assertEquals( 0xab, readerOf( 36, 0xab, 0x00).readInt());
- assertEquals( 0xabcd, readerOf( 68, 0xcd, 0xab, 0x00).readInt());
- assertEquals( 0xabcdef, readerOf(100, 0xef, 0xcd, 0xab, 0x00).readInt());
- assertEquals(0xabcdef01, readerOf(100, 0x01, 0xef, 0xcd, 0xab).readInt());
- assertEquals(0x7fffffff, readerOf(100, 0xff, 0xff, 0xff, 127).readInt());
- }
-
- public void testReadLong() {
- assertEquals(0x8000000000000000L, readerOf( -26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80).readLong());
- assertEquals( 0x00L, readerOf( 6, 0x00).readLong());
- assertEquals( 0xabL, readerOf( 38, 0xab, 0x00).readLong());
- assertEquals( 0xabcdL, readerOf( 70, 0xcd, 0xab, 0x00).readLong());
- assertEquals( 0xabcdefL, readerOf( 102, 0xef, 0xcd, 0xab, 0x00).readLong());
- assertEquals( 0xabcdef01L, readerOf(-122, 0x01, 0xef, 0xcd, 0xab, 0x00).readLong());
- assertEquals( 0xabcdef0123L, readerOf( -90, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x00).readLong());
- assertEquals( 0xabcdef012345L, readerOf( -58, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x00).readLong());
- assertEquals( 0xabcdef01234567L, readerOf( -26, 0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x00).readLong());
- assertEquals(0xabcdef0123456789L, readerOf( -26, 0x89, 0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab).readLong());
- assertEquals(0x7fffffffffffffffL, readerOf( -26, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f).readLong());
- }
-
- public void testReadFloat() {
- assertEquals(Float.NEGATIVE_INFINITY, readerOf(48, -128, -1).readFloat());
- assertEquals(Float.POSITIVE_INFINITY, readerOf(48, -128, 127).readFloat());
- assertEquals(Float.NaN, readerOf(48, -64, 127).readFloat());
- assertEquals(-0.0f, readerOf(16, -128).readFloat());
- assertEquals(0.0f, readerOf(16, 0).readFloat());
- assertEquals(0.5f, readerOf(16, 63).readFloat());
- assertEquals(1f, readerOf(48, -128, 63).readFloat());
- assertEquals(1.0E06f, readerOf(80, 36, 116, 73).readFloat());
- assertEquals(1.0E12f, readerOf(112, -91, -44, 104, 83).readFloat());
- }
-
- public void testReadDouble() {
- assertEquals(Double.NEGATIVE_INFINITY, readerOf(49, -16, -1).readDouble());
- assertEquals(Double.POSITIVE_INFINITY, readerOf(49, -16, 127).readDouble());
- assertEquals(Double.NaN, readerOf(49, -8, 127).readDouble());
- assertEquals(-0.0, readerOf(17, -128).readDouble());
- assertEquals(0.0, readerOf(17, 0).readDouble());
- assertEquals(0.5, readerOf(49, -32, 63).readDouble());
- assertEquals(1.0, readerOf(49, -16, 63).readDouble());
- assertEquals(1.0E06, readerOf(113, -128, -124, 46, 65).readDouble());
- assertEquals(1.0E12, readerOf(-111, -94, -108, 26, 109, 66).readDouble());
- assertEquals(1.0E24, readerOf(-15, -76, -99, -39, 121, 67, 120, -22, 68).readDouble());
- }
-
- public void testReadChar() {
- assertEquals('\u0000', readerOf( 3, 0x00).readChar());
- assertEquals('\u00ab', readerOf( 3, 0xab).readChar());
- assertEquals('\uabcd', readerOf(35, 0xcd, 0xab).readChar());
- assertEquals('\uffff', readerOf(35, 0xff, 0xff).readChar());
- }
-
- public void testReadBoolean() {
- assertEquals(true, readerOf(63).readBoolean());
- assertEquals(false, readerOf(31).readBoolean());
- }
-
- public void testReadNull() {
- readerOf(30).readNull();
- }
-
- public void testReadReference() {
- assertEquals( 0xab, readerOf(0x17, 0xab).readString());
- assertEquals( 0xabcd, readerOf(0x37, 0xcd, 0xab).readString());
- assertEquals( 0xabcdef, readerOf(0x57, 0xef, 0xcd, 0xab).readString());
- assertEquals(0xabcdef01, readerOf(0x77, 0x01, 0xef, 0xcd, 0xab).readString());
- }
-
- public void testReadWrongType() {
- try {
- readerOf(0x17, 0xab).readField();
- fail();
- } catch (IllegalStateException expected) {
- }
- }
-
- private EncodedValueReader readerOf(int... bytes) {
- byte[] data = new byte[bytes.length];
- for (int i = 0; i < bytes.length; i++) {
- data[i] = (byte) bytes[i];
- }
- return new EncodedValueReader(new ByteArrayByteInput(data));
- }
-}
diff --git a/dom/src/test/java/org/w3c/domts/JUnitTestCaseAdapter.java b/dom/src/test/java/org/w3c/domts/JUnitTestCaseAdapter.java
index 711079236..8d964e47f 100644
--- a/dom/src/test/java/org/w3c/domts/JUnitTestCaseAdapter.java
+++ b/dom/src/test/java/org/w3c/domts/JUnitTestCaseAdapter.java
@@ -44,7 +44,7 @@ public JUnitTestCaseAdapter(DOMTestCase test) {
test.setFramework(this);
this.test = test;
}
-//BEGIN android-added
+//BEGIN Android-added
public JUnitTestCaseAdapter() {
}
@@ -150,9 +150,9 @@ public void setName(String name) {
}
}
}
-//END android-added
+//END Android-added
protected void runTest() throws Throwable {
- //BEGIN android-added
+ //BEGIN Android-added
if (failed) {
if (errorMessage != null) {
fail(errorMessage);
@@ -160,7 +160,7 @@ protected void runTest() throws Throwable {
fail("init failed");
}
}
- //END android-added
+ //END Android-added
test.runTest();
int mutationCount = test.getMutationCount();
if (mutationCount != 0) {
diff --git a/dom/src/test/java/org/w3c/domts/level1/core/hc_attrgetvalue1.java b/dom/src/test/java/org/w3c/domts/level1/core/hc_attrgetvalue1.java
index f3484da4c..5f137a316 100644
--- a/dom/src/test/java/org/w3c/domts/level1/core/hc_attrgetvalue1.java
+++ b/dom/src/test/java/org/w3c/domts/level1/core/hc_attrgetvalue1.java
@@ -69,7 +69,7 @@ public void runTest() throws Throwable {
attributes = testNode.getAttributes();
titleAttr = (Attr) attributes.getNamedItem("class");
value = titleAttr.getValue();
- assertEquals("attrValue1", "Y\u03b1", value); // android-changed: GREEK LOWER CASE ALPHA
+ assertEquals("attrValue1", "Y\u03b1", value); // Android-changed: GREEK LOWER CASE ALPHA
}
/**
* Gets URI that identifies the test.
diff --git a/dom/src/test/java/org/w3c/domts/level1/core/hc_attrgetvalue2.java b/dom/src/test/java/org/w3c/domts/level1/core/hc_attrgetvalue2.java
index 814b69341..c2bf30c84 100644
--- a/dom/src/test/java/org/w3c/domts/level1/core/hc_attrgetvalue2.java
+++ b/dom/src/test/java/org/w3c/domts/level1/core/hc_attrgetvalue2.java
@@ -89,7 +89,7 @@ public void runTest() throws Throwable {
firstChild = titleAttr.getFirstChild();
retval = titleAttr.insertBefore(alphaRef, firstChild);
value = titleAttr.getValue();
- assertEquals("attrValue1", "\u03b1Y\u03b1", value); // android-changed: GREEK LOWER CASE ALPHA
+ assertEquals("attrValue1", "\u03b1Y\u03b1", value); // Android-changed: GREEK LOWER CASE ALPHA
}
}
diff --git a/dom/src/test/java/org/w3c/domts/level1/core/hc_attrspecifiedvaluechanged.java b/dom/src/test/java/org/w3c/domts/level1/core/hc_attrspecifiedvaluechanged.java
index 8ba4c578b..01ce038ee 100644
--- a/dom/src/test/java/org/w3c/domts/level1/core/hc_attrspecifiedvaluechanged.java
+++ b/dom/src/test/java/org/w3c/domts/level1/core/hc_attrspecifiedvaluechanged.java
@@ -71,7 +71,7 @@ public void runTest() throws Throwable {
doc = (Document) load("hc_staff", true);
addressList = doc.getElementsByTagName("acronym");
testNode = addressList.item(2);
- ((Element) /*Node */testNode).setAttribute("class", "Y\u03b1"); // android-changed: GREEK LOWER CASE ALPHA
+ ((Element) /*Node */testNode).setAttribute("class", "Y\u03b1"); // Android-changed: GREEK LOWER CASE ALPHA
attributes = testNode.getAttributes();
streetAttr = (Attr) attributes.getNamedItem("class");
state = streetAttr.getSpecified();
diff --git a/dom/src/test/java/org/w3c/domts/level1/core/hc_namednodemapinuseattributeerr.java b/dom/src/test/java/org/w3c/domts/level1/core/hc_namednodemapinuseattributeerr.java
index 36dc3f81b..fcb4981c8 100644
--- a/dom/src/test/java/org/w3c/domts/level1/core/hc_namednodemapinuseattributeerr.java
+++ b/dom/src/test/java/org/w3c/domts/level1/core/hc_namednodemapinuseattributeerr.java
@@ -75,7 +75,7 @@ public void runTest() throws Throwable {
elementList = doc.getElementsByTagName("acronym");
firstNode = (Element) elementList.item(0);
domesticAttr = doc.createAttribute("title");
- domesticAttr.setValue("Y\u03b1"); // android-changed: GREEK LOWER CASE ALPHA
+ domesticAttr.setValue("Y\u03b1"); // Android-changed: GREEK LOWER CASE ALPHA
setAttr = firstNode.setAttributeNode(domesticAttr);
elementList = doc.getElementsByTagName("acronym");
testNode = elementList.item(2);
diff --git a/dom/src/test/java/org/w3c/domts/level1/core/hc_textparseintolistofelements.java b/dom/src/test/java/org/w3c/domts/level1/core/hc_textparseintolistofelements.java
index 2a10501f2..3364a14d7 100644
--- a/dom/src/test/java/org/w3c/domts/level1/core/hc_textparseintolistofelements.java
+++ b/dom/src/test/java/org/w3c/domts/level1/core/hc_textparseintolistofelements.java
@@ -72,13 +72,13 @@ public void runTest() throws Throwable {
java.util.List result = new java.util.ArrayList();
java.util.List expectedNormal = new java.util.ArrayList();
- expectedNormal.add("\u03b2"); // android-changed: GREEK LOWER CASE BETA
+ expectedNormal.add("\u03b2"); // Android-changed: GREEK LOWER CASE BETA
expectedNormal.add(" Dallas, ");
- expectedNormal.add("\u03b3"); // android-changed: GREEK LOWER CASE GAMMA
+ expectedNormal.add("\u03b3"); // Android-changed: GREEK LOWER CASE GAMMA
expectedNormal.add("\n 98554");
java.util.List expectedExpanded = new java.util.ArrayList();
- expectedExpanded.add("\u03b2 Dallas, \u03b3\n 98554"); // android-changed: GREEK LOWER CASE BETA, GREEK LOWER CASE GAMMA
+ expectedExpanded.add("\u03b2 Dallas, \u03b3\n 98554"); // Android-changed: GREEK LOWER CASE BETA, GREEK LOWER CASE GAMMA
doc = (Document) load("hc_staff", false);
elementList = doc.getElementsByTagName("acronym");
diff --git a/dom/src/test/java/org/w3c/domts/level2/core/documentcreateattributeNS04.java b/dom/src/test/java/org/w3c/domts/level2/core/documentcreateattributeNS04.java
index bae9800dc..4ec52a202 100644
--- a/dom/src/test/java/org/w3c/domts/level2/core/documentcreateattributeNS04.java
+++ b/dom/src/test/java/org/w3c/domts/level2/core/documentcreateattributeNS04.java
@@ -92,14 +92,14 @@ public void runTest() throws Throwable {
qualifiedName = (String) qualifiedNames.get(indexN1004E);
{
- // BEGIN android-changed
+ // BEGIN Android-changed
// Our exception priorities differ from the spec
try {
attribute = doc.createAttributeNS(namespaceURI, qualifiedName);
fail("documentcreateattributeNS04");
} catch (DOMException expected) {
}
- // END android-changed
+ // END Android-changed
}
}
}
diff --git a/dom/src/test/java/org/w3c/domts/level2/core/setAttributeNS02.java b/dom/src/test/java/org/w3c/domts/level2/core/setAttributeNS02.java
index 9a83561bd..29ed3049e 100644
--- a/dom/src/test/java/org/w3c/domts/level2/core/setAttributeNS02.java
+++ b/dom/src/test/java/org/w3c/domts/level2/core/setAttributeNS02.java
@@ -75,14 +75,14 @@ public void runTest() throws Throwable {
testAddr = elementList.item(0);
{
- // BEGIN android-changed
+ // BEGIN Android-changed
// Our exception priorities differ from the spec
try {
((Element) /*Node */testAddr).setAttributeNS(namespaceURI, qualifiedName, "newValue");
fail("throw_NAMESPACE_ERR");
} catch (DOMException ex) {
}
- // END android-changed
+ // END Android-changed
}
}
/**
diff --git a/expectations/brokentests.txt b/expectations/brokentests.txt
index 5dc7ad8f5..cd24094fd 100644
--- a/expectations/brokentests.txt
+++ b/expectations/brokentests.txt
@@ -45,37 +45,19 @@
description: "Some tests depend on ICU data, which has changed. Others make assumptions about floating point rounding",
result: EXEC_FAILED,
names: [
- "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_BigDecimalExceptionOrder",
"org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_DateTimeConversion",
- "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_FloatConversionE",
- "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_FloatConversionF",
- "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_FloatConversionG",
- "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_FloatDoubleBigDecimalExceptionOrder",
"org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_GeneralConversionOther",
"org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_LineSeparator",
- "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_Percent",
- "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_Width"
+ "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_Percent"
]
},
{
description: "(Needs investigation) Some tests make assertions that don't make sense, others use broken port allocation logic.",
result: EXEC_FAILED,
names: [
- "org.apache.harmony.tests.java.net.Inet6AddressTest#test_getByNameLjava_lang_String",
- "org.apache.harmony.tests.java.net.InetAddressTest#test_getByNameLjava_lang_String",
"org.apache.harmony.tests.java.net.InetAddressTest#test_isReachableLjava_net_NetworkInterfaceII_loopbackInterface"
]
},
-{
- description: "(Needs investigation) Test failures from the harmony import of external/apache-harmony/archive",
- bug: 12189307,
- result: EXEC_FAILED,
- names: [
- "org.apache.harmony.tests.java.util.jar.ManifestTest#testNul",
- "org.apache.harmony.tests.java.util.jar.ManifestTest#testRead",
- "org.apache.harmony.tests.java.util.jar.ManifestTest#testStreamConstructor"
- ]
-},
{
description: "Potentially flakey because they rely on a specific local TCP port being free.",
result: EXEC_FAILED,
@@ -122,13 +104,6 @@
"org.apache.harmony.tests.api.javax.security.cert.X509CertificateTest#testVerifyPublicKeyString"
]
},
-{
- description: "Suffers from side effect of other, currently unknown test",
- result: EXEC_FAILED,
- names: [
- "org.apache.harmony.luni.tests.internal.net.www.protocol.http.HttpURLConnectionTest#testProxyAuthorization"
- ]
-},
{
description: "Support_TestWebServer requires isolation.",
result: EXEC_FAILED,
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index 396b864a9..1f0ef3269 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -18,11 +18,6 @@
name: "org.apache.harmony.crypto.tests.javax.crypto.func.KeyAgreementFunctionalTest#test_KeyAgreement",
bug: 3473300
},
-{
- description: "RandomAccessFile missing finalizer",
- name: "libcore.java.io.RandomAccessFileTest#testRandomAccessFileHasCleanupFinalizer",
- bug: 3015023
-},
{
description: "ICU seems to treat unknown and invalid locales differently",
name: "libcore.java.text.DateFormatSymbolsTest#test_getInstance_unknown_locale",
@@ -69,12 +64,6 @@
],
bug: 2702411
},
-{
- description: "Runtime.getRuntime().traceMethodCalls(true) doesn't return on the host, fails in CTS",
- bug: 3447964,
- result: EXEC_FAILED,
- name: "libcore.java.lang.OldRuntimeTest#test_traceMethodCalls"
-},
{
description: "It's not allowed to pass null as parent class loader to a new ClassLoader anymore. Maybe we need
to change URLClassLoader to allow this? It's not specified.",
@@ -1304,19 +1293,6 @@
result: EXEC_FAILED,
name: "org.apache.harmony.tests.java.lang.MathTest#test_powDD"
},
-{
- description: "Known failures in PropertiesTest: We don't deal with comments in store()",
- bug: 11686302,
- result: EXEC_FAILED,
- names: [
- "org.apache.harmony.tests.java.util.PropertiesTest#testStore_scenario0",
- "org.apache.harmony.tests.java.util.PropertiesTest#testStore_scenario1",
- "org.apache.harmony.tests.java.util.PropertiesTest#testStore_scenario2",
- "org.apache.harmony.tests.java.util.PropertiesTest#testStore_scenario3",
- "org.apache.harmony.tests.java.util.PropertiesTest#testStore_scenario9",
- "org.apache.harmony.tests.java.util.PropertiesTest#testStore_scenario11"
- ]
-},
{
description: "Known failures in URLTest and URLDecoderTest",
bug: 11686814,
@@ -1423,27 +1399,11 @@
"com.android.org.apache.harmony.beans.tests.java.beans.PropertyChangeSupportTest#testSerializationCompatibility"
]
},
-{
- description: "Known precision issue in DecimalFormat",
- bug: 17656132,
- names: [
- "org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatDouble_bug17656132",
- "org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatDouble_roundingProblemCases"
- ]
-},
{
description: "Known failure in GregorianCalendarTest",
bug: 12778197,
name: "org.apache.harmony.tests.java.util.GregorianCalendarTest#test_computeTime"
},
-{
- description: "OkHttp tests require SOCKS 5 support. Android PlainSocketImpl implements SOCKS 4",
- bug: 96926,
- names: [
- "com.squareup.okhttp.SocksProxyTest#proxy",
- "com.squareup.okhttp.SocksProxyTest#proxySelector"
- ]
-},
{
description: "OkHttp tests that fail on Wear devices due to a lack of memory",
bug: 20055487,
@@ -1454,7 +1414,7 @@
},
{
description: "libcore.java.text.DecimalFormatSymbolsTest#test_getInstance_unknown_or_invalid_locale assumes fallback to locale other than en_US_POSIX.",
- bug: 17374604,
+ bug: 17422813,
names: [
"libcore.java.text.DecimalFormatSymbolsTest#test_getInstance_unknown_or_invalid_locale"
]
@@ -1501,15 +1461,6 @@
"libcore.io.OsTest#test_PacketSocketAddress"
]
},
-{
- description: "Need to rewrite tests for the client-side of renegotiation",
- bug: 21876068,
- result: EXEC_FAILED,
- names: [
- "com.android.org.conscrypt.NativeCryptoTest#test_SSL_renegotiate",
- "com.android.org.conscrypt.NativeCryptoTest#test_SSL_do_handshake_clientCertificateRequested_throws_after_renegotiate"
- ]
-},
{
description: "Failures in OldSHA1PRNGSecureRandomTest",
result: EXEC_FAILED,
@@ -1552,5 +1503,13 @@
names: [
"com.android.org.apache.harmony.luni.tests.java.net.URLClassLoaderImplTest#test_Constructor$Ljava_net_URLLjava_lang_ClassLoaderLjava_net_URLStreamHandlerFactory"
]
+},
+{
+ description: "Waiting for ICU 58 to be merged",
+ bug: 31516121,
+ result: EXEC_FAILED,
+ names: [
+ "libcore.java.text.OldBidiTest#testUnicode9EmojisAreLtrNeutral"
+ ]
}
]
diff --git a/expectations/virtualdeviceknownfailures.txt b/expectations/virtualdeviceknownfailures.txt
new file mode 100644
index 000000000..54d0d64f0
--- /dev/null
+++ b/expectations/virtualdeviceknownfailures.txt
@@ -0,0 +1,16 @@
+/*
+ * List of test cases known to fail on a virtual device.
+ */
+[
+{
+ description: "IPv6 connectivity not yet supported in virtual device testing infra",
+ result: EXEC_FAILED,
+ name: "libcore.java.net.SocketTest#testSocketTestAllAddresses",
+ bug: 30965313
+},
+{
+ description: "Virtual devices do not implement the SELinux policy (forbid hard link) asserted by this test",
+ name: "libcore.java.nio.file.Files2Test#test_createLink",
+ bug: 35670953
+}
+]
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/CharArrayReaderTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/CharArrayReaderTest.java
index 88653327a..6a1ba7135 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/CharArrayReaderTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/CharArrayReaderTest.java
@@ -167,6 +167,15 @@ public void test_skipJ() throws IOException {
assertEquals("Skip skipped wrong chars", 'W', cr.read());
}
+ /**
+ * java.io.CharArrayReader#skip(long) overflow
+ */
+ public void test_skipOverflow() throws IOException {
+ cr = new CharArrayReader(hw);
+ assertEquals(1L, cr.skip(1L));
+ assertEquals(hw.length - 1, cr.skip(Long.MAX_VALUE));
+ }
+
/**
* Tears down the fixture, for example, close a network connection. This
* method is called after a test is executed.
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/DataInputStreamTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/DataInputStreamTest.java
index 67a4e5f54..7d890179e 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/DataInputStreamTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/DataInputStreamTest.java
@@ -23,6 +23,7 @@
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
+import java.io.InputStream;
public class DataInputStreamTest extends junit.framework.TestCase {
@@ -564,6 +565,54 @@ public void test_skipBytesI() throws IOException {
+ skipped, skipped == fileString.length());
}
+ // b/30268192 : Some apps rely on the exact calls that
+ // DataInputStream makes on the wrapped InputStream. This
+ // test is to prevent *unintentional* regressions but may
+ // change in future releases.
+ public void test_readShortUsesMultiByteRead() throws IOException {
+ ThrowExceptionOnSingleByteReadInputStream
+ is = new ThrowExceptionOnSingleByteReadInputStream();
+ DataInputStream dis = new DataInputStream(is);
+ dis.readShort();
+ is.assertMultiByteReadWasCalled();
+ }
+
+ // b/30268192 : Some apps rely on the exact calls that
+ // DataInputStream makes on the wrapped InputStream. This
+ // test is to prevent *unintentional* regressions but may
+ // change in future releases.
+ public void test_readCharUsesMultiByteRead() throws IOException {
+ ThrowExceptionOnSingleByteReadInputStream
+ is = new ThrowExceptionOnSingleByteReadInputStream();
+ DataInputStream dis = new DataInputStream(is);
+ dis.readChar();
+ is.assertMultiByteReadWasCalled();
+ }
+
+ // b/30268192 : Some apps rely on the exact calls that
+ // DataInputStream makes on the wrapped InputStream. This
+ // test is to prevent *unintentional* regressions but may
+ // change in future releases.
+ public void test_readIntUsesMultiByteRead() throws IOException {
+ ThrowExceptionOnSingleByteReadInputStream
+ is = new ThrowExceptionOnSingleByteReadInputStream();
+ DataInputStream dis = new DataInputStream(is);
+ dis.readInt();
+ is.assertMultiByteReadWasCalled();
+ }
+
+ // b/30268192 : Some apps rely on the exact calls that
+ // DataInputStream makes on the wrapped InputStream. This
+ // test is to prevent *unintentional* regressions but may
+ // change in future releases.
+ public void test_readUnsignedShortUsesMultiByteRead() throws IOException {
+ ThrowExceptionOnSingleByteReadInputStream
+ is = new ThrowExceptionOnSingleByteReadInputStream();
+ DataInputStream dis = new DataInputStream(is);
+ dis.readUnsignedShort();
+ is.assertMultiByteReadWasCalled();
+ }
+
private void openDataInputStream() throws IOException {
dis = new DataInputStream(new ByteArrayInputStream(bos.toByteArray()));
}
@@ -591,4 +640,27 @@ protected void tearDown() {
} catch (Exception e) {
}
}
+
+ public static class ThrowExceptionOnSingleByteReadInputStream extends InputStream {
+
+ private boolean multiByteReadWasCalled = false;
+
+ @Override
+ public int read() throws IOException {
+ fail("Should not call single byte read");
+ return 0;
+ }
+
+ @Override
+ public int read(byte[] b, int i, int j) throws IOException {
+ multiByteReadWasCalled = true;
+ return j;
+ }
+
+ public void assertMultiByteReadWasCalled() {
+ if (!multiByteReadWasCalled) {
+ fail("read(byte[], int, int) was not called");
+ }
+ }
+ }
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FileInputStreamTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FileInputStreamTest.java
index af54d4b89..4375afd01 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FileInputStreamTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FileInputStreamTest.java
@@ -24,9 +24,14 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
-import junit.framework.TestCase;
-
-public class FileInputStreamTest extends TestCase {
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
+
+public class FileInputStreamTest extends TestCaseWithRules {
+ @Rule
+ public TestRule guardRule = ResourceLeakageDetector.getRule();
private String fileName;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FileOutputStreamTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FileOutputStreamTest.java
index 11dd8b621..cc0d9539f 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FileOutputStreamTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FileOutputStreamTest.java
@@ -25,10 +25,14 @@
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
-import junit.framework.TestCase;
-
-public class FileOutputStreamTest extends TestCase {
+public class FileOutputStreamTest extends TestCaseWithRules {
+ @Rule
+ public TestRule guardRule = ResourceLeakageDetector.getRule();
private FileOutputStream fos;
private FileInputStream fis;
@@ -92,6 +96,7 @@ public void test_ConstructorLjava_lang_String() throws IOException {
f = File.createTempFile("FileOutputStreamTest", "tst");
String fileName = f.getAbsolutePath();
fos = new FileOutputStream(fileName);
+ fos.close();
// Harmony 4012.
fos = new FileOutputStream("/dev/null");
@@ -285,12 +290,13 @@ public void test_getChannel() throws IOException {
// Regression for HARMONY-508
File tmpfile = File.createTempFile("FileOutputStream", "tmp");
tmpfile.deleteOnExit();
- FileOutputStream fos = new FileOutputStream(tmpfile);
- fos.write(bytes);
- fos.flush();
- fos.close();
- FileOutputStream f = new FileOutputStream(tmpfile, true);
- assertEquals(10, f.getChannel().position());
+ try (FileOutputStream fos = new FileOutputStream(tmpfile)) {
+ fos.write(bytes);
+ fos.flush();
+ }
+ try (FileOutputStream f = new FileOutputStream(tmpfile, true)) {
+ assertEquals(10, f.getChannel().position());
+ }
}
public void test_getChannel_Append() throws IOException {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectStreamClassTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectStreamClassTest.java
index 7ae46177d..bebeb6ec5 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectStreamClassTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectStreamClassTest.java
@@ -17,7 +17,7 @@
package org.apache.harmony.tests.java.io;
-import junit.framework.TestCase;
+import dalvik.system.VMRuntime;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
@@ -25,8 +25,10 @@
import java.io.ObjectStreamClass;
import java.io.ObjectStreamField;
import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
+import junit.framework.TestCase;
public class ObjectStreamClassTest extends TestCase {
@@ -221,20 +223,43 @@ public void test_lookupAnyLjava_lang_Class() {
// http://b/28106822
public void testBug28106822() throws Exception {
- Method getConstructorId = ObjectStreamClass.class.getDeclaredMethod(
- "getConstructorId", Class.class);
- getConstructorId.setAccessible(true);
-
- assertEquals(1189998819991197253L, getConstructorId.invoke(null, Object.class));
- assertEquals(1189998819991197253L, getConstructorId.invoke(null, String.class));
-
- Method newInstance = ObjectStreamClass.class.getDeclaredMethod("newInstance",
- Class.class, Long.TYPE);
- newInstance.setAccessible(true);
+ int savedTargetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
+ try {
+ // Assert behavior up to 24
+ VMRuntime.getRuntime().setTargetSdkVersion(24);
+ Method getConstructorId = ObjectStreamClass.class.getDeclaredMethod(
+ "getConstructorId", Class.class);
+ getConstructorId.setAccessible(true);
+
+ assertEquals(1189998819991197253L, getConstructorId.invoke(null, Object.class));
+ assertEquals(1189998819991197253L, getConstructorId.invoke(null, String.class));
+
+ Method newInstance = ObjectStreamClass.class.getDeclaredMethod("newInstance",
+ Class.class, Long.TYPE);
+ newInstance.setAccessible(true);
+
+ Object obj = newInstance.invoke(null, String.class, 0 /* ignored */);
+ assertNotNull(obj);
+ assertTrue(obj instanceof String);
+
+ // Assert behavior from API 25
+ VMRuntime.getRuntime().setTargetSdkVersion(25);
+ try {
+ getConstructorId.invoke(null, Object.class);
+ fail();
+ } catch (InvocationTargetException expected) {
+ assertTrue(expected.getCause() instanceof UnsupportedOperationException);
+ }
+ try {
+ newInstance.invoke(null, String.class, 0 /* ignored */);
+ fail();
+ } catch (InvocationTargetException expected) {
+ assertTrue(expected.getCause() instanceof UnsupportedOperationException);
+ }
- Object obj = newInstance.invoke(null, String.class, 0 /* ignored */);
- assertNotNull(obj);
- assertTrue(obj instanceof String);
+ } finally {
+ VMRuntime.getRuntime().setTargetSdkVersion(savedTargetSdkVersion);
+ }
}
// Class without method
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/RandomAccessFileTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/RandomAccessFileTest.java
index f6784fbf4..b6610d13f 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/RandomAccessFileTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/RandomAccessFileTest.java
@@ -26,8 +26,14 @@
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.NonWritableChannelException;
-
-public class RandomAccessFileTest extends junit.framework.TestCase {
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
+
+public class RandomAccessFileTest extends TestCaseWithRules {
+ @Rule
+ public TestRule resourceLeakageDetectorRule = ResourceLeakageDetector.getRule();
public String fileName;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/SerializationStressTest4.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/SerializationStressTest4.java
index c5dd4f02f..40706b3a3 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/SerializationStressTest4.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/SerializationStressTest4.java
@@ -30,11 +30,13 @@
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
@@ -187,43 +189,17 @@ public void test_writeObject_Character() {
}
- public void test_writeObject_Collections_UnmodifiableCollection() {
+ public void test_writeObject_Collections_UnmodifiableCollection() throws Exception {
// Test for method void
// java.io.ObjectOutputStream.writeObject(java.util.Collections.UnmodifiableCollection)
- Object objToSave = null;
- Object objLoaded = null;
+ Collection objToSave = java.util.Collections.unmodifiableCollection(SET);
+ Collection objLoaded = (Collection) dumpAndReload(objToSave);
- try {
- objToSave = Collections.unmodifiableCollection(SET);
- if (DEBUG)
- System.out.println("Obj = " + objToSave);
- objLoaded = dumpAndReload(objToSave);
-
- // Has to have worked
- boolean equals;
- equals = ((java.util.Collection) objToSave).size() == ((java.util.Collection) objLoaded)
- .size();
- if (equals) {
- java.util.Iterator iter1 = ((java.util.Collection) objToSave)
- .iterator(), iter2 = ((java.util.Collection) objLoaded)
- .iterator();
- while (iter1.hasNext())
- equals = equals && iter1.next().equals(iter2.next());
- }
- assertTrue(MSG_TEST_FAILED + objToSave, equals);
- } catch (IOException e) {
- fail("IOException serializing " + objToSave + " : "
- + e.getMessage());
- } catch (ClassNotFoundException e) {
- fail("ClassNotFoundException reading Object type : "
- + e.getMessage());
- } catch (Error err) {
- System.out.println("Error when obj = " + objToSave);
- // err.printStackTrace();
- throw err;
- }
+ HashSet objToSaveElements = new HashSet<>(objToSave);
+ HashSet objLoadedElements = new HashSet<>(objLoaded);
+ assertEquals(objToSaveElements, objLoadedElements);
}
public void test_writeObject_Format() {
@@ -1420,42 +1396,17 @@ public void test_writeObject_Long() {
}
- public void test_writeObject_Collections_SynchronizedCollection() {
+ public void test_writeObject_Collections_SynchronizedCollection() throws Exception {
// Test for method void
// java.io.ObjectOutputStream.writeObject(java.util.Collections.SynchronizedCollection)
- Object objToSave = null;
- Object objLoaded = null;
+ Collection objToSave = java.util.Collections.synchronizedCollection(SET);
+ Collection objLoaded = (Collection) dumpAndReload(objToSave);
- try {
- objToSave = java.util.Collections.synchronizedCollection(SET);
- if (DEBUG)
- System.out.println("Obj = " + objToSave);
- objLoaded = dumpAndReload(objToSave);
-
- // Has to have worked
- boolean equals;
- equals = ((java.util.Collection) objToSave).size() == ((java.util.Collection) objLoaded)
- .size();
- if (equals) {
- java.util.Iterator iter1 = ((java.util.Collection) objToSave)
- .iterator(), iter2 = ((java.util.Collection) objLoaded)
- .iterator();
- while (iter1.hasNext())
- equals = equals && iter1.next().equals(iter2.next());
- }
- assertTrue(MSG_TEST_FAILED + objToSave, equals);
- } catch (IOException e) {
- fail("Exception serializing " + objToSave + " : " + e.getMessage());
- } catch (ClassNotFoundException e) {
- fail("ClassNotFoundException reading Object type: "
- + e.getMessage());
- } catch (Error err) {
- System.out.println("Error when obj = " + objToSave);
- // err.printStackTrace();
- throw err;
- }
+ HashSet objToSaveElements = new HashSet<>(objToSave);
+ HashSet objLoadedElements = new HashSet<>(objLoaded);
+ assertEquals(objToSaveElements, objLoadedElements);
}
public void test_writeObject_Random() {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/Character_UnicodeBlockTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/Character_UnicodeBlockTest.java
index 792ee3dff..9a4a406e9 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/Character_UnicodeBlockTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/Character_UnicodeBlockTest.java
@@ -4,9 +4,9 @@
* 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.
@@ -232,6 +232,14 @@ public void test_ofC() {
assertEquals(Character.UnicodeBlock.SPECIALS, Character.UnicodeBlock.of((char) 0xfff0));
assertEquals(Character.UnicodeBlock.SPECIALS, Character.UnicodeBlock.of((char) 0xffff));
+ // Blocks added in 1.8
+ assertEquals(Character.UnicodeBlock.ARABIC_EXTENDED_A, Character.UnicodeBlock.of((char) 0x08a0));
+ assertEquals(Character.UnicodeBlock.ARABIC_EXTENDED_A, Character.UnicodeBlock.of((char) 0x08ff));
+ assertEquals(Character.UnicodeBlock.SUNDANESE_SUPPLEMENT, Character.UnicodeBlock.of((char) 0x1cc0));
+ assertEquals(Character.UnicodeBlock.SUNDANESE_SUPPLEMENT, Character.UnicodeBlock.of((char) 0x1ccf));
+ assertEquals(Character.UnicodeBlock.MEETEI_MAYEK_EXTENSIONS, Character.UnicodeBlock.of((char) 0xaae0));
+ assertEquals(Character.UnicodeBlock.MEETEI_MAYEK_EXTENSIONS, Character.UnicodeBlock.of((char) 0xaaff));
+
// Negative test: The range [0x0860, 0x08A0) is currently unassigned.
assertEquals(null, Character.UnicodeBlock.of((char) 0x0860));
assertEquals(null, Character.UnicodeBlock.of((char) 0x089F));
@@ -489,6 +497,30 @@ public void test_ofI() {
assertEquals(Character.UnicodeBlock.SUPPLEMENTARY_PRIVATE_USE_AREA_B, Character.UnicodeBlock.of(0x100000));
assertEquals(Character.UnicodeBlock.SUPPLEMENTARY_PRIVATE_USE_AREA_B, Character.UnicodeBlock.of(0x10ffff));
+ // Blocks added in 1.8
+ assertEquals(Character.UnicodeBlock.ARABIC_EXTENDED_A, Character.UnicodeBlock.of(0x08a0));
+ assertEquals(Character.UnicodeBlock.ARABIC_EXTENDED_A, Character.UnicodeBlock.of(0x08ff));
+ assertEquals(Character.UnicodeBlock.SUNDANESE_SUPPLEMENT, Character.UnicodeBlock.of(0x1cc0));
+ assertEquals(Character.UnicodeBlock.SUNDANESE_SUPPLEMENT, Character.UnicodeBlock.of(0x1ccf));
+ assertEquals(Character.UnicodeBlock.MEETEI_MAYEK_EXTENSIONS, Character.UnicodeBlock.of(0xaae0));
+ assertEquals(Character.UnicodeBlock.MEETEI_MAYEK_EXTENSIONS, Character.UnicodeBlock.of(0xaaff));
+ assertEquals(Character.UnicodeBlock.MEROITIC_HIEROGLYPHS, Character.UnicodeBlock.of(0x10980));
+ assertEquals(Character.UnicodeBlock.MEROITIC_HIEROGLYPHS, Character.UnicodeBlock.of(0x1099f));
+ assertEquals(Character.UnicodeBlock.MEROITIC_CURSIVE, Character.UnicodeBlock.of(0x109a0));
+ assertEquals(Character.UnicodeBlock.MEROITIC_CURSIVE, Character.UnicodeBlock.of(0x109ff));
+ assertEquals(Character.UnicodeBlock.SORA_SOMPENG, Character.UnicodeBlock.of(0x110d0));
+ assertEquals(Character.UnicodeBlock.SORA_SOMPENG, Character.UnicodeBlock.of(0x110ff));
+ assertEquals(Character.UnicodeBlock.CHAKMA, Character.UnicodeBlock.of(0x11100));
+ assertEquals(Character.UnicodeBlock.CHAKMA, Character.UnicodeBlock.of(0x1114f));
+ assertEquals(Character.UnicodeBlock.SHARADA, Character.UnicodeBlock.of(0x11180));
+ assertEquals(Character.UnicodeBlock.SHARADA, Character.UnicodeBlock.of(0x111df));
+ assertEquals(Character.UnicodeBlock.TAKRI, Character.UnicodeBlock.of(0x11680));
+ assertEquals(Character.UnicodeBlock.TAKRI, Character.UnicodeBlock.of(0x116cf));
+ assertEquals(Character.UnicodeBlock.MIAO, Character.UnicodeBlock.of(0x16f00));
+ assertEquals(Character.UnicodeBlock.MIAO, Character.UnicodeBlock.of(0x16f9f));
+ assertEquals(Character.UnicodeBlock.ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS, Character.UnicodeBlock.of(0x1ee00));
+ assertEquals(Character.UnicodeBlock.ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS, Character.UnicodeBlock.of(0x1eeff));
+
// Negative test: The range [0x0860, 0x08A0) is currently unassigned.
assertEquals(null, Character.UnicodeBlock.of((char) 0x0860));
assertEquals(null, Character.UnicodeBlock.of((char) 0x089F));
@@ -793,6 +825,37 @@ public void test_forNameLjava_lang_String() {
assertEquals(Character.UnicodeBlock.SUPPLEMENTARY_PRIVATE_USE_AREA_B, Character.UnicodeBlock.forName("SUPPLEMENTARY_PRIVATE_USE_AREA_B"));
assertEquals(Character.UnicodeBlock.SUPPLEMENTARY_PRIVATE_USE_AREA_B, Character.UnicodeBlock.forName("Supplementary Private Use Area-B"));
assertEquals(Character.UnicodeBlock.SUPPLEMENTARY_PRIVATE_USE_AREA_B, Character.UnicodeBlock.forName("SupplementaryPrivateUseArea-B"));
+
+ // Blocks added in 1.8
+ assertEquals(Character.UnicodeBlock.ARABIC_EXTENDED_A, Character.UnicodeBlock.forName("ARABIC_EXTENDED_A"));
+ assertEquals(Character.UnicodeBlock.ARABIC_EXTENDED_A, Character.UnicodeBlock.forName("arabic extended-A"));
+ assertEquals(Character.UnicodeBlock.ARABIC_EXTENDED_A, Character.UnicodeBlock.forName("ArabicExtended-A"));
+ assertEquals(Character.UnicodeBlock.SUNDANESE_SUPPLEMENT, Character.UnicodeBlock.forName("SUNDANESE_SUPPLEMENT"));
+ assertEquals(Character.UnicodeBlock.SUNDANESE_SUPPLEMENT, Character.UnicodeBlock.forName("Sundanese Supplement"));
+ assertEquals(Character.UnicodeBlock.SUNDANESE_SUPPLEMENT, Character.UnicodeBlock.forName("SundaneseSupplement"));
+ assertEquals(Character.UnicodeBlock.MEETEI_MAYEK_EXTENSIONS, Character.UnicodeBlock.forName("MEETEI_MAYEK_EXTENSIONS"));
+ assertEquals(Character.UnicodeBlock.MEETEI_MAYEK_EXTENSIONS, Character.UnicodeBlock.forName("MEETEI MAYEK EXTENSIONS"));
+ assertEquals(Character.UnicodeBlock.MEETEI_MAYEK_EXTENSIONS, Character.UnicodeBlock.forName("MeeteiMayekExtensions"));
+ assertEquals(Character.UnicodeBlock.MEROITIC_HIEROGLYPHS, Character.UnicodeBlock.forName("MEROITIC_HIEROGLYPHS"));
+ assertEquals(Character.UnicodeBlock.MEROITIC_HIEROGLYPHS, Character.UnicodeBlock.forName("MEROITIC HIEROGLYPHS"));
+ assertEquals(Character.UnicodeBlock.MEROITIC_HIEROGLYPHS, Character.UnicodeBlock.forName("MeroiticHieroglyphs"));
+ assertEquals(Character.UnicodeBlock.MEROITIC_CURSIVE, Character.UnicodeBlock.forName("MEROITIC_CURSIVE"));
+ assertEquals(Character.UnicodeBlock.MEROITIC_CURSIVE, Character.UnicodeBlock.forName("MEROITIC CURSIVE"));
+ assertEquals(Character.UnicodeBlock.MEROITIC_CURSIVE, Character.UnicodeBlock.forName("MeroiticCursive"));
+ assertEquals(Character.UnicodeBlock.SORA_SOMPENG, Character.UnicodeBlock.forName("SORA_SOMPENG"));
+ assertEquals(Character.UnicodeBlock.SORA_SOMPENG, Character.UnicodeBlock.forName("SORA SOMPENG"));
+ assertEquals(Character.UnicodeBlock.SORA_SOMPENG, Character.UnicodeBlock.forName("SoraSompeng"));
+ assertEquals(Character.UnicodeBlock.CHAKMA, Character.UnicodeBlock.forName("CHAKMA"));
+ assertEquals(Character.UnicodeBlock.SHARADA, Character.UnicodeBlock.forName("SHARADA"));
+ assertEquals(Character.UnicodeBlock.TAKRI, Character.UnicodeBlock.forName("TAKRI"));
+ assertEquals(Character.UnicodeBlock.MIAO, Character.UnicodeBlock.forName("MIAO"));
+ assertEquals(Character.UnicodeBlock.ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS,
+ Character.UnicodeBlock.forName("ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS"));
+ assertEquals(Character.UnicodeBlock.ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS,
+ Character.UnicodeBlock.forName("ARABIC MATHEMATICAL ALPHABETIC SYMBOLS"));
+ assertEquals(Character.UnicodeBlock.ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS,
+ Character.UnicodeBlock.forName("ArabicMathematicalAlphabeticSymbols"));
+
}
public void test_forNameLjava_lang_StringExceptions() {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ClassTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ClassTest.java
index 95dad9a21..5d97393bd 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ClassTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ClassTest.java
@@ -21,6 +21,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@@ -34,7 +36,9 @@
import java.security.Security;
import java.util.Arrays;
import java.util.List;
+import java.util.TreeMap;
import java.util.Vector;
+import java.util.function.Function;
public class ClassTest extends junit.framework.TestCase {
@@ -545,27 +549,6 @@ public void test_newInstance() throws Exception {
}
}
- /**
- * java.lang.Class#toString()
- */
- public void test_toString() throws ClassNotFoundException {
- assertEquals("Class toString printed wrong value",
- "int", int.class.toString());
- Class> clazz = null;
- clazz = Class.forName("[I");
- assertEquals("Class toString printed wrong value",
- "class [I", clazz.toString());
-
- clazz = Class.forName("java.lang.Object");
- assertEquals("Class toString printed wrong value",
- "class java.lang.Object", clazz.toString());
-
- clazz = Class.forName("[Ljava.lang.Object;");
- assertEquals("Class toString printed wrong value",
- "class [Ljava.lang.Object;", clazz.toString());
- }
-
-
// Regression Test for JIRA-2047
public void test_getResourceAsStream_withSharpChar() throws Exception {
// Class.getResourceAsStream() requires a leading "/" for absolute paths.
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ProcessBuilderTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ProcessBuilderTest.java
index 87cf88cbc..2fea31a7b 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ProcessBuilderTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ProcessBuilderTest.java
@@ -4,9 +4,9 @@
* 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.
@@ -168,4 +168,13 @@ public void testStart() throws IOException {
assertTrue(err.read(buf) > 0);
}
}
+
+ public void testNullInCommand() {
+ ProcessBuilder pb = new ProcessBuilder("ls", "with\u0000inside");
+ try {
+ pb.start();
+ fail();
+ } catch(IOException expected) {}
+ }
+
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ProcessManagerTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ProcessManagerTest.java
index 9f7474a75..f5d416351 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ProcessManagerTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ProcessManagerTest.java
@@ -20,7 +20,7 @@
import java.io.BufferedReader;
import java.io.File;
-import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -174,7 +174,7 @@ private static void stuff() {
rt = null;
}
- InputStream in;
+ FileOutputStream out;
public void testCloseNonStandardFds()
throws IOException, InterruptedException {
@@ -183,8 +183,9 @@ public void testCloseNonStandardFds()
Process process = Runtime.getRuntime().exec(commands, null, null);
int before = countLines(process);
+ File tmpFile = File.createTempFile("testCloseNonStandardFds", ".txt");
// Open a new fd.
- this.in = new FileInputStream("/proc/version");
+ this.out = new FileOutputStream(tmpFile);
try {
process = Runtime.getRuntime().exec(commands, null, null);
@@ -193,7 +194,8 @@ public void testCloseNonStandardFds()
// Assert that the new fd wasn't open in the second run.
assertEquals(before, after);
} finally {
- this.in = null;
+ this.out.close();
+ tmpFile.delete();
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ProcessTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ProcessTest.java
index a5b6509d9..cf6f89ecd 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ProcessTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ProcessTest.java
@@ -23,6 +23,7 @@
import java.io.OutputStream;
import java.util.ArrayList;
import libcore.io.Libcore;
+import java.util.concurrent.TimeUnit;
public class ProcessTest extends junit.framework.TestCase {
// Test that failures to exec don't leave zombies lying around.
@@ -140,4 +141,45 @@ public void test_destroy() throws Exception {
process.destroy();
process.destroy();
}
+
+ public void test_destroyForcibly() throws Exception {
+ String[] commands = { "sh", "-c", "sleep 3000"};
+ Process process = Runtime.getRuntime().exec(commands, null, null);
+ assertNotNull(process.destroyForcibly());
+ process.waitFor(); // destroy is asynchronous.
+ assertTrue(process.exitValue() != 0);
+ }
+
+ public void test_isAlive() throws Exception {
+ String[] commands = { "sh", "-c", "sleep 3000"};
+ Process process = Runtime.getRuntime().exec(commands, null, null);
+ assertTrue(process.isAlive());
+ assertNotNull(process.destroyForcibly());
+ process.waitFor(); // destroy is asynchronous.
+ assertFalse(process.isAlive());
+ }
+
+ public void test_waitForTimeout() throws Exception {
+ String[] commands = { "sh", "-c", "sleep 3000"};
+ Process process = Runtime.getRuntime().exec(commands, null, null);
+ assertFalse(process.waitFor(0, TimeUnit.MICROSECONDS));
+ assertTrue(process.isAlive());
+ assertFalse(process.waitFor(500, TimeUnit.MICROSECONDS));
+ assertTrue(process.isAlive());
+ assertNotNull(process.destroyForcibly());
+ assertTrue(process.waitFor(2, TimeUnit.SECONDS));
+ assertFalse(process.isAlive());
+ }
+
+ public void test_waitForTimeout_NPE() throws Exception {
+ String[] commands = { "sh", "-c", "sleep 3000"};
+ Process process = Runtime.getRuntime().exec(commands, null, null);
+ try {
+ process.waitFor(500, null);
+ fail();
+ } catch(NullPointerException expected) {}
+ assertNotNull(process.destroyForcibly());
+ process.waitFor();
+ }
+
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ThreadLocalTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ThreadLocalTest.java
index 400ff01a3..dd03a8066 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ThreadLocalTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ThreadLocalTest.java
@@ -18,6 +18,7 @@
package org.apache.harmony.tests.java.lang;
import junit.framework.TestCase;
+import java.util.concurrent.atomic.AtomicReference;
public class ThreadLocalTest extends TestCase {
@@ -147,4 +148,43 @@ public void run() {
THREADVALUE.result);
}
+
+ /**
+ * java.lang.ThreadLocal#withInitial()
+ */
+ public void test_withInitial() {
+ // The ThreadLocal has to run once for each thread that touches the
+ // ThreadLocal
+ final String INITIAL_VALUE = "'foo'";
+ final String OTHER_VALUE = "'bar'";
+ final ThreadLocal l1 = ThreadLocal.withInitial(() -> INITIAL_VALUE);
+
+ assertSame(INITIAL_VALUE, l1.get());
+
+ l1.set(OTHER_VALUE);
+ assertSame(OTHER_VALUE, l1.get());
+
+ assertTrue("ThreadLocal's value should be " + OTHER_VALUE
+ + " but is " + l1.get(), l1.get() == OTHER_VALUE);
+
+ AtomicReference threadValue = new AtomicReference();
+
+ Thread t = new Thread() {
+ @Override
+ public void run() {
+ threadValue.set(l1.get());
+ }
+ };
+
+ // Wait for the other Thread assign what it observes as the value of the
+ // variable
+ t.start();
+ try {
+ t.join();
+ } catch (InterruptedException ie) {
+ fail("Interrupted!!");
+ }
+
+ assertSame(INITIAL_VALUE, threadValue.get());
+ }
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/PhantomReferenceTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/PhantomReferenceTest.java
index 5a80fde8b..34dd0fa56 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/PhantomReferenceTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/PhantomReferenceTest.java
@@ -49,7 +49,24 @@ public void test_get() {
/**
* java.lang.Runtime#gc()
*/
- public void test_gcInteraction() {
+ public void test_gcInteraction_Runtime() {
+ check_gcInteraction(() -> { Runtime.getRuntime().gc(); } );
+ }
+
+ /**
+ * Checks that the sequence {@link System#gc()}, {@link System#runFinalization()}}
+ * also has the effect as asserted for {@link Runtime#gc()} elsewhere. The
+ * conditions under which System.gc() results in a garbage collection are an
+ * implementation detail not guaranteed by documentation.
+ */
+ public void test_gcInteraction_System() {
+ check_gcInteraction(() -> {
+ System.gc();
+ System.runFinalization();
+ } );
+ }
+
+ private void check_gcInteraction(Runnable gc) {
class TestPhantomReference extends PhantomReference {
public TestPhantomReference(T referent,
ReferenceQueue super T> q) {
@@ -58,7 +75,7 @@ public TestPhantomReference(T referent,
public boolean enqueue() {
// Initiate another GC from inside enqueue() to
// see if it causes any problems inside the VM.
- Runtime.getRuntime().gc();
+ gc.run();
return super.enqueue();
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/reflect/GenericArrayTypeTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/reflect/GenericArrayTypeTest.java
index 4888fd21f..58b15e0e0 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/reflect/GenericArrayTypeTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/reflect/GenericArrayTypeTest.java
@@ -36,6 +36,9 @@ public void testGetGenericComponentType() throws Exception {
Field field = clazz.getDeclaredField("array");
Type genericType = field.getGenericType();
assertInstanceOf(GenericArrayType.class, genericType);
+ assertEquals("T[]", genericType.toString());
+ assertEquals("T[]", genericType.getTypeName());
+
Type componentType = ((GenericArrayType) genericType).getGenericComponentType();
assertEquals(getTypeParameter(clazz), componentType);
assertInstanceOf(TypeVariable.class, componentType);
@@ -52,13 +55,17 @@ public void testParameterizedComponentType() throws Exception {
Class extends B> clazz = GenericArrayTypeTest.B.class;
Field field = clazz.getDeclaredField("array");
Type genericType = field.getGenericType();
-
assertInstanceOf(GenericArrayType.class, genericType);
+
+ String bName = B.class.getName();
+ assertEquals(bName + "[]", genericType.toString());
+ assertEquals(bName + "[]", genericType.getTypeName());
+
GenericArrayType arrayType = (GenericArrayType) genericType;
Type componentType = arrayType.getGenericComponentType();
assertInstanceOf(ParameterizedType.class, componentType);
- ParameterizedType parameteriezdType = (ParameterizedType) componentType;
- assertEquals(clazz, parameteriezdType.getRawType());
- assertEquals(clazz.getTypeParameters()[0], parameteriezdType.getActualTypeArguments()[0]);
+ ParameterizedType parameterizedType = (ParameterizedType) componentType;
+ assertEquals(clazz, parameterizedType.getRawType());
+ assertEquals(clazz.getTypeParameters()[0], parameterizedType.getActualTypeArguments()[0]);
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/reflect/ParameterizedTypeTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/reflect/ParameterizedTypeTest.java
index 3b2614eae..6004863b4 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/reflect/ParameterizedTypeTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/reflect/ParameterizedTypeTest.java
@@ -32,6 +32,11 @@ public void testStringParameterizedSuperClass() {
Class extends B> clazz = B.class;
Type genericSuperclass = clazz.getGenericSuperclass();
assertInstanceOf(ParameterizedType.class, genericSuperclass);
+
+ String aName = A.class.getName();
+ assertEquals(aName + "", genericSuperclass.toString());
+ assertEquals(aName + "", genericSuperclass.getTypeName());
+
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
assertEquals(ParameterizedTypeTest.class, parameterizedType.getOwnerType());
assertEquals(A.class, parameterizedType.getRawType());
@@ -48,6 +53,11 @@ public void testTypeParameterizedSuperClass() {
Class extends D> clazz = D.class;
Type genericSuperclass = clazz.getGenericSuperclass();
assertInstanceOf(ParameterizedType.class, genericSuperclass);
+
+ String cName = C.class.getName();
+ assertEquals(cName + "", genericSuperclass.toString());
+ assertEquals(cName + "", genericSuperclass.getTypeName());
+
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
assertEquals(ParameterizedTypeTest.class, parameterizedType.getOwnerType());
assertEquals(C.class, parameterizedType.getRawType());
@@ -70,6 +80,10 @@ public void testParameterizedMemeber() throws Exception{
assertEquals(ParameterizedTypeTest.class, parameterizedType.getOwnerType());
assertEquals(E.class, parameterizedType.getRawType());
+ String eName = E.class.getName();
+ assertEquals(eName + "", parameterizedType.toString());
+ assertEquals(eName + "", parameterizedType.getTypeName());
+
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
assertLenghtOne(actualTypeArguments);
assertEquals(getTypeParameter(clazz), actualTypeArguments[0]);
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/reflect/TypeVariableTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/reflect/TypeVariableTest.java
index d1c7ea995..8f93da484 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/reflect/TypeVariableTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/reflect/TypeVariableTest.java
@@ -35,6 +35,8 @@ public void testSimpleTypeVariableOnClass(){
TypeVariable typeVariable = typeParameters[0];
assertEquals(clazz, typeVariable.getGenericDeclaration());
assertEquals("T", typeVariable.getName());
+ assertEquals("T", typeVariable.toString());
+ assertEquals("T", typeVariable.getTypeName());
Type[] bounds = typeVariable.getBounds();
assertLenghtOne(bounds);
assertEquals(Object.class, bounds[0]);
@@ -51,6 +53,8 @@ public void testSimpleTypeVariableOnMethod() throws Exception{
TypeVariable typeVariable = typeParameters[0];
assertEquals(method, typeVariable.getGenericDeclaration());
assertEquals("T", typeVariable.getName());
+ assertEquals("T", typeVariable.toString());
+ assertEquals("T", typeVariable.getTypeName());
Type[] bounds = typeVariable.getBounds();
assertLenghtOne(bounds);
assertEquals(Object.class, bounds[0]);
@@ -67,6 +71,8 @@ public void testSimpleTypeVariableOnConstructor() throws Exception{
TypeVariable> typeVariable = typeParameters[0];
assertEquals(constructor, typeVariable.getGenericDeclaration());
assertEquals("T", typeVariable.getName());
+ assertEquals("T", typeVariable.toString());
+ assertEquals("T", typeVariable.getTypeName());
Type[] bounds = typeVariable.getBounds();
assertLenghtOne(bounds);
assertEquals(Object.class, bounds[0]);
@@ -79,13 +85,18 @@ public void testMultipleTypeVariablesOnClass() throws Exception {
assertEquals(3, typeParameters.length);
assertEquals("Q", typeParameters[0].getName());
assertEquals(clazz, typeParameters[0].getGenericDeclaration());
+ assertEquals("Q", typeParameters[0].toString());
+ assertEquals("Q", typeParameters[0].getTypeName());
assertEquals("R", typeParameters[1].getName());
assertEquals(clazz, typeParameters[1].getGenericDeclaration());
+ assertEquals("R", typeParameters[1].toString());
+ assertEquals("R", typeParameters[1].getTypeName());
assertEquals("S", typeParameters[2].getName());
assertEquals(clazz, typeParameters[2].getGenericDeclaration());
-
+ assertEquals("S", typeParameters[2].toString());
+ assertEquals("S", typeParameters[2].getTypeName());
}
static class E {
@@ -99,12 +110,18 @@ public void testMultipleTypeVariablesOnMethod() throws Exception {
assertEquals(3, typeParameters.length);
assertEquals("Q", typeParameters[0].getName());
assertEquals(method, typeParameters[0].getGenericDeclaration());
+ assertEquals("Q", typeParameters[0].toString());
+ assertEquals("Q", typeParameters[0].getTypeName());
assertEquals("R", typeParameters[1].getName());
assertEquals(method, typeParameters[1].getGenericDeclaration());
+ assertEquals("R", typeParameters[1].toString());
+ assertEquals("R", typeParameters[1].getTypeName());
assertEquals("S", typeParameters[2].getName());
assertEquals(method, typeParameters[2].getGenericDeclaration());
+ assertEquals("S", typeParameters[2].toString());
+ assertEquals("S", typeParameters[2].getTypeName());
}
static class F {
@@ -118,12 +135,18 @@ public void testMultipleTypeVariablesOnConstructor() throws Exception {
assertEquals(3, typeParameters.length);
assertEquals("Q", typeParameters[0].getName());
assertEquals(constructor, typeParameters[0].getGenericDeclaration());
+ assertEquals("Q", typeParameters[0].toString());
+ assertEquals("Q", typeParameters[0].getTypeName());
assertEquals("R", typeParameters[1].getName());
assertEquals(constructor, typeParameters[1].getGenericDeclaration());
+ assertEquals("R", typeParameters[1].toString());
+ assertEquals("R", typeParameters[1].getTypeName());
assertEquals("S", typeParameters[2].getName());
assertEquals(constructor, typeParameters[2].getGenericDeclaration());
+ assertEquals("S", typeParameters[2].toString());
+ assertEquals("S", typeParameters[2].getTypeName());
}
static class G {}
@@ -135,6 +158,8 @@ public void testSingleBound() throws Exception {
Type[] bounds = typeVariable.getBounds();
assertLenghtOne(bounds);
assertEquals(Number.class, bounds[0]);
+ assertEquals("T", typeVariable.toString());
+ assertEquals("T", typeVariable.getTypeName());
}
static class H {}
@@ -146,5 +171,7 @@ public void testMultipleBound() throws Exception {
assertEquals(2, bounds.length);
assertEquals(Number.class, bounds[0]);
assertEquals(Serializable.class, bounds[1]);
+ assertEquals("T", typeVariable.toString());
+ assertEquals("T", typeVariable.getTypeName());
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/reflect/WildcardTypeTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/reflect/WildcardTypeTest.java
index e29fd474c..9d3a8b0db 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/reflect/WildcardTypeTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/reflect/WildcardTypeTest.java
@@ -76,6 +76,8 @@ private void checkLowerBoundedParameter(Method method) {
assertInstanceOf(WildcardType.class, actualTypeArguments[0]);
WildcardType wildcardType = (WildcardType) actualTypeArguments[0];
+ assertEquals("? super T", wildcardType.toString());
+ assertEquals("? super T", wildcardType.getTypeName());
Type[] lowerBounds = wildcardType.getLowerBounds();
assertLenghtOne(lowerBounds);
@@ -97,6 +99,8 @@ private void checkUpperBoundedParameter(Method method) {
assertInstanceOf(WildcardType.class, actualTypeArguments[0]);
WildcardType wildcardType = (WildcardType) actualTypeArguments[0];
+ assertEquals("? extends T", wildcardType.toString());
+ assertEquals("? extends T", wildcardType.getTypeName());
assertLenghtZero(wildcardType.getLowerBounds());
Type[] upperBounds = wildcardType.getUpperBounds();
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/math/BigDecimalTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/math/BigDecimalTest.java
index 20e9237f5..41ef93ece 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/math/BigDecimalTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/math/BigDecimalTest.java
@@ -912,7 +912,7 @@ public void test_stripTrailingZero() {
((notrailingzerotest.stripTrailingZeros()).scale() == 0)
);
- // BEGIN android-changed: preserve RI compatibility, so BigDecimal.equals (which checks
+ // BEGIN Android-changed: preserve RI compatibility, so BigDecimal.equals (which checks
// value *and* scale) continues to work. https://issues.apache.org/jira/browse/HARMONY-4623
/* Zero */
BigDecimal zerotest = new BigDecimal("0.0000");
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/math/OldBigIntegerTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/math/OldBigIntegerTest.java
index 7d1f1b4f3..0b866aed9 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/math/OldBigIntegerTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/math/OldBigIntegerTest.java
@@ -230,7 +230,7 @@ public void test_probablePrime() {
}
}
-// BEGIN android-added
+// BEGIN Android-added
// public void testModPowPerformance() {
// Random rnd = new Random();
// for (int i = 0; i < 10; i++) {
@@ -283,7 +283,7 @@ public void test_probablePrime() {
// }
// }
// }
-// END android-added
+// END Android-added
@@ -342,7 +342,7 @@ public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
- throw new AssertionError(e); // android-changed
+ throw new AssertionError(e); // Android-changed
}
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/CookiePolicyTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/CookiePolicyTest.java
index 61eff1e63..1e3879880 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/CookiePolicyTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/CookiePolicyTest.java
@@ -33,29 +33,10 @@ public class CookiePolicyTest extends TestCase {
public void test_ShouldAccept_LURI_LHttpCookie() throws URISyntaxException {
HttpCookie cookie = new HttpCookie("Harmony_6", "ongoing");
URI uri = new URI("");
- try {
- CookiePolicy.ACCEPT_ORIGINAL_SERVER.shouldAccept(null, cookie);
- fail("Should throw NullPointerException");
- } catch (NullPointerException e) {
- // expected
- }
-
- try {
- CookiePolicy.ACCEPT_ORIGINAL_SERVER.shouldAccept(uri, null);
- fail("Should throw NullPointerException");
- } catch (NullPointerException e) {
- // expected
- }
-
- try {
- CookiePolicy.ACCEPT_ORIGINAL_SERVER.shouldAccept(null, null);
- fail("Should throw NullPointerException");
- } catch (NullPointerException e) {
- // expected
- }
+ boolean accept;
// Policy: ACCEPT_ALL, always returns true
- boolean accept = CookiePolicy.ACCEPT_ALL.shouldAccept(null, cookie);
+ accept = CookiePolicy.ACCEPT_ALL.shouldAccept(null, cookie);
assertTrue(accept);
accept = CookiePolicy.ACCEPT_ALL.shouldAccept(null, null);
@@ -107,6 +88,15 @@ public void test_ShouldAccept_LURI_LHttpCookie() throws URISyntaxException {
accept = CookiePolicy.ACCEPT_ORIGINAL_SERVER.shouldAccept(new URI(
"s://a.b.c.d"), cookie);
assertFalse(accept);
+
+ accept = CookiePolicy.ACCEPT_ORIGINAL_SERVER.shouldAccept(null, cookie);
+ assertFalse(accept);
+
+ accept = CookiePolicy.ACCEPT_ORIGINAL_SERVER.shouldAccept(uri, null);
+ assertFalse(accept);
+
+ accept = CookiePolicy.ACCEPT_ORIGINAL_SERVER.shouldAccept(null, null);
+ assertFalse(accept);
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketImplTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketImplTest.java
index e94a963d6..fb2d78b4f 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketImplTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketImplTest.java
@@ -25,8 +25,15 @@
import java.net.NetworkInterface;
import java.net.SocketAddress;
import java.net.SocketException;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
+
+public class DatagramSocketImplTest extends TestCaseWithRules {
+ @Rule
+ public TestRule guardRule = ResourceLeakageDetector.getRule();
-public class DatagramSocketImplTest extends junit.framework.TestCase {
/**
* java.net.DatagramSocketImpl#DatagramSocketImpl()
*/
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java
index 4998dc528..bb9e806ad 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java
@@ -31,10 +31,20 @@
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.channels.DatagramChannel;
+import libcore.io.Libcore;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
-public class DatagramSocketTest extends junit.framework.TestCase {
+import static android.system.OsConstants.IPPROTO_IP;
+import static android.system.OsConstants.IP_MULTICAST_ALL;
- static final class DatagramServer extends Thread {
+public class DatagramSocketTest extends TestCaseWithRules {
+ @Rule
+ public TestRule guardRule = ResourceLeakageDetector.getRule();
+
+ static final class DatagramServer extends Thread implements AutoCloseable {
volatile boolean running = true;
@@ -70,8 +80,6 @@ public void run() {
}
} catch (IOException e) {
fail();
- } finally {
- serverSocket.close();
}
}
@@ -79,16 +87,28 @@ public int getPort() {
return serverSocket.getLocalPort();
}
- public void stopServer() {
+ @Override
+ public void close() throws Exception {
running = false;
+ try {
+ join();
+ } finally {
+ serverSocket.close();
+ }
}
}
/**
* java.net.DatagramSocket#DatagramSocket()
*/
- public void test_Constructor() throws SocketException {
- new DatagramSocket();
+ public void test_Constructor() throws Exception {
+ try (DatagramSocket ds = new DatagramSocket()) {
+ // Datagram sockets bound to the wildcard INADDR_ANY address should by default only
+ // receive messages from groups they explicitly joined.
+ boolean multicastAllEnabled = Libcore.os.getsockoptInt(ds.getFileDescriptor$(),
+ IPPROTO_IP, IP_MULTICAST_ALL) == 1;
+ assertFalse(multicastAllEnabled);
+ }
}
/**
@@ -103,10 +123,11 @@ public void test_ConstructorI() throws SocketException {
* java.net.DatagramSocket#DatagramSocket(int, java.net.InetAddress)
*/
public void test_ConstructorILjava_net_InetAddress() throws IOException {
- DatagramSocket ds = new DatagramSocket(0, InetAddress.getLocalHost());
- assertTrue("Created socket with incorrect port", ds.getLocalPort() != 0);
- assertEquals("Created socket with incorrect address", InetAddress
- .getLocalHost(), ds.getLocalAddress());
+ try (DatagramSocket ds = new DatagramSocket(0, InetAddress.getLocalHost())) {
+ assertTrue("Created socket with incorrect port", ds.getLocalPort() != 0);
+ assertEquals("Created socket with incorrect address", InetAddress
+ .getLocalHost(), ds.getLocalAddress());
+ }
}
/**
@@ -126,18 +147,21 @@ public void test_close() throws UnknownHostException, SocketException {
}
public void test_connectLjava_net_InetAddressI() throws Exception {
- DatagramSocket ds = new DatagramSocket();
- InetAddress inetAddress = InetAddress.getLocalHost();
- ds.connect(inetAddress, 0);
- assertEquals("Incorrect InetAddress", inetAddress, ds.getInetAddress());
- assertEquals("Incorrect Port", 0, ds.getPort());
- ds.disconnect();
+ try (DatagramSocket ds = new DatagramSocket()) {
+ InetAddress inetAddress = InetAddress.getLocalHost();
+ ds.connect(inetAddress, 0);
+ assertEquals("Incorrect InetAddress", inetAddress, ds.getInetAddress());
+ assertEquals("Incorrect Port", 0, ds.getPort());
+ ds.disconnect();
+ }
- ds = new java.net.DatagramSocket();
- inetAddress = InetAddress.getByName("FE80:0000:0000:0000:020D:60FF:FE0F:A776%4");
- ds.connect(inetAddress, 0);
- assertEquals(inetAddress, ds.getInetAddress());
- ds.disconnect();
+ try (DatagramSocket ds = new DatagramSocket()) {
+ InetAddress inetAddress =
+ InetAddress.getByName("FE80:0000:0000:0000:020D:60FF:FE0F:A776%4");
+ ds.connect(inetAddress, 0);
+ assertEquals(inetAddress, ds.getInetAddress());
+ ds.disconnect();
+ }
}
public void testConnect_connectToSelf() throws Exception {
@@ -177,189 +201,182 @@ private static void assertPacketDataEquals(DatagramPacket p1, DatagramPacket p2)
}
public void testConnect_echoServer() throws Exception {
- final DatagramSocket ds = new DatagramSocket(0);
+ try (DatagramSocket ds = new DatagramSocket(0);
+ DatagramServer server = new DatagramServer(Inet6Address.LOOPBACK)) {
+ server.start();
- final DatagramServer server = new DatagramServer(Inet6Address.LOOPBACK);
- server.start();
+ ds.connect(Inet6Address.LOOPBACK, server.getPort());
- ds.connect(Inet6Address.LOOPBACK, server.getPort());
+ final byte[] sendBytes = { 'T', 'e', 's', 't', 0 };
+ final DatagramPacket send = new DatagramPacket(sendBytes, sendBytes.length);
+ final DatagramPacket receive = new DatagramPacket(new byte[20], 20);
- final byte[] sendBytes = { 'T', 'e', 's', 't', 0 };
- final DatagramPacket send = new DatagramPacket(sendBytes, sendBytes.length);
- final DatagramPacket receive = new DatagramPacket(new byte[20], 20);
+ ds.send(send);
+ ds.setSoTimeout(2000);
+ ds.receive(receive);
- ds.send(send);
- ds.setSoTimeout(2000);
- ds.receive(receive);
- ds.close();
-
- assertEquals(sendBytes.length, receive.getLength());
- assertPacketDataEquals(send, receive);
- assertEquals(Inet6Address.LOOPBACK, receive.getAddress());
-
- server.stopServer();
+ assertEquals(sendBytes.length, receive.getLength());
+ assertPacketDataEquals(send, receive);
+ assertEquals(Inet6Address.LOOPBACK, receive.getAddress());
+ }
}
// Validate that once connected we cannot send to another address.
public void testConnect_throwsOnAddressMismatch() throws Exception {
- final DatagramSocket ds = new DatagramSocket(0);
+ try (DatagramSocket ds = new DatagramSocket(0);
+ DatagramServer s1 = new DatagramServer(Inet6Address.LOOPBACK);
+ DatagramServer s2 = new DatagramServer(Inet6Address.LOOPBACK)) {
- DatagramServer s1 = new DatagramServer(Inet6Address.LOOPBACK);
- DatagramServer s2 = new DatagramServer(Inet6Address.LOOPBACK);
- try {
ds.connect(Inet6Address.LOOPBACK, s1.getPort());
- ds.send(new DatagramPacket(new byte[10], 10, Inet6Address.LOOPBACK, s2.getPort()));
- fail();
- } catch (IllegalArgumentException expected) {
- } finally {
- ds.close();
- s1.stopServer();
- s2.stopServer();
+ try {
+ ds.send(new DatagramPacket(new byte[10], 10, Inet6Address.LOOPBACK, s2.getPort()));
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
}
}
// Validate that we can connect, then disconnect, then connect then
// send/recv.
public void testConnect_connectDisconnectConnectThenSendRecv() throws Exception {
- final DatagramSocket ds = new DatagramSocket(0);
-
- final DatagramServer server = new DatagramServer(Inet6Address.LOOPBACK);
- final DatagramServer broken = new DatagramServer(Inet6Address.LOOPBACK, false);
- server.start();
- broken.start();
+ try (DatagramSocket ds = new DatagramSocket(0);
+ DatagramServer server = new DatagramServer(Inet6Address.LOOPBACK);
+ DatagramServer broken = new DatagramServer(Inet6Address.LOOPBACK, false)) {
+ server.start();
+ broken.start();
- final int serverPortNumber = server.getPort();
- ds.connect(Inet6Address.LOOPBACK, broken.getPort());
- ds.disconnect();
- ds.connect(Inet6Address.LOOPBACK, serverPortNumber);
-
- final byte[] sendBytes = { 'T', 'e', 's', 't', 0 };
- final DatagramPacket send = new DatagramPacket(sendBytes, sendBytes.length);
- final DatagramPacket receive = new DatagramPacket(new byte[20], 20);
- ds.send(send);
- ds.setSoTimeout(2000);
- ds.receive(receive);
- ds.close();
+ final int serverPortNumber = server.getPort();
+ ds.connect(Inet6Address.LOOPBACK, broken.getPort());
+ ds.disconnect();
+ ds.connect(Inet6Address.LOOPBACK, serverPortNumber);
- assertPacketDataEquals(send, receive);
- assertEquals(Inet6Address.LOOPBACK, receive.getAddress());
+ final byte[] sendBytes = { 'T', 'e', 's', 't', 0 };
+ final DatagramPacket send = new DatagramPacket(sendBytes, sendBytes.length);
+ final DatagramPacket receive = new DatagramPacket(new byte[20], 20);
+ ds.send(send);
+ ds.setSoTimeout(2000);
+ ds.receive(receive);
- server.stopServer();
- broken.stopServer();
+ assertPacketDataEquals(send, receive);
+ assertEquals(Inet6Address.LOOPBACK, receive.getAddress());
+ }
}
// Validate that we can connect/disconnect then send/recv to any address
public void testConnect_connectDisconnectThenSendRecv() throws Exception {
- final DatagramSocket ds = new DatagramSocket(0);
+ try (DatagramSocket ds = new DatagramSocket(0);
+ DatagramServer server = new DatagramServer(Inet6Address.LOOPBACK)) {
+ server.start();
- final DatagramServer server = new DatagramServer(Inet6Address.LOOPBACK);
- server.start();
+ final int serverPortNumber = server.getPort();
+ ds.connect(Inet6Address.LOOPBACK, serverPortNumber);
+ ds.disconnect();
- final int serverPortNumber = server.getPort();
- ds.connect(Inet6Address.LOOPBACK, serverPortNumber);
- ds.disconnect();
+ final byte[] sendBytes = { 'T', 'e', 's', 't', 0 };
+ final DatagramPacket send = new DatagramPacket(sendBytes, sendBytes.length,
+ Inet6Address.LOOPBACK, serverPortNumber);
+ final DatagramPacket receive = new DatagramPacket(new byte[20], 20);
+ ds.send(send);
+ ds.setSoTimeout(2000);
+ ds.receive(receive);
- final byte[] sendBytes = { 'T', 'e', 's', 't', 0 };
- final DatagramPacket send = new DatagramPacket(sendBytes, sendBytes.length,
- Inet6Address.LOOPBACK, serverPortNumber);
- final DatagramPacket receive = new DatagramPacket(new byte[20], 20);
- ds.send(send);
- ds.setSoTimeout(2000);
- ds.receive(receive);
- ds.close();
-
- assertPacketDataEquals(send, receive);
- assertEquals(Inet6Address.LOOPBACK, receive.getAddress());
-
- server.stopServer();
+ assertPacketDataEquals(send, receive);
+ assertEquals(Inet6Address.LOOPBACK, receive.getAddress());
+ }
}
public void testConnect_connectTwice() throws Exception {
- final DatagramSocket ds = new DatagramSocket(0);
+ try (DatagramSocket ds = new DatagramSocket(0);
+ DatagramServer server = new DatagramServer(Inet6Address.LOOPBACK);
+ DatagramServer broken = new DatagramServer(Inet6Address.LOOPBACK)) {
+ server.start();
+ broken.start();
- final DatagramServer server = new DatagramServer(Inet6Address.LOOPBACK);
- final DatagramServer broken = new DatagramServer(Inet6Address.LOOPBACK);
- server.start();
- broken.start();
+ final int serverPortNumber = server.getPort();
+ ds.connect(Inet6Address.LOOPBACK, broken.getPort());
+ ds.connect(Inet6Address.LOOPBACK, serverPortNumber);
+ ds.disconnect();
- final int serverPortNumber = server.getPort();
- ds.connect(Inet6Address.LOOPBACK, broken.getPort());
- ds.connect(Inet6Address.LOOPBACK, serverPortNumber);
- ds.disconnect();
+ final byte[] sendBytes = { 'T', 'e', 's', 't', 0 };
+ final DatagramPacket send = new DatagramPacket(sendBytes, sendBytes.length,
+ Inet6Address.LOOPBACK, serverPortNumber);
+ final DatagramPacket receive = new DatagramPacket(new byte[20], 20);
+ ds.send(send);
+ ds.setSoTimeout(2000);
+ ds.receive(receive);
- final byte[] sendBytes = { 'T', 'e', 's', 't', 0 };
- final DatagramPacket send = new DatagramPacket(sendBytes, sendBytes.length,
- Inet6Address.LOOPBACK, serverPortNumber);
- final DatagramPacket receive = new DatagramPacket(new byte[20], 20);
- ds.send(send);
- ds.setSoTimeout(2000);
- ds.receive(receive);
- ds.close();
-
- assertPacketDataEquals(send, receive);
- assertEquals(Inet6Address.LOOPBACK, receive.getAddress());
-
- server.stopServer();
- broken.stopServer();
+ assertPacketDataEquals(send, receive);
+ assertEquals(Inet6Address.LOOPBACK, receive.getAddress());
+ }
}
public void testConnect_zeroAddress() throws Exception {
- DatagramSocket ds = new DatagramSocket();
- byte[] addressBytes = { 0, 0, 0, 0 };
- InetAddress inetAddress = InetAddress.getByAddress(addressBytes);
- ds.connect(inetAddress, 0);
+ try (DatagramSocket ds = new DatagramSocket()) {
+ byte[] addressBytes = { 0, 0, 0, 0 };
+ InetAddress inetAddress = InetAddress.getByAddress(addressBytes);
+ ds.connect(inetAddress, 0);
+ }
- ds = new java.net.DatagramSocket();
- byte[] addressTestBytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0 };
- inetAddress = InetAddress.getByAddress(addressTestBytes);
- ds.connect(inetAddress, 0);
+ try (DatagramSocket ds = new DatagramSocket()) {
+ byte[] addressTestBytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0 };
+ InetAddress inetAddress = InetAddress.getByAddress(addressTestBytes);
+ ds.connect(inetAddress, 0);
+ }
}
public void test_disconnect() throws Exception {
- DatagramSocket ds = new DatagramSocket();
- InetAddress inetAddress = InetAddress.getLocalHost();
- ds.connect(inetAddress, 0);
- ds.disconnect();
- assertNull("Incorrect InetAddress", ds.getInetAddress());
- assertEquals("Incorrect Port", -1, ds.getPort());
+ try (DatagramSocket ds = new DatagramSocket()) {
+ InetAddress inetAddress = InetAddress.getLocalHost();
+ ds.connect(inetAddress, 0);
+ ds.disconnect();
+ assertNull("Incorrect InetAddress", ds.getInetAddress());
+ assertEquals("Incorrect Port", -1, ds.getPort());
+ }
- ds = new DatagramSocket();
- inetAddress = InetAddress.getByName("FE80:0000:0000:0000:020D:60FF:FE0F:A776%4");
- ds.connect(inetAddress, 0);
- ds.disconnect();
- assertNull("Incorrect InetAddress", ds.getInetAddress());
- assertEquals("Incorrect Port", -1, ds.getPort());
+ try (DatagramSocket ds = new DatagramSocket()) {
+ InetAddress inetAddress =
+ InetAddress.getByName("FE80:0000:0000:0000:020D:60FF:FE0F:A776%4");
+ ds.connect(inetAddress, 0);
+ ds.disconnect();
+ assertNull("Incorrect InetAddress", ds.getInetAddress());
+ assertEquals("Incorrect Port", -1, ds.getPort());
+ }
}
public void test_getLocalAddress() throws Exception {
// Test for method java.net.InetAddress
// java.net.DatagramSocket.getLocalAddress()
InetAddress local = InetAddress.getLocalHost();
- DatagramSocket ds = new java.net.DatagramSocket(0, local);
- assertEquals(InetAddress.getByName(InetAddress.getLocalHost().getHostName()), ds.getLocalAddress());
+ try (DatagramSocket ds = new DatagramSocket(0, local)) {
+ assertEquals(InetAddress.getByName(InetAddress.getLocalHost().getHostName()),
+ ds.getLocalAddress());
+ }
// now check behavior when the ANY address is returned
- DatagramSocket s = new DatagramSocket(0);
- assertTrue("ANY address not IPv6: " + s.getLocalSocketAddress(), s.getLocalAddress() instanceof Inet6Address);
- s.close();
+ try (DatagramSocket s = new DatagramSocket(0)) {
+ assertTrue("ANY address not IPv6: " + s.getLocalSocketAddress(),
+ s.getLocalAddress() instanceof Inet6Address);
+ }
}
public void test_getLocalPort() throws SocketException {
- DatagramSocket ds = new DatagramSocket();
- assertTrue("Returned incorrect port", ds.getLocalPort() != 0);
+ try (DatagramSocket ds = new DatagramSocket()) {
+ assertTrue("Returned incorrect port", ds.getLocalPort() != 0);
+ }
}
public void test_getPort() throws IOException {
- DatagramSocket theSocket = new DatagramSocket();
- assertEquals("Expected -1 for remote port as not connected", -1,
- theSocket.getPort());
+ try (DatagramSocket theSocket = new DatagramSocket()) {
+ assertEquals("Expected -1 for remote port as not connected", -1,
+ theSocket.getPort());
- // Now connect the socket and validate that we get the right port
- int portNumber = 49152; // any valid port, even if it is unreachable
- theSocket.connect(InetAddress.getLocalHost(), portNumber);
- assertEquals("getPort returned wrong value", portNumber, theSocket
- .getPort());
+ // Now connect the socket and validate that we get the right port
+ int portNumber = 49152; // any valid port, even if it is unreachable
+ theSocket.connect(InetAddress.getLocalHost(), portNumber);
+ assertEquals("getPort returned wrong value", portNumber, theSocket
+ .getPort());
+ }
}
public void test_getReceiveBufferSize() throws Exception {
@@ -389,12 +406,15 @@ public void test_getSendBufferSize() throws Exception {
}
public void test_getSoTimeout() throws Exception {
- DatagramSocket ds = new DatagramSocket();
- final int timeoutSet = 100;
- ds.setSoTimeout(timeoutSet);
- int actualTimeout = ds.getSoTimeout();
- // The kernel can round the requested value based on the HZ setting. We allow up to 10ms.
- assertTrue("Returned incorrect timeout", Math.abs(actualTimeout - timeoutSet) <= 10);
+ try (DatagramSocket ds = new DatagramSocket()) {
+ final int timeoutSet = 100;
+ ds.setSoTimeout(timeoutSet);
+ int actualTimeout = ds.getSoTimeout();
+ // The kernel can round the requested value based on the HZ setting. We allow up to
+ // 10ms.
+ assertTrue("Returned incorrect timeout",
+ Math.abs(actualTimeout - timeoutSet) <= 10);
+ }
}
static final class TestDatagramSocketImpl extends DatagramSocketImpl {
@@ -593,23 +613,25 @@ public UnsupportedSocketAddress() {
}
}
- DatagramSocket ds = new DatagramSocket(new InetSocketAddress(
- InetAddress.getLocalHost(), 0));
- assertTrue(ds.getBroadcast());
- assertTrue("Created socket with incorrect port", ds.getLocalPort() != 0);
- assertEquals("Created socket with incorrect address", InetAddress
- .getLocalHost(), ds.getLocalAddress());
+ try (DatagramSocket ds = new DatagramSocket(
+ new InetSocketAddress(InetAddress.getLocalHost(), 0))) {
+ assertTrue(ds.getBroadcast());
+ assertTrue("Created socket with incorrect port", ds.getLocalPort() != 0);
+ assertEquals("Created socket with incorrect address", InetAddress
+ .getLocalHost(), ds.getLocalAddress());
+ }
try {
- ds = new java.net.DatagramSocket(new UnsupportedSocketAddress());
+ new DatagramSocket(new UnsupportedSocketAddress());
fail("No exception when constructing datagramSocket with unsupported SocketAddress type");
} catch (IllegalArgumentException e) {
// Expected
}
// regression for HARMONY-894
- ds = new DatagramSocket(null);
- assertTrue(ds.getBroadcast());
+ try (DatagramSocket ds = new DatagramSocket(null)) {
+ assertTrue(ds.getBroadcast());
+ }
}
@@ -677,50 +699,52 @@ public void test_isBound() throws Exception {
}
public void test_isConnected() throws Exception {
- DatagramServer ds = new DatagramServer(Inet6Address.LOOPBACK);
+ try (DatagramServer ds = new DatagramServer(Inet6Address.LOOPBACK)) {
- // base test
- DatagramSocket theSocket = new DatagramSocket(0);
- assertFalse(theSocket.isConnected());
- theSocket.connect(new InetSocketAddress(Inet6Address.LOOPBACK, ds.getPort()));
- assertTrue(theSocket.isConnected());
+ // base test
+ try (DatagramSocket theSocket = new DatagramSocket(0)) {
+ assertFalse(theSocket.isConnected());
+ theSocket.connect(new InetSocketAddress(Inet6Address.LOOPBACK, ds.getPort()));
+ assertTrue(theSocket.isConnected());
- // reconnect the socket and make sure we get the right answer
- theSocket.connect(new InetSocketAddress(Inet6Address.LOOPBACK, ds.getPort()));
- assertTrue(theSocket.isConnected());
+ // reconnect the socket and make sure we get the right answer
+ theSocket.connect(new InetSocketAddress(Inet6Address.LOOPBACK, ds.getPort()));
+ assertTrue(theSocket.isConnected());
- // now disconnect the socket and make sure we get the right answer
- theSocket.disconnect();
- assertFalse(theSocket.isConnected());
- theSocket.close();
+ // now disconnect the socket and make sure we get the right answer
+ theSocket.disconnect();
+ assertFalse(theSocket.isConnected());
+ }
- // now check behavior when socket is closed when connected
- theSocket = new DatagramSocket(0);
- theSocket.connect(new InetSocketAddress(Inet6Address.LOOPBACK, ds.getPort()));
- theSocket.close();
- assertTrue(theSocket.isConnected());
+ // now check behavior when socket is closed when connected
+ DatagramSocket theSocket = new DatagramSocket(0);
+ theSocket.connect(new InetSocketAddress(Inet6Address.LOOPBACK, ds.getPort()));
+ theSocket.close();
+ assertTrue(theSocket.isConnected());
+ }
}
public void test_getRemoteSocketAddress() throws Exception {
- DatagramServer server = new DatagramServer(Inet6Address.LOOPBACK);
- DatagramSocket s = new DatagramSocket(0);
- s.connect(new InetSocketAddress(Inet6Address.LOOPBACK, server.getPort()));
+ try (DatagramServer server = new DatagramServer(Inet6Address.LOOPBACK)) {
+ try (DatagramSocket s = new DatagramSocket(0)) {
+ s.connect(new InetSocketAddress(Inet6Address.LOOPBACK, server.getPort()));
- assertEquals(new InetSocketAddress(Inet6Address.LOOPBACK, server.getPort()),
- s.getRemoteSocketAddress());
- s.close();
+ assertEquals(new InetSocketAddress(Inet6Address.LOOPBACK, server.getPort()),
+ s.getRemoteSocketAddress());
+ }
- // now create one that is not connected and validate that we get the
- // right answer
- DatagramSocket theSocket = new DatagramSocket(null);
- theSocket.bind(new InetSocketAddress(InetAddress.getLocalHost(), 0));
- assertNull(theSocket.getRemoteSocketAddress());
+ // now create one that is not connected and validate that we get the
+ // right answer
+ try (DatagramSocket theSocket = new DatagramSocket(null)) {
+ theSocket.bind(new InetSocketAddress(InetAddress.getLocalHost(), 0));
+ assertNull(theSocket.getRemoteSocketAddress());
- // now connect and validate we get the right answer
- theSocket.connect(new InetSocketAddress(Inet6Address.LOOPBACK, server.getPort()));
- assertEquals(new InetSocketAddress(Inet6Address.LOOPBACK, server.getPort()),
- theSocket.getRemoteSocketAddress());
- theSocket.close();
+ // now connect and validate we get the right answer
+ theSocket.connect(new InetSocketAddress(Inet6Address.LOOPBACK, server.getPort()));
+ assertEquals(new InetSocketAddress(Inet6Address.LOOPBACK, server.getPort()),
+ theSocket.getRemoteSocketAddress());
+ }
+ }
}
public void test_getLocalSocketAddress_late_bind() throws Exception {
@@ -864,34 +888,36 @@ public void test_setBroadcastZ() throws Exception {
}
public void test_getBroadcast() throws Exception {
- DatagramSocket theSocket = new DatagramSocket();
- theSocket.setBroadcast(true);
- assertTrue("getBroadcast false when it should be true", theSocket.getBroadcast());
- theSocket.setBroadcast(false);
- assertFalse("getBroadcast true when it should be False", theSocket.getBroadcast());
+ try (DatagramSocket theSocket = new DatagramSocket()) {
+ theSocket.setBroadcast(true);
+ assertTrue("getBroadcast false when it should be true", theSocket.getBroadcast());
+ theSocket.setBroadcast(false);
+ assertFalse("getBroadcast true when it should be False", theSocket.getBroadcast());
+ }
}
public void test_setTrafficClassI() throws Exception {
int IPTOS_LOWCOST = 0x2;
int IPTOS_THROUGHPUT = 0x8;
- DatagramSocket theSocket = new DatagramSocket(0);
+ try (DatagramSocket theSocket = new DatagramSocket(0)) {
- // validate that value set must be between 0 and 255
- try {
- theSocket.setTrafficClass(256);
- fail("No exception when traffic class set to 256");
- } catch (IllegalArgumentException e) {
- }
+ // validate that value set must be between 0 and 255
+ try {
+ theSocket.setTrafficClass(256);
+ fail("No exception when traffic class set to 256");
+ } catch (IllegalArgumentException e) {
+ }
- try {
- theSocket.setTrafficClass(-1);
- fail("No exception when traffic class set to -1");
- } catch (IllegalArgumentException e) {
- }
+ try {
+ theSocket.setTrafficClass(-1);
+ fail("No exception when traffic class set to -1");
+ } catch (IllegalArgumentException e) {
+ }
- // now validate that we can set it to some good values
- theSocket.setTrafficClass(IPTOS_LOWCOST);
- theSocket.setTrafficClass(IPTOS_THROUGHPUT);
+ // now validate that we can set it to some good values
+ theSocket.setTrafficClass(IPTOS_LOWCOST);
+ theSocket.setTrafficClass(IPTOS_THROUGHPUT);
+ }
}
@@ -911,19 +937,20 @@ public void test_isClosed() throws Exception {
}
public void test_getChannel() throws Exception {
- assertNull(new DatagramSocket().getChannel());
+ try (DatagramSocket ds = new DatagramSocket()) {
+ assertNull(ds.getChannel());
+ }
- DatagramServer server = new DatagramServer(Inet6Address.LOOPBACK);
- DatagramSocket ds = new DatagramSocket(0);
- assertNull(ds.getChannel());
- ds.disconnect();
- ds.close();
- server.stopServer();
+ try (DatagramServer server = new DatagramServer(Inet6Address.LOOPBACK);
+ DatagramSocket ds = new DatagramSocket(0)) {
+ assertNull(ds.getChannel());
+ ds.disconnect();
+ }
- DatagramChannel channel = DatagramChannel.open();
- DatagramSocket socket = channel.socket();
- assertEquals(channel, socket.getChannel());
- socket.close();
+ try (DatagramChannel channel = DatagramChannel.open();
+ DatagramSocket socket = channel.socket()) {
+ assertEquals(channel, socket.getChannel());
+ }
}
public void testReceiveOversizePacket() throws Exception {
@@ -941,4 +968,28 @@ public void testReceiveOversizePacket() throws Exception {
ds.close();
assertEquals(new String("01234"), new String(recvBuffer, 0, recvBuffer.length, "UTF-8"));
}
+
+ // Receive twice reusing the same DatagramPacket.
+ // http://b/33957878
+ public void testReceiveTwice() throws Exception {
+ try (DatagramSocket ds = new DatagramSocket();
+ DatagramSocket sds = new DatagramSocket()) {
+ sds.connect(ds.getLocalSocketAddress());
+ DatagramPacket p = new DatagramPacket(new byte[16], 16);
+
+ byte[] smallPacketBytes = "01234".getBytes("UTF-8");
+ DatagramPacket smallPacket =
+ new DatagramPacket(smallPacketBytes, smallPacketBytes.length);
+ sds.send(smallPacket);
+ ds.receive(p);
+ assertPacketDataEquals(smallPacket, p);
+
+ byte[] largePacketBytes = "0123456789".getBytes("UTF-8");
+ DatagramPacket largerPacket =
+ new DatagramPacket(largePacketBytes, largePacketBytes.length);
+ sds.send(largerPacket);
+ ds.receive(p);
+ assertPacketDataEquals(largerPacket, p);
+ }
+ }
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/HttpCookieTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/HttpCookieTest.java
index e8d2ba94a..5fedfd787 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/HttpCookieTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/HttpCookieTest.java
@@ -5,9 +5,9 @@
* 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
@@ -164,6 +164,10 @@ public void test_DomainMatches() {
match = HttpCookie.domainMatches(null, "b.a.AJAX.com");
assertFalse(match);
+
+ // JDK-7023713
+ match = HttpCookie.domainMatches("hostname.local", "hostname");
+ assertTrue(match);
}
/**
@@ -781,12 +785,7 @@ public void test_Parse() {
list = HttpCookie
.parse("Set-Cookie:name=test;expires=Sun, 29-Feb-1999 19:14:07 GMT");
cookie = list.get(0);
- // A value of "0" means the cookie must be discarded immediately. 29-Feb-1999 is an
- // invalid date and fails to parse, so it must be discarded immediately.
- //
- // Android versions earlier than N returned a negative value here, which means the cookie
- // is valid for the current session.
- assertEquals(0, cookie.getMaxAge());
+ assertTrue(cookie.getMaxAge() < 0);
assertTrue(cookie.hasExpired());
// Parse multiple cookies
@@ -950,6 +949,19 @@ public void test_Parse_versionConflict() {
assertEquals(0, cookie.getVersion());
}
+ // http://b/31039416. Android N+ checks current time in hasExpired.
+ // Repeated invocations of cookie.hasExpired() may return different results
+ // due to time passage.
+ // This was not the case in earlier android versions, where hasExpired
+ // was testing the value of max-age/expires at the time of cookie creation.
+ public void test_hasExpired_checksTime() throws Exception {
+ List list = HttpCookie.parse("Set-Cookie:name=test;Max-Age=1");
+ HttpCookie cookie = list.get(0);
+ assertFalse(cookie.hasExpired());
+ Thread.sleep(2000);
+ assertTrue(cookie.hasExpired());
+ }
+
/**
* java.net.HttpCookie#parse(String) on multiple threads
* Regression test for HARMONY-6307
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/Inet6AddressTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/Inet6AddressTest.java
index 785a303d2..b32a96515 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/Inet6AddressTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/Inet6AddressTest.java
@@ -681,49 +681,6 @@ public void test_isIPv4CompatibleAddress() throws Exception {
.isIPv4CompatibleAddress());
}
- public void test_getByNameLjava_lang_String() throws Exception {
- // ones to add "::255.255.255.255", "::FFFF:0.0.0.0",
- // "0.0.0.0.0.0::255.255.255.255", "F:F:F:F:F:F:F:F",
- // "[F:F:F:F:F:F:F:F]"
- String validIPAddresses[] = { "::1.2.3.4", "::", "::", "1::0", "1::",
- "::1", "0", /* jdk1.5 accepts 0 as valid */
- "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF",
- "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:255.255.255.255",
- "0:0:0:0:0:0:0:0", "0:0:0:0:0:0:0.0.0.0" };
-
- String invalidIPAddresses[] = { "FFFF:FFFF" };
-
- for (int i = 0; i < validIPAddresses.length; i++) {
-
- InetAddress.getByName(validIPAddresses[i]);
-
- //exercise positive cache
- InetAddress.getByName(validIPAddresses[i]);
-
- if (!validIPAddresses[i].equals("0")) {
- String tempIPAddress = "[" + validIPAddresses[i] + "]";
- InetAddress.getByName(tempIPAddress);
- }
- }
-
- for (int i = 0; i < invalidIPAddresses.length; i++) {
- try {
- InetAddress.getByName(invalidIPAddresses[i]);
- fail("Invalid IP address incorrectly recognized as valid: "
- + invalidIPAddresses[i]);
- } catch (Exception e) {
- }
-
- //exercise negative cache
- try {
- InetAddress.getByName(invalidIPAddresses[i]);
- fail("Invalid IP address incorrectly recognized as valid: "
- + invalidIPAddresses[i]);
- } catch (Exception e) {
- }
- }
- }
-
public void test_getByAddressLString$BI() throws UnknownHostException {
try {
Inet6Address.getByAddress("123", null, 0);
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java
index 4e41c2a1a..7e232cc93 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java
@@ -111,23 +111,6 @@ public void test_getAllByNameLjava_lang_String() throws Exception {
}
}
- /**
- * java.net.InetAddress#getByName(java.lang.String)
- */
- public void test_getByNameLjava_lang_String() throws Exception {
- // Test for method java.net.InetAddress
- // java.net.InetAddress.getByName(java.lang.String)
- InetAddress ia2 = InetAddress.getByName("127.0.0.1");
-
- // TODO : Test to ensure all the address formats are recognized
- InetAddress i = InetAddress.getByName("1.2.3");
- assertEquals("1.2.0.3", i.getHostAddress());
- i = InetAddress.getByName("1.2");
- assertEquals("1.0.0.2", i.getHostAddress());
- i = InetAddress.getByName(String.valueOf(0xffffffffL));
- assertEquals("255.255.255.255", i.getHostAddress());
- }
-
/**
* java.net.InetAddress#getHostAddress()
*/
@@ -383,12 +366,11 @@ public void test_isReachableLjava_net_NetworkInterfaceII_loopbackInterface() thr
NetworkInterface loopbackInterface = null;
ArrayList localAddresses = new ArrayList();
- Enumeration networkInterfaces = NetworkInterface
- .getNetworkInterfaces();
+ Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces();
+ assertNotNull(networkInterfaces);
while (networkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = networkInterfaces.nextElement();
- Enumeration addresses = networkInterface
- .getInetAddresses();
+ Enumeration addresses = networkInterface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress address = addresses.nextElement();
if (address.isLoopbackAddress()) {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java
index 264e004e8..a24a67b87 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java
@@ -32,8 +32,14 @@
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
-public class MulticastSocketTest extends junit.framework.TestCase {
+public class MulticastSocketTest extends TestCaseWithRules {
+ @Rule
+ public TestRule guardRule = ResourceLeakageDetector.getRule();
private static InetAddress lookup(String s) {
try {
@@ -71,7 +77,7 @@ protected void setUp() throws Exception {
// Determine if the device is marked to support multicast or not. If this propery is not
// set we assume the device has an interface capable of supporting multicast.
- supportsMulticast = Boolean.valueOf(
+ supportsMulticast = Boolean.parseBoolean(
System.getProperty("android.cts.device.multicast", "true"));
if (!supportsMulticast) {
return;
@@ -573,32 +579,33 @@ private void test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
SocketAddress groupSockAddr = null;
SocketAddress groupSockAddr2 = null;
- MulticastSocket mss = new MulticastSocket(0);
- groupSockAddr = new InetSocketAddress(group, mss.getLocalPort());
- mss.joinGroup(groupSockAddr, null);
- mss.leaveGroup(groupSockAddr, null);
- try {
+ try (MulticastSocket mss = new MulticastSocket(0)) {
+ groupSockAddr = new InetSocketAddress(group, mss.getLocalPort());
+ mss.joinGroup(groupSockAddr, null);
mss.leaveGroup(groupSockAddr, null);
- fail("Did not get exception when trying to leave group that was already left");
- } catch (IOException expected) {
- }
+ try {
+ mss.leaveGroup(groupSockAddr, null);
+ fail("Did not get exception when trying to leave group that was already left");
+ } catch (IOException expected) {
+ }
- groupSockAddr2 = new InetSocketAddress(group2, mss.getLocalPort());
- mss.joinGroup(groupSockAddr, networkInterface);
- try {
- mss.leaveGroup(groupSockAddr2, networkInterface);
- fail("Did not get exception when trying to leave group that was never joined");
- } catch (IOException expected) {
- }
+ groupSockAddr2 = new InetSocketAddress(group2, mss.getLocalPort());
+ mss.joinGroup(groupSockAddr, networkInterface);
+ try {
+ mss.leaveGroup(groupSockAddr2, networkInterface);
+ fail("Did not get exception when trying to leave group that was never joined");
+ } catch (IOException expected) {
+ }
- mss.leaveGroup(groupSockAddr, networkInterface);
+ mss.leaveGroup(groupSockAddr, networkInterface);
- mss.joinGroup(groupSockAddr, networkInterface);
- try {
- mss.leaveGroup(groupSockAddr, loopbackInterface);
- fail("Did not get exception when trying to leave group on wrong interface " +
- "joined on [" + networkInterface + "] left on [" + loopbackInterface + "]");
- } catch (IOException expected) {
+ mss.joinGroup(groupSockAddr, networkInterface);
+ try {
+ mss.leaveGroup(groupSockAddr, loopbackInterface);
+ fail("Did not get exception when trying to leave group on wrong interface " +
+ "joined on [" + networkInterface + "] left on [" + loopbackInterface + "]");
+ } catch (IOException expected) {
+ }
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/ServerSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/ServerSocketTest.java
index 527946495..9d6c95023 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/ServerSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/ServerSocketTest.java
@@ -17,6 +17,12 @@
package org.apache.harmony.tests.java.net;
+import libcore.io.Libcore;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
+
import tests.support.Support_Configuration;
import java.io.IOException;
import java.io.InputStream;
@@ -38,7 +44,12 @@
import java.util.Locale;
import java.util.Properties;
-public class ServerSocketTest extends junit.framework.TestCase {
+import static android.system.OsConstants.F_GETFL;
+import static android.system.OsConstants.O_NONBLOCK;
+
+public class ServerSocketTest extends TestCaseWithRules {
+ @Rule
+ public TestRule guardRule = ResourceLeakageDetector.getRule();
boolean interrupted;
@@ -168,12 +179,16 @@ public void test_ConstructorIILjava_net_InetAddress()
/**
* java.net.ServerSocket#accept()
*/
- public void test_accept() throws IOException {
+ public void test_accept() throws Exception {
s = new ServerSocket(0);
try {
s.setSoTimeout(5000);
startClient(s.getLocalPort());
sconn = s.accept();
+
+ // The new socket should not be blocking.
+ assertEquals(0, Libcore.os.fcntlVoid(sconn.getFileDescriptor$(), F_GETFL) & O_NONBLOCK);
+
int localPort1 = s.getLocalPort();
int localPort2 = sconn.getLocalPort();
sconn.close();
@@ -691,19 +706,25 @@ public void test_defaultValueReuseAddress() throws Exception {
String platform = System.getProperty("os.name").toLowerCase(Locale.US);
if (!platform.startsWith("windows")) {
// on Unix
- assertTrue(new ServerSocket().getReuseAddress());
- assertTrue(new ServerSocket(0).getReuseAddress());
- assertTrue(new ServerSocket(0, 50).getReuseAddress());
- assertTrue(new ServerSocket(0, 50, InetAddress.getLocalHost()).getReuseAddress());
+ assertReuseAddressAndCloseSocket(new ServerSocket());
+ assertReuseAddressAndCloseSocket(new ServerSocket(0));
+ assertReuseAddressAndCloseSocket(new ServerSocket(0, 50));
+ assertReuseAddressAndCloseSocket(new ServerSocket(0, 50, InetAddress.getLocalHost()));
} else {
// on Windows
- assertFalse(new ServerSocket().getReuseAddress());
- assertFalse(new ServerSocket(0).getReuseAddress());
- assertFalse(new ServerSocket(0, 50).getReuseAddress());
- assertFalse(new ServerSocket(0, 50, InetAddress.getLocalHost()).getReuseAddress());
+ assertReuseAddressAndCloseSocket(new ServerSocket());
+ assertReuseAddressAndCloseSocket(new ServerSocket(0));
+ assertReuseAddressAndCloseSocket(new ServerSocket(0, 50));
+ assertReuseAddressAndCloseSocket(new ServerSocket(0, 50, InetAddress.getLocalHost()));
}
}
+ private void assertReuseAddressAndCloseSocket(ServerSocket socket) throws IOException {
+ boolean reuseAddress = socket.getReuseAddress();
+ socket.close();
+ assertTrue(reuseAddress);
+ }
+
public void test_setReuseAddressZ() throws Exception {
// set up server and connect
InetSocketAddress anyAddress = new InetSocketAddress(InetAddress.getLocalHost(), 0);
@@ -719,16 +740,15 @@ public void test_setReuseAddressZ() throws Exception {
serverSocket.close();
// now try to rebind the server which should fail with
- // setReuseAddress to false. On windows platforms the bind is
- // allowed even then reUseAddress is false so our test uses
- // the platform to determine what the expected result is.
- String platform = System.getProperty("os.name");
- try {
- serverSocket = new ServerSocket();
- serverSocket.setReuseAddress(false);
- serverSocket.bind(theAddress);
- fail("No exception when setReuseAddress is false and we bind:" + theAddress.toString());
- } catch (IOException expected) {
+ // setReuseAddress to false.
+ try (ServerSocket failingServerSocket = new ServerSocket()) {
+ failingServerSocket.setReuseAddress(false);
+ try {
+ failingServerSocket.bind(theAddress);
+ fail("No exception when setReuseAddress is false and we bind:" + theAddress
+ .toString());
+ } catch (IOException expected) {
+ }
}
stillActiveSocket.close();
theSocket.close();
@@ -748,13 +768,14 @@ public void test_setReuseAddressZ() throws Exception {
// now try to rebind the server which should pass with
// setReuseAddress to true
- try {
- serverSocket = new ServerSocket();
- serverSocket.setReuseAddress(true);
- serverSocket.bind(theAddress);
- } catch (IOException ex) {
- fail("Unexpected exception when setReuseAddress is true and we bind:"
- + theAddress.toString() + ":" + ex.toString());
+ try (ServerSocket rebindServerSocket = new ServerSocket()) {
+ rebindServerSocket.setReuseAddress(true);
+ try {
+ rebindServerSocket.bind(theAddress);
+ } catch (IOException ex) {
+ fail("Unexpected exception when setReuseAddress is true and we bind:"
+ + theAddress.toString() + ":" + ex.toString());
+ }
}
stillActiveSocket.close();
theSocket.close();
@@ -773,23 +794,26 @@ public void test_setReuseAddressZ() throws Exception {
serverSocket.close();
// now try to rebind the server which should pass
- try {
- serverSocket = new ServerSocket();
- serverSocket.bind(theAddress);
- } catch (IOException ex) {
- fail("Unexpected exception when setReuseAddress is the default case and we bind:"
- + theAddress.toString() + ":" + ex.toString());
+ try (ServerSocket rebindServerSocket = new ServerSocket()) {
+ try {
+ rebindServerSocket.bind(theAddress);
+ } catch (IOException ex) {
+ fail("Unexpected exception when setReuseAddress is the default case and we bind:"
+ + theAddress.toString() + ":" + ex.toString());
+ }
}
stillActiveSocket.close();
theSocket.close();
}
public void test_getReuseAddress() throws Exception {
- ServerSocket theSocket = new ServerSocket();
- theSocket.setReuseAddress(true);
- assertTrue("getReuseAddress false when it should be true", theSocket.getReuseAddress());
- theSocket.setReuseAddress(false);
- assertFalse("getReuseAddress true when it should be False", theSocket.getReuseAddress());
+ try (ServerSocket theSocket = new ServerSocket()) {
+ theSocket.setReuseAddress(true);
+ assertTrue("getReuseAddress false when it should be true", theSocket.getReuseAddress());
+ theSocket.setReuseAddress(false);
+ assertFalse("getReuseAddress true when it should be false",
+ theSocket.getReuseAddress());
+ }
}
public void test_setReceiveBufferSizeI() throws Exception {
@@ -819,13 +843,15 @@ public void test_setReceiveBufferSizeI() throws Exception {
}
public void test_getReceiveBufferSize() throws Exception {
- ServerSocket theSocket = new ServerSocket();
+ try (ServerSocket theSocket = new ServerSocket()) {
- // since the value returned is not necessary what we set we are
- // limited in what we can test
- // just validate that it is not 0 or negative
- assertFalse("get Buffer size returns 0:", 0 == theSocket.getReceiveBufferSize());
- assertFalse("get Buffer size returns a negative value:", 0 > theSocket.getReceiveBufferSize());
+ // since the value returned is not necessary what we set we are
+ // limited in what we can test
+ // just validate that it is not 0 or negative
+ assertFalse("get Buffer size returns 0:", 0 == theSocket.getReceiveBufferSize());
+ assertFalse("get Buffer size returns a negative value:",
+ 0 > theSocket.getReceiveBufferSize());
+ }
}
public void test_getChannel() throws Exception {
@@ -880,11 +906,13 @@ protected void startClient(int port) {
*/
public void test_implAcceptLjava_net_Socket() throws Exception {
// regression test for Harmony-1235
- try {
- new MockServerSocket().mockImplAccept(new MockSocket(
- new MockSocketImpl()));
- } catch (SocketException e) {
- // expected
+ try (MockServerSocket mockServerSocket = new MockServerSocket()) {
+ try {
+ mockServerSocket.mockImplAccept(new MockSocket(new MockSocketImpl()));
+ fail("Expected SocketException");
+ } catch (SocketException e) {
+ // expected
+ }
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/SocketImplTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/SocketImplTest.java
index f6122e5ac..b64a2cedd 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/SocketImplTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/SocketImplTest.java
@@ -25,8 +25,14 @@
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketImpl;
-
-public class SocketImplTest extends junit.framework.TestCase {
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
+
+public class SocketImplTest extends TestCaseWithRules {
+ @Rule
+ public TestRule guardRule = ResourceLeakageDetector.getRule();
/**
* java.net.SocketImpl#SocketImpl()
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/SocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/SocketTest.java
index 0915a2763..68122b289 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/SocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/SocketTest.java
@@ -21,8 +21,6 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ConnectException;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
@@ -31,16 +29,20 @@
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketImpl;
-import java.net.SocketImplFactory;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
-import java.security.Permission;
import java.util.Arrays;
import java.util.Locale;
-
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
import tests.support.Support_Configuration;
-public class SocketTest extends junit.framework.TestCase {
+public class SocketTest extends TestCaseWithRules {
+ @Rule
+ public TestRule guardRule = ResourceLeakageDetector.getRule();
+
private class ClientThread implements Runnable {
public void run() {
@@ -509,12 +511,10 @@ public void test_Constructor() {
* java.net.Socket#Socket(java.lang.String, int)
*/
public void test_ConstructorLjava_lang_StringI() throws IOException {
- ServerSocket server = new ServerSocket(0);
- Socket client = new Socket(InetAddress.getLocalHost(), server
- .getLocalPort());
-
- assertEquals("Failed to create socket", server.getLocalPort(), client
- .getPort());
+ try (ServerSocket server = new ServerSocket(0);
+ Socket client = new Socket(InetAddress.getLocalHost(), server.getLocalPort())) {
+ assertEquals("Failed to create socket", server.getLocalPort(), client.getPort());
+ }
// Regression for HARMONY-946
ServerSocket ss = new ServerSocket(0);
@@ -601,10 +601,11 @@ public void test_ConstructorLjava_net_InetAddressI() throws IOException {
*/
public void test_ConstructorLjava_net_InetAddressILjava_net_InetAddressI()
throws IOException {
- ServerSocket server = new ServerSocket(0);
- Socket client = new Socket(InetAddress.getLocalHost(), server
- .getLocalPort(), InetAddress.getLocalHost(), 0);
- assertNotSame("Failed to create socket", 0, client.getLocalPort());
+ try (ServerSocket server = new ServerSocket(0);
+ Socket client = new Socket(InetAddress.getLocalHost(), server.getLocalPort(),
+ InetAddress.getLocalHost(), 0)) {
+ assertNotSame("Failed to create socket", 0, client.getLocalPort());
+ }
}
/**
@@ -612,14 +613,17 @@ public void test_ConstructorLjava_net_InetAddressILjava_net_InetAddressI()
*/
@SuppressWarnings("deprecation")
public void test_ConstructorLjava_net_InetAddressIZ() throws IOException {
- ServerSocket server = new ServerSocket(0);
- int serverPort = server.getLocalPort();
+ try (ServerSocket server = new ServerSocket(0)) {
+ int serverPort = server.getLocalPort();
- Socket client = new Socket(InetAddress.getLocalHost(), serverPort, true);
- assertEquals("Failed to create socket", serverPort, client.getPort());
+ try (Socket client = new Socket(InetAddress.getLocalHost(), serverPort, true)) {
+ assertEquals("Failed to create socket", serverPort, client.getPort());
+ }
- client = new Socket(InetAddress.getLocalHost(), serverPort, false);
- client.close();
+ try (Socket client = new Socket(InetAddress.getLocalHost(), serverPort, false)) {
+ assertEquals("Failed to create socket", serverPort, client.getPort());
+ }
+ }
}
/**
@@ -694,43 +698,40 @@ private boolean isUnix() {
}
public void test_getKeepAlive() throws Exception {
- ServerSocket server = new ServerSocket(0);
- Socket client = new Socket(InetAddress.getLocalHost(), server.getLocalPort(), null, 0);
+ try (ServerSocket server = new ServerSocket(0);
+ Socket client = new Socket(InetAddress.getLocalHost(),
+ server.getLocalPort(), null, 0)) {
- client.setKeepAlive(true);
- assertTrue("getKeepAlive false when it should be true", client.getKeepAlive());
+ client.setKeepAlive(true);
+ assertTrue("getKeepAlive false when it should be true", client.getKeepAlive());
- client.setKeepAlive(false);
- assertFalse("getKeepAlive true when it should be False", client.getKeepAlive());
+ client.setKeepAlive(false);
+ assertFalse("getKeepAlive true when it should be False", client.getKeepAlive());
+ }
}
public void test_getLocalAddress() throws IOException {
- ServerSocket server = new ServerSocket(0);
- Socket client = new Socket(InetAddress.getLocalHost(), server.getLocalPort());
-
- assertTrue("Returned incorrect InetAddress", client.getLocalAddress()
- .equals(InetAddress.getLocalHost()));
-
- client = new Socket();
- client.bind(new InetSocketAddress(InetAddress.getByName("0.0.0.0"), 0));
- assertTrue(client.getLocalAddress().isAnyLocalAddress());
+ try (ServerSocket server = new ServerSocket(0)) {
+ try (Socket client = new Socket(InetAddress.getLocalHost(), server.getLocalPort())) {
+ assertTrue("Returned incorrect InetAddress", client.getLocalAddress()
+ .equals(InetAddress.getLocalHost()));
+ }
- client.close();
- server.close();
+ try (Socket client = new Socket()) {
+ client.bind(new InetSocketAddress(InetAddress.getByName("0.0.0.0"), 0));
+ assertTrue(client.getLocalAddress().isAnyLocalAddress());
+ }
+ }
}
/**
* java.net.Socket#getLocalPort()
*/
public void test_getLocalPort() throws IOException {
- ServerSocket server = new ServerSocket(0);
- Socket client = new Socket(InetAddress.getLocalHost(), server
- .getLocalPort());
-
- assertNotSame("Returned incorrect port", 0, client.getLocalPort());
-
- client.close();
- server.close();
+ try (ServerSocket server = new ServerSocket(0);
+ Socket client = new Socket(InetAddress.getLocalHost(), server.getLocalPort())) {
+ assertNotSame("Returned incorrect port", 0, client.getLocalPort());
+ }
}
public void test_getLocalSocketAddress() throws IOException {
@@ -776,16 +777,16 @@ public void test_getLocalSocketAddress() throws IOException {
}
public void test_getOOBInline() throws Exception {
- Socket theSocket = new Socket();
-
- theSocket.setOOBInline(true);
- assertTrue("expected OOBIline to be true", theSocket.getOOBInline());
+ try (Socket theSocket = new Socket()) {
+ theSocket.setOOBInline(true);
+ assertTrue("expected OOBIline to be true", theSocket.getOOBInline());
- theSocket.setOOBInline(false);
- assertFalse("expected OOBIline to be false", theSocket.getOOBInline());
+ theSocket.setOOBInline(false);
+ assertFalse("expected OOBIline to be false", theSocket.getOOBInline());
- theSocket.setOOBInline(false);
- assertFalse("expected OOBIline to be false", theSocket.getOOBInline());
+ theSocket.setOOBInline(false);
+ assertFalse("expected OOBIline to be false", theSocket.getOOBInline());
+ }
}
/**
@@ -870,15 +871,16 @@ public void run() {
sinkServer.close();
// Regression test for HARMONY-873
- ServerSocket ss2 = new ServerSocket(0);
- Socket s = new Socket("127.0.0.1", ss2.getLocalPort());
- ss2.accept();
- s.shutdownOutput();
- try {
- s.getOutputStream();
- fail("should throw SocketException");
- } catch (SocketException e) {
- // expected
+ try (ServerSocket ss2 = new ServerSocket(0);
+ Socket s = new Socket("127.0.0.1", ss2.getLocalPort())) {
+ ss2.accept();
+ s.shutdownOutput();
+ try {
+ s.getOutputStream();
+ fail("should throw SocketException");
+ } catch (SocketException e) {
+ // expected
+ }
}
}
@@ -938,54 +940,52 @@ public void test_getRemoteSocketAddress() throws IOException {
}
public void test_getReuseAddress() throws Exception {
- Socket theSocket = new Socket();
- theSocket.setReuseAddress(true);
- assertTrue("getReuseAddress false when it should be true", theSocket.getReuseAddress());
- theSocket.setReuseAddress(false);
- assertFalse("getReuseAddress true when it should be False", theSocket.getReuseAddress());
+ try (Socket theSocket = new Socket()) {
+ theSocket.setReuseAddress(true);
+ assertTrue("getReuseAddress false when it should be true", theSocket.getReuseAddress());
+ theSocket.setReuseAddress(false);
+ assertFalse("getReuseAddress true when it should be False",
+ theSocket.getReuseAddress());
+ }
}
public void test_getSendBufferSize() throws Exception {
- ServerSocket server = new ServerSocket(0);
- Socket client = new Socket(InetAddress.getLocalHost(), server.getLocalPort());
- client.setSendBufferSize(134);
- assertTrue("Incorrect buffer size", client.getSendBufferSize() >= 134);
- client.close();
- server.close();
+ try (ServerSocket server = new ServerSocket(0);
+ Socket client = new Socket(InetAddress.getLocalHost(), server.getLocalPort())) {
+ client.setSendBufferSize(134);
+ assertTrue("Incorrect buffer size", client.getSendBufferSize() >= 134);
+ }
}
public void test_getSoLinger() throws Exception {
- ServerSocket server = new ServerSocket(0);
- Socket client = new Socket(InetAddress.getLocalHost(), server.getLocalPort());
- client.setSoLinger(true, 200);
- assertEquals("Returned incorrect linger", 200, client.getSoLinger());
- client.setSoLinger(false, 0);
- client.close();
- server.close();
+ try (ServerSocket server = new ServerSocket(0);
+ Socket client = new Socket(InetAddress.getLocalHost(), server.getLocalPort())) {
+ client.setSoLinger(true, 200);
+ assertEquals("Returned incorrect linger", 200, client.getSoLinger());
+ client.setSoLinger(false, 0);
+ }
}
public void test_getSoTimeout() throws Exception {
- ServerSocket server = new ServerSocket(0);
- Socket client = new Socket(InetAddress.getLocalHost(), server.getLocalPort());
- final int timeoutSet = 100;
- client.setSoTimeout(timeoutSet);
- int actualTimeout = client.getSoTimeout();
- // The kernel can round the requested value based on the HZ setting. We allow up to 10ms.
- assertTrue("Returned incorrect sotimeout", Math.abs(timeoutSet - actualTimeout) <= 10);
- client.close();
- server.close();
+ try (ServerSocket server = new ServerSocket(0);
+ Socket client = new Socket(InetAddress.getLocalHost(), server.getLocalPort())) {
+ final int timeoutSet = 100;
+ client.setSoTimeout(timeoutSet);
+ int actualTimeout = client.getSoTimeout();
+ // The kernel can round the requested value based on the HZ setting. We allow up to 10ms.
+ assertTrue("Returned incorrect sotimeout",
+ Math.abs(timeoutSet - actualTimeout) <= 10);
+ }
}
public void test_getTcpNoDelay() throws Exception {
- ServerSocket server = new ServerSocket(0);
- Socket client = new Socket(InetAddress.getLocalHost(), server.getLocalPort());
-
- boolean bool = !client.getTcpNoDelay();
- client.setTcpNoDelay(bool);
- assertTrue("Failed to get no delay setting: " + client.getTcpNoDelay(), client.getTcpNoDelay() == bool);
-
- client.close();
- server.close();
+ try (ServerSocket server = new ServerSocket(0);
+ Socket client = new Socket(InetAddress.getLocalHost(), server.getLocalPort())) {
+ boolean bool = !client.getTcpNoDelay();
+ client.setTcpNoDelay(bool);
+ assertTrue("Failed to get no delay setting: " + client.getTcpNoDelay(),
+ client.getTcpNoDelay() == bool);
+ }
}
public void test_getTrafficClass() throws Exception {
@@ -994,9 +994,11 @@ public void test_getTrafficClass() throws Exception {
* does not support the option then it may come back unset even
* though we set it so just get the value to make sure we can get it
*/
- int trafficClass = new Socket().getTrafficClass();
- assertTrue(0 <= trafficClass);
- assertTrue(trafficClass <= 255);
+ try (Socket socket = new Socket()) {
+ int trafficClass = socket.getTrafficClass();
+ assertTrue(0 <= trafficClass);
+ assertTrue(trafficClass <= 255);
+ }
}
/**
@@ -1422,18 +1424,22 @@ public TestSocket(SocketImpl impl) throws SocketException {
server.close();
// Regression test for HARMONY-1136
- new TestSocket(null).setKeepAlive(true);
+ try (TestSocket socket = new TestSocket(null)) {
+ socket.setKeepAlive(true);
+ }
}
public void test_setOOBInlineZ() throws Exception {
- Socket theSocket = new Socket();
- theSocket.setOOBInline(true);
- assertTrue("expected OOBIline to be true", theSocket.getOOBInline());
+ try (Socket theSocket = new Socket()) {
+ theSocket.setOOBInline(true);
+ assertTrue("expected OOBIline to be true", theSocket.getOOBInline());
+ }
}
public void test_setPerformancePreference_Int_Int_Int() throws IOException {
- Socket theSocket = new Socket();
- theSocket.setPerformancePreferences(1, 1, 1);
+ try (Socket theSocket = new Socket()) {
+ theSocket.setPerformancePreferences(1, 1, 1);
+ }
}
public void test_setReceiveBufferSizeI() throws Exception {
@@ -1522,26 +1528,27 @@ public void test_setTrafficClassI() throws Exception {
int IPTOS_THROUGHPUT = 0x8;
int IPTOS_LOWDELAY = 0x10;
- Socket theSocket = new Socket();
+ try (Socket theSocket = new Socket()) {
- // validate that value set must be between 0 and 255
- try {
- theSocket.setTrafficClass(256);
- fail("No exception was thrown when traffic class set to 256");
- } catch (IllegalArgumentException expected) {
- }
+ // validate that value set must be between 0 and 255
+ try {
+ theSocket.setTrafficClass(256);
+ fail("No exception was thrown when traffic class set to 256");
+ } catch (IllegalArgumentException expected) {
+ }
- try {
- theSocket.setTrafficClass(-1);
- fail("No exception was thrown when traffic class set to -1");
- } catch (IllegalArgumentException expected) {
- }
+ try {
+ theSocket.setTrafficClass(-1);
+ fail("No exception was thrown when traffic class set to -1");
+ } catch (IllegalArgumentException expected) {
+ }
- // now validate that we can set it to some good values
- theSocket.setTrafficClass(IPTOS_LOWCOST);
- theSocket.setTrafficClass(IPTOS_RELIABILTY);
- theSocket.setTrafficClass(IPTOS_THROUGHPUT);
- theSocket.setTrafficClass(IPTOS_LOWDELAY);
+ // now validate that we can set it to some good values
+ theSocket.setTrafficClass(IPTOS_LOWCOST);
+ theSocket.setTrafficClass(IPTOS_RELIABILTY);
+ theSocket.setTrafficClass(IPTOS_THROUGHPUT);
+ theSocket.setTrafficClass(IPTOS_LOWDELAY);
+ }
}
@SuppressWarnings("deprecation")
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ByteBufferTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ByteBufferTest.java
index b25c4dec4..db09af8cc 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ByteBufferTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ByteBufferTest.java
@@ -17,6 +17,7 @@
package org.apache.harmony.tests.java.nio;
+import java.io.RandomAccessFile;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
@@ -29,6 +30,9 @@
import java.nio.LongBuffer;
import java.nio.ReadOnlyBufferException;
import java.nio.ShortBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Arrays;
/**
@@ -2033,6 +2037,28 @@ public void testWrappedByteBuffer_null_array() {
}
}
+ // http://b/34045479
+ public void testMappedByteBuffer_Put_ReadOnlyHeapByteBuffer() throws Exception {
+ // Create a temp file
+ byte[] data = new byte[] {1, 2, 3, 4};
+ Path tempFile = Files.createTempFile("mmap", "test");
+ Files.write(tempFile, data);
+
+ // Create a read-only heap buffer
+ ByteBuffer readOnlySource = ByteBuffer.allocate(4).asReadOnlyBuffer();
+ try (RandomAccessFile tempRAF = new RandomAccessFile(tempFile.toFile(), "rw")) {
+ FileChannel tempFileChannel = tempRAF.getChannel();
+ ByteBuffer mappedByteBuffer =
+ tempFileChannel.map(FileChannel.MapMode.READ_WRITE, 0, tempFileChannel.size());
+
+ // Try to put a non-empty, read-only heap byte buffer into a mapped byte buffer.
+ mappedByteBuffer.put(readOnlySource);
+ tempFileChannel.close();
+ } finally {
+ Files.delete(tempFile);
+ }
+ }
+
private void loadTestData1(byte array[], int offset, int length) {
for (int i = 0; i < length; i++) {
array[offset + i] = (byte) i;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyCharBufferTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyCharBufferTest.java
index 8ff795699..e567504db 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyCharBufferTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyCharBufferTest.java
@@ -140,8 +140,8 @@ public void testPutCharBuffer() {
}
try {
buf.put(buf);
- fail("Should throw ReadOnlyBufferException"); //$NON-NLS-1$
- } catch (ReadOnlyBufferException e) {
+ fail("Should throw IllegalArgumentException"); //$NON-NLS-1$
+ } catch (IllegalArgumentException e) {
// expected
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyDoubleBufferTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyDoubleBufferTest.java
index f2f1ea41d..1673c164a 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyDoubleBufferTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyDoubleBufferTest.java
@@ -137,8 +137,8 @@ public void testPutDoubleBuffer() {
}
try {
buf.put(buf);
- fail("Should throw ReadOnlyBufferException"); //$NON-NLS-1$
- } catch (ReadOnlyBufferException e) {
+ fail("Should throw IllegalArgumentException"); //$NON-NLS-1$
+ } catch (IllegalArgumentException e) {
// expected
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyFloatBufferTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyFloatBufferTest.java
index 56a14baba..3aec858d3 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyFloatBufferTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyFloatBufferTest.java
@@ -138,8 +138,8 @@ public void testPutFloatBuffer() {
}
try {
buf.put(buf);
- fail("Should throw ReadOnlyBufferException"); //$NON-NLS-1$
- } catch (ReadOnlyBufferException e) {
+ fail("Should throw IllegalArgumentException"); //$NON-NLS-1$
+ } catch (IllegalArgumentException e) {
// expected
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyIntBufferTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyIntBufferTest.java
index e6187835f..f0dcad01d 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyIntBufferTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyIntBufferTest.java
@@ -138,8 +138,8 @@ public void testPutIntBuffer() {
}
try {
buf.put(buf);
- fail("Should throw ReadOnlyBufferException"); //$NON-NLS-1$
- } catch (ReadOnlyBufferException e) {
+ fail("Should throw IllegalArgumentException"); //$NON-NLS-1$
+ } catch (IllegalArgumentException e) {
// expected
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyLongBufferTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyLongBufferTest.java
index fd6438eb2..283f4f11d 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyLongBufferTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyLongBufferTest.java
@@ -138,8 +138,8 @@ public void testPutLongBuffer() {
}
try {
buf.put(buf);
- fail("Should throw ReadOnlyBufferException"); //$NON-NLS-1$
- } catch (ReadOnlyBufferException e) {
+ fail("Should throw IllegalArgumentException"); //$NON-NLS-1$
+ } catch (IllegalArgumentException e) {
// expected
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyShortBufferTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyShortBufferTest.java
index aab913e92..88858060f 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyShortBufferTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/ReadOnlyShortBufferTest.java
@@ -138,8 +138,8 @@ public void testPutShortBuffer() {
}
try {
buf.put(buf);
- fail("Should throw ReadOnlyBufferException"); //$NON-NLS-1$
- } catch (ReadOnlyBufferException e) {
+ fail("Should throw IllegalArgumentException"); //$NON-NLS-1$
+ } catch (IllegalArgumentException e) {
// expected
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/ChannelsTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/ChannelsTest.java
index bd7a1ad59..274628a9d 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/ChannelsTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/ChannelsTest.java
@@ -507,6 +507,7 @@ public void testNewWriterWritableByteChannelString_internalBufZero()
// null channel
try {
Writer testWriter = Channels.newWriter(null, Charset.forName(CODE_SET).newEncoder(), -1);
+ fail();
} catch (NullPointerException expected) {
}
@@ -514,6 +515,7 @@ public void testNewWriterWritableByteChannelString_internalBufZero()
this.fouts = null;
try {
WritableByteChannel wbChannel = Channels.newChannel(this.fouts);
+ fail();
} catch (NullPointerException expected) {
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/FileChannelTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/FileChannelTest.java
index d6dacb40d..03c472cc4 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/FileChannelTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/FileChannelTest.java
@@ -1367,6 +1367,7 @@ public void test_readLByteBufferJ_Position_As_Long() throws Exception {
ByteBuffer readBuffer = ByteBuffer.allocate(CAPACITY);
try {
readOnlyFileChannel.read(readBuffer, Long.MAX_VALUE);
+ fail();
} catch (IOException expected) {
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/MockDatagramChannel.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/MockDatagramChannel.java
index 8b0f5b3ae..8978714bd 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/MockDatagramChannel.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/MockDatagramChannel.java
@@ -25,6 +25,7 @@
import java.net.SocketOption;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
+import java.nio.channels.MembershipKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.Set;
@@ -111,13 +112,23 @@ public T getOption(SocketOption name) throws IOException {
return null;
}
+ public DatagramChannel bind(SocketAddress local) throws IOException {
+ return null;
+ }
+
@Override
- public Set> supportedOptions() {
+ public MembershipKey join(InetAddress group, NetworkInterface interf) {
return null;
}
@Override
- public DatagramChannel bind(SocketAddress local) throws IOException {
+ public MembershipKey join(InetAddress group, NetworkInterface interf, InetAddress source)
+ throws IOException {
+ return null;
+ }
+
+ @Override
+ public Set> supportedOptions() {
return null;
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/charset/CharsetEncoderTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/charset/CharsetEncoderTest.java
index 5226ed688..c1c1e93a0 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/charset/CharsetEncoderTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/charset/CharsetEncoderTest.java
@@ -178,7 +178,7 @@ public void testCharsetEncoderCharsetfloatfloatbyteArray() {
assertSame(ec.charset(), cs);
assertEquals(1.0, ec.averageBytesPerChar(), 0.0);
assertTrue(ec.maxBytesPerChar() == MAX_BYTES);
- assertSame(ba, ec.replacement());
+ assertTrue(Arrays.equals(ba, ec.replacement()));
/*
* ------------------------ Exceptional cases -------------------------
@@ -996,7 +996,7 @@ public void testReplacement() {
byte[] nr = getLegalByteArray();
assertSame(encoder, encoder.replaceWith(nr));
- assertSame(nr, encoder.replacement());
+ assertTrue(Arrays.equals(nr, encoder.replacement()));
nr = getIllegalByteArray();
try {
@@ -1099,7 +1099,7 @@ protected CoderResult implFlush(ByteBuffer out) {
}
protected void implReplaceWith(byte[] ba) {
- assertSame(ba, replacement());
+ assertTrue(Arrays.equals(ba, replacement()));
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java
index d52e58621..d2f4ca3c4 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java
@@ -21,6 +21,7 @@
import java.text.FieldPosition;
import java.text.MessageFormat;
import java.text.ParsePosition;
+import java.util.Arrays;
import java.util.Locale;
import junit.framework.TestCase;
@@ -292,31 +293,6 @@ public void test_formatJLjava_lang_StringBufferLjava_text_FieldPosition() {
assertEquals("Wrong choice for 2.5", "Greater than two", r);
}
- /**
- * @tests java.text.ChoiceFormat#getFormats()
- */
- public void test_getFormats() {
- // Test for method java.lang.Object []
- // java.text.ChoiceFormat.getFormats()
- String[] orgFormats = (String[]) formats.clone();
- String[] f = (String[]) f1.getFormats();
- assertTrue("Wrong formats", f.equals(formats));
- f[0] = "Modified";
- assertTrue("Formats copied", !f.equals(orgFormats));
- }
-
- /**
- * @tests java.text.ChoiceFormat#getLimits()
- */
- public void test_getLimits() {
- // Test for method double [] java.text.ChoiceFormat.getLimits()
- double[] orgLimits = (double[]) limits.clone();
- double[] l = f1.getLimits();
- assertTrue("Wrong limits", l.equals(limits));
- l[0] = 3.14527;
- assertTrue("Limits copied", !l.equals(orgLimits));
- }
-
/**
* @tests java.text.ChoiceFormat#hashCode()
*/
@@ -389,20 +365,6 @@ public void test_previousDoubleD() {
.previousDouble(Double.NaN)));
}
- /**
- * @tests java.text.ChoiceFormat#setChoices(double[], java.lang.String[])
- */
- public void test_setChoices$D$Ljava_lang_String() {
- // Test for method void java.text.ChoiceFormat.setChoices(double [],
- // java.lang.String [])
- ChoiceFormat f = (ChoiceFormat) f1.clone();
- double[] l = new double[] { 0, 1 };
- String[] fs = new String[] { "0", "1" };
- f.setChoices(l, fs);
- assertTrue("Limits copied", f.getLimits() == l);
- assertTrue("Formats copied", f.getFormats() == fs);
- }
-
/**
* @tests java.text.ChoiceFormat#toPattern()
*/
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java
index 3d710c595..29470d112 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java
@@ -1151,12 +1151,12 @@ public void test_formatDouble_scientificNotation() {
// Scientific notation => use significant digit logic
// '@' not present: Significant digits: Min: 1,
// Max: "min integer digits" (1) + "max fractional digits (0) == 1
- formatTester.format(df, "0E0", 0.0);
- formatTester.format(df, "1E0", 1.0);
- formatTester.format(df, "1E1", 12.0);
- formatTester.format(df, "1E2", 123.0);
- formatTester.format(df, "1E3", 1234.0);
- formatTester.format(df, "1E4", 9999.0);
+ formatTester.format(df, "0.E0", 0.0);
+ formatTester.format(df, "1.E0", 1.0);
+ formatTester.format(df, "1.E1", 12.0);
+ formatTester.format(df, "1.E2", 123.0);
+ formatTester.format(df, "1.E3", 1234.0);
+ formatTester.format(df, "1.E4", 9999.0);
df = new DecimalFormat("##0.00#E0", dfs);
// ["##0.00#E0",isDecimalSeparatorAlwaysShown=false,groupingSize=0,multiplier=1,
@@ -1699,7 +1699,7 @@ public void test_formatDouble_bug17656132() {
// double 9999999999.999998 is decimal 9999999999.9999980926513671875
assertEquals("9999999999.999998", df.format(9999999999.999998));
// double 1E23 is decimal 99999999999999991611392
- assertEquals("9999999999999999", df.format(1E23));
+ assertEquals("99999999999999990000000", df.format(1E23));
}
public void test_getDecimalFormatSymbols() {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ParseExceptionTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ParseExceptionTest.java
index c73d8e3c5..307cfb684 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ParseExceptionTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ParseExceptionTest.java
@@ -16,6 +16,8 @@
*/
package org.apache.harmony.tests.java.text;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
import java.text.DateFormat;
import java.text.ParseException;
@@ -46,4 +48,17 @@ public void test_getErrorOffset() {
assertEquals("getErrorOffsetFailed.", 4, e.getErrorOffset());
}
}
+
+ public void test_serialize() throws Exception {
+ try (InputStream inputStream = getClass().getResourceAsStream(
+ "/serialization/org/apache/harmony/tests/java/text/ParseException.ser");
+ ObjectInputStream ois = new ObjectInputStream(inputStream)) {
+
+ Object object = ois.readObject();
+ assertTrue("Not a ParseException", object instanceof ParseException);
+ ParseException parseException = (ParseException) object;
+ assertEquals("fred", parseException.getMessage());
+ assertEquals(4, parseException.getErrorOffset());
+ }
+ }
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/SimpleDateFormatTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/SimpleDateFormatTest.java
index 9237fac3b..16217b2f0 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/SimpleDateFormatTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/SimpleDateFormatTest.java
@@ -641,11 +641,13 @@ public void test_parse_h_z_2DigitOffsetFromGMT_doesNotParse() throws Exception {
SimpleDateFormat pFormat = new SimpleDateFormat("h z", Locale.ENGLISH);
try {
pFormat.parse("14 GMT-23");
+ fail();
} catch (ParseException expected) {
}
try {
pFormat.parse("14 GMT+23");
+ fail();
} catch (ParseException expected) {
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArrayDequeTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArrayDequeTest.java
index b0fc89673..0b832239a 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArrayDequeTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArrayDequeTest.java
@@ -928,6 +928,7 @@ public void test_spliterator() throws Exception {
SpliteratorTester.runOrderedTests(adq);
SpliteratorTester.runSizedTests(adq, 16 /* expected size */);
SpliteratorTester.runSubSizedTests(adq, 16 /* expected size */);
+ SpliteratorTester.assertSupportsTrySplit(adq);
}
public void test_spliterator_CME() throws Exception {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArrayListTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArrayListTest.java
index cb22613a8..7b3d7d04e 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArrayListTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArrayListTest.java
@@ -344,7 +344,7 @@ public void test_addAllILjava_util_Collection_3() {
}
}
-// BEGIN android-removed
+// BEGIN Android-removed
// The spec does not mandate that IndexOutOfBoundsException be thrown in
// preference to NullPointerException when the caller desserves both.
//
@@ -360,7 +360,7 @@ public void test_addAllILjava_util_Collection_3() {
// } catch (IndexOutOfBoundsException e) {
// }
// }
-// END android-removed
+// END Android-removed
/**
* java.util.ArrayList#addAll(java.util.Collection)
@@ -1129,6 +1129,7 @@ public void test_spliterator() throws Exception {
SpliteratorTester.runOrderedTests(list);
SpliteratorTester.runSizedTests(list, 16 /* expected size */);
SpliteratorTester.runSubSizedTests(list, 16 /* expected size */);
+ SpliteratorTester.assertSupportsTrySplit(list);
}
public void test_spliterator_CME() throws Exception {
@@ -1178,6 +1179,7 @@ public void test_sublist_spliterator() {
SpliteratorTester.runOrderedTests(list);
SpliteratorTester.runSizedTests(list, 8 /* expected size */);
SpliteratorTester.runSubSizedTests(list, 8 /* expected size */);
+ SpliteratorTester.assertSupportsTrySplit(list);
}
/**
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArraysTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArraysTest.java
index 7b0bed1fe..ea6d02e15 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArraysTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArraysTest.java
@@ -4214,6 +4214,7 @@ public void test_asList_spliterator() {
assertTrue(list.spliterator().hasCharacteristics(Spliterator.ORDERED));
SpliteratorTester.runOrderedTests(list);
+ SpliteratorTester.assertSupportsTrySplit(list);
}
public void test_spliterator_ref() {
@@ -4225,6 +4226,7 @@ public void test_spliterator_ref() {
SpliteratorTester.runBasicIterationTests(Arrays.spliterator(elements), expected);
SpliteratorTester.testSpliteratorNPE(Arrays.spliterator(elements));
+ assertNotNull(Arrays.spliterator(elements).trySplit());
Spliterator sp = Arrays.spliterator(elements);
assertTrue(sp.hasCharacteristics(Spliterator.ORDERED));
@@ -4249,6 +4251,7 @@ public void test_spliterator_ref_bounds() {
SpliteratorTester.runBasicIterationTests(Arrays.spliterator(elements, 2, 16), expected);
SpliteratorTester.testSpliteratorNPE(Arrays.spliterator(elements, 2, 16));
+ assertNotNull(Arrays.spliterator(elements, 2, 16).trySplit());
Spliterator sp = Arrays.spliterator(elements, 2, 16);
assertTrue(sp.hasCharacteristics(Spliterator.ORDERED));
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CalendarTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CalendarTest.java
index 06a37c816..6284f0f46 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CalendarTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CalendarTest.java
@@ -968,7 +968,8 @@ public void test_getDisplayNamesIILjava_util_Locale() {
.getAmPmStrings() : symbols.getEras();
assertDisplayNameMap(values, shortResult, 0);
assertDisplayNameMap(values, longResult, 0);
- assertDisplayNameMap(values, allResult, 0);
+ assertTrue(allResult.size() >= shortResult.size());
+ assertTrue(allResult.size() >= longResult.size());
break;
case Calendar.MONTH:
values = symbols.getShortMonths();
@@ -977,8 +978,6 @@ public void test_getDisplayNamesIILjava_util_Locale() {
assertDisplayNameMap(values, longResult, 0);
assertTrue(allResult.size() >= shortResult.size());
assertTrue(allResult.size() >= longResult.size());
- assertTrue(allResult.size() <= shortResult.size()
- + longResult.size());
break;
case Calendar.DAY_OF_WEEK:
values = symbols.getShortWeekdays();
@@ -987,8 +986,6 @@ public void test_getDisplayNamesIILjava_util_Locale() {
assertDisplayNameMap(values, longResult, 1);
assertTrue(allResult.size() >= shortResult.size());
assertTrue(allResult.size() >= longResult.size());
- assertTrue(allResult.size() <= shortResult.size()
- + longResult.size());
break;
default:
assertNull(shortResult);
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CollectionsTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CollectionsTest.java
index 8b45079da..b71fade8d 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CollectionsTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CollectionsTest.java
@@ -28,6 +28,7 @@
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.util.AbstractList;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
@@ -750,10 +751,11 @@ public void test_sortLjava_util_ListLjava_util_Comparator() {
//expected
}
- Mock_ArrayList mal = new Mock_ArrayList();
-
- mal.add(new MyInt(1));
- mal.add(new MyInt(2));
+ List mal = new AbstractList() {
+ private final List delegate = Arrays.asList(new MyInt(1), new MyInt(2));
+ @Override public Object get(int index) { return delegate.get(index); }
+ @Override public int size() { return delegate.size(); }
+ };
try {
Collections.sort(mal, comp);
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CurrencyTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CurrencyTest.java
index a32845c95..ec065a96c 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CurrencyTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CurrencyTest.java
@@ -131,6 +131,18 @@ public void test_getInstanceLjava_util_Locale() {
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
}
+
+ try {
+ Currency.getInstance((Locale) null);
+ fail("Expected NullPointerException");
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ Currency.getInstance((String) null);
+ fail("Expected NullPointerException");
+ } catch (NullPointerException expected) {
+ }
}
/**
@@ -142,31 +154,31 @@ public void test_getSymbol() {
Currency currUS = Currency.getInstance("USD");
Locale.setDefault(Locale.US);
- // BEGIN android-changed
+ // BEGIN Android-changed
// KRW currency symbol is \u20a9 since CLDR1.7 release.
assertEquals("currK.getSymbol()", "\u20a9", currK.getSymbol());
// IEP currency symbol is IEP since CLDR2.0 release.
assertEquals("currI.getSymbol()", "IEP", currI.getSymbol());
- // END android-changed
+ // END Android-changed
assertEquals("currUS.getSymbol()", "$", currUS.getSymbol());
Locale.setDefault(new Locale("en", "IE"));
- // BEGIN android-changed
+ // BEGIN Android-changed
assertEquals("currK.getSymbol()", "\u20a9", currK.getSymbol());
assertEquals("currI.getSymbol()", "IEP", currI.getSymbol());
assertEquals("currUS.getSymbol()", "US$", currUS.getSymbol());
- // END android-changed
+ // END Android-changed
// Test what happens if the default is an invalid locale, one with the country Korea (KR)
// but a currently unsupported language. "kr" == Kanuri (Korean is actually "ko").
// All these values are those defined in the "root" locale or the currency code if one isn't
// defined.
Locale.setDefault(new Locale("kr", "KR"));
- // BEGIN android-changed
+ // BEGIN Android-changed
assertEquals("currK.getSymbol()", "\u20a9", currK.getSymbol());
assertEquals("currI.getSymbol()", "IEP", currI.getSymbol());
assertEquals("currUS.getSymbol()", "US$", currUS.getSymbol());
- // END android-changed
+ // END Android-changed
}
/**
@@ -221,10 +233,10 @@ public void test_getSymbolLjava_util_Locale() {
// But the RI returns the \uffe5 and Android returns those with \u00a5
String[] yen = new String[] {"JPY", "\u00a5", "\u00a5JP", "JP\u00a5", "\uffe5", "\uffe5JP", "JP\uffe5"};
String[] dollar = new String[] {"USD", "$", "US$", "$US", "$ US"};
- // BEGIN android-changed
+ // BEGIN Android-changed
// Starting CLDR 1.7 release, currency symbol for CAD changed to CA$ in some locales such as ja.
String[] cDollar = new String[] {"CA$", "CAD", "$", "Can$", "$CA"};
- // END android-changed
+ // END Android-changed
Currency currE = Currency.getInstance("EUR");
Currency currJ = Currency.getInstance("JPY");
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/EnumSetTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/EnumSetTest.java
index 612c9f1b4..9213d7f38 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/EnumSetTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/EnumSetTest.java
@@ -1211,11 +1211,15 @@ public void test_retainAll_LCollection() {
}
set.clear();
- boolean result = set.retainAll(null);
- assertFalse("Should return false", result);
+ try {
+ set.retainAll(null);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
Collection rawCollection = new ArrayList();
- result = set.retainAll(rawCollection);
+ boolean result = set.retainAll(rawCollection);
assertFalse("Should return false", result);
rawCollection.add(EnumFoo.a);
@@ -1305,8 +1309,12 @@ public void test_retainAll_LCollection() {
}
hugeSet.clear();
- result = hugeSet.retainAll(null);
- assertFalse(result);
+ try {
+ hugeSet.retainAll(null);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
rawCollection = new ArrayList();
result = hugeSet.retainAll(rawCollection);
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/GregorianCalendarTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/GregorianCalendarTest.java
index bbd8c50ae..1483222c5 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/GregorianCalendarTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/GregorianCalendarTest.java
@@ -580,7 +580,9 @@ public void test_rollIZ() {
.get(Calendar.YEAR));
assertEquals("Wrong month: " + cal.getTime(), Calendar.JANUARY, cal
.get(Calendar.MONTH));
- assertEquals("Wrong date: " + cal.getTime(), 9, cal.get(Calendar.DATE));
+ // Android-changed: Bugfix for https://bugs.openjdk.java.net/browse/JDK-6902861. This
+ // returned 9 before Android O.
+ assertEquals("Wrong date: " + cal.getTime(), 2, cal.get(Calendar.DATE));
// Regression for HARMONY-4372
cal.set(1994, 11, 30, 5, 0, 0);
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashMapTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashMapTest.java
index adf662065..5c7812609 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashMapTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashMapTest.java
@@ -848,6 +848,7 @@ public void test_spliterator_keySet() {
SpliteratorTester.runSizedTests(keys.spliterator(), 16);
SpliteratorTester.runDistinctTests(keys);
+ SpliteratorTester.assertSupportsTrySplit(keys);
}
public void test_spliterator_valueSet() {
@@ -879,6 +880,7 @@ public void test_spliterator_valueSet() {
assertTrue(values.spliterator().hasCharacteristics(Spliterator.SIZED));
SpliteratorTester.runSizedTests(values.spliterator(), 16);
+ SpliteratorTester.assertSupportsTrySplit(values);
}
public void test_spliterator_entrySet() {
@@ -914,6 +916,7 @@ public void test_spliterator_entrySet() {
SpliteratorTester.runSizedTests(values.spliterator(), 16);
SpliteratorTester.runDistinctTests(values);
+ SpliteratorTester.assertSupportsTrySplit(values);
}
/**
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashSetTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashSetTest.java
index 95aeb6edc..a42b42fc3 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashSetTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashSetTest.java
@@ -275,6 +275,7 @@ public void test_spliterator() throws Exception {
assertTrue(hashSet.spliterator().hasCharacteristics(Spliterator.DISTINCT));
SpliteratorTester.runDistinctTests(keys);
+ SpliteratorTester.assertSupportsTrySplit(hashSet);
}
/**
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashtableTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashtableTest.java
index 165ff2322..6500ae7c4 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashtableTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/HashtableTest.java
@@ -249,7 +249,7 @@ public void test_elements() {
}
}
-// BEGIN android-removed
+// BEGIN Android-removed
// implementation dependent
// /**
// * java.util.Hashtable#elements()
@@ -285,7 +285,7 @@ public void test_elements() {
// }
// assertTrue("unexpected NoSuchElementException", !exception);
// }
-// END android-removed
+// END Android-removed
/**
* java.util.Hashtable#entrySet()
@@ -301,11 +301,11 @@ public void test_entrySet() {
while (e.hasMoreElements())
assertTrue("Returned incorrect entry set", s2.contains(e
.nextElement()));
-// BEGIN android-removed
+// BEGIN Android-removed
// implementation dependent
// assertEquals("Not synchronized",
// "java.util.Collections$SynchronizedSet", s.getClass().getName());
-// END android-removed
+// END Android-removed
boolean exception = false;
try {
@@ -338,7 +338,7 @@ public void test_getLjava_lang_Object() {
assertEquals("Could not retrieve element", "FVal 2", ((String) h.get("FKey 2"))
);
-// BEGIN android-removed
+// BEGIN Android-removed
// implementation dependent
// // Regression for HARMONY-262
// ReusableKey k = new ReusableKey();
@@ -358,7 +358,7 @@ public void test_getLjava_lang_Object() {
// } catch (NullPointerException e) {
// //expected
// }
-// END android-removed
+// END Android-removed
}
/**
@@ -469,11 +469,11 @@ public void test_keySet() {
assertTrue("Returned incorrect key set", s
.contains(e.nextElement()));
-// BEGIN android-removed
+// BEGIN Android-removed
// implementation dependent
// assertEquals("Not synchronized",
// "java.util.Collections$SynchronizedSet", s.getClass().getName());
-// END android-removed
+// END Android-removed
Map map = new Hashtable(101);
map.put(new Integer(1), "1");
@@ -548,7 +548,7 @@ public void run() {
}
}
-// BEGIN android-removed
+// BEGIN Android-removed
// implementation dependent
// /**
// * java.util.Hashtable#keySet()
@@ -592,7 +592,7 @@ public void run() {
// }
// assertTrue("unexpected NoSuchElementException", !exception);
// }
-// END android-removed
+// END Android-removed
/**
* java.util.Hashtable#put(java.lang.Object, java.lang.Object)
@@ -751,11 +751,11 @@ public void test_values() {
while (e.hasMoreElements())
assertTrue("Returned incorrect values", c.contains(e.nextElement()));
-// BEGIN android-removed
+// BEGIN Android-removed
// implementation dependent
// assertEquals("Not synchronized",
// "java.util.Collections$SynchronizedCollection", c.getClass().getName());
-// END android-removed
+// END Android-removed
Hashtable myHashtable = new Hashtable();
for (int i = 0; i < 100; i++)
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/IdentityHashMapTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/IdentityHashMapTest.java
index ee1a3721c..bc84a9a00 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/IdentityHashMapTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/IdentityHashMapTest.java
@@ -448,12 +448,12 @@ public void test_equalsLjava_lang_Object() {
public void test_Serialization() throws Exception {
IdentityHashMap map = new IdentityHashMap();
map.put(ID, "world");
- // BEGIN android-added
+ // BEGIN Android-added
// Regression test for null key in serialized IdentityHashMap (1178549)
// Together with this change the IdentityHashMap.golden.ser resource
// was replaced by a version that contains a map with a null key.
map.put(null, "null");
- // END android-added
+ // END Android-added
SerializationTest.verifySelf(map, comparator);
SerializationTest.verifyGolden(this, map, comparator);
}
@@ -467,7 +467,7 @@ protected void setUp() {
objArray2 = new Object[hmSize];
for (int i = 0; i < objArray.length; i++) {
objArray[i] = new Integer(i);
- // android-changed: the containsKey test requires unique strings.
+ // Android-changed: the containsKey test requires unique strings.
objArray2[i] = new String(objArray[i].toString());
}
@@ -996,6 +996,7 @@ public void test_spliterator_keySet() {
SpliteratorTester.runBasicIterationTests(keys.spliterator(), expectedKeys);
SpliteratorTester.runBasicSplitTests(keys, expectedKeys);
SpliteratorTester.testSpliteratorNPE(keys.spliterator());
+ SpliteratorTester.assertSupportsTrySplit(keys);
}
public void test_spliterator_valueSet() {
@@ -1023,6 +1024,7 @@ public void test_spliterator_valueSet() {
SpliteratorTester.runBasicIterationTests(values.spliterator(), expectedValues);
SpliteratorTester.runBasicSplitTests(values, expectedValues);
SpliteratorTester.testSpliteratorNPE(values.spliterator());
+ SpliteratorTester.assertSupportsTrySplit(values);
}
public void test_spliterator_entrySet() {
@@ -1053,6 +1055,7 @@ public void test_spliterator_entrySet() {
SpliteratorTester.runBasicIterationTests(values.spliterator(), expectedValues);
SpliteratorTester.runBasicSplitTests(values, expectedValues, comparator);
SpliteratorTester.testSpliteratorNPE(values.spliterator());
+ SpliteratorTester.assertSupportsTrySplit(values);
}
public void test_replaceAll() {
@@ -1080,6 +1083,7 @@ public String apply(String s, String s2) {
return "";
}
});
+ fail();
} catch (ConcurrentModificationException expected) {}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/InvalidPropertiesFormatExceptionTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/InvalidPropertiesFormatExceptionTest.java
deleted file mode 100644
index 10bb50e4d..000000000
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/InvalidPropertiesFormatExceptionTest.java
+++ /dev/null
@@ -1,50 +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.
- */
-package org.apache.harmony.tests.java.util;
-
-import java.io.NotSerializableException;
-import java.util.InvalidPropertiesFormatException;
-
-import org.apache.harmony.testframework.serialization.SerializationTest;
-
-public class InvalidPropertiesFormatExceptionTest extends
- junit.framework.TestCase {
-
- /**
- * java.util.InvalidPropertiesFormatException#SerializationTest()
- */
- public void test_Serialization() throws Exception {
- InvalidPropertiesFormatException ipfe = new InvalidPropertiesFormatException(
- "Hey, this is InvalidPropertiesFormatException");
- try {
- SerializationTest.verifySelf(ipfe);
- } catch (NotSerializableException e) {
- // expected
- }
- }
-
- /**
- * {@link java.util.InvalidPropertiesFormatException#InvalidPropertiesFormatException(Throwable)}
- */
- public void test_Constructor_Ljava_lang_Throwable() {
- Throwable throwable = new Throwable();
- InvalidPropertiesFormatException exception = new InvalidPropertiesFormatException(
- throwable);
- assertEquals("the casue did not equals argument passed in constructor",
- throwable, exception.getCause());
- }
-
-}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/LinkedHashSetTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/LinkedHashSetTest.java
index f3340d140..d403b2ac1 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/LinkedHashSetTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/LinkedHashSetTest.java
@@ -348,6 +348,7 @@ public void test_spliterator() throws Exception {
assertTrue(hashSet.spliterator().hasCharacteristics(Spliterator.DISTINCT));
SpliteratorTester.runDistinctTests(keys);
+ SpliteratorTester.assertSupportsTrySplit(hashSet);
}
/**
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/LinkedListTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/LinkedListTest.java
index da01e342d..ea829c9a9 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/LinkedListTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/LinkedListTest.java
@@ -963,6 +963,7 @@ public void test_spliterator() throws Exception {
SpliteratorTester.runOrderedTests(list);
SpliteratorTester.runSizedTests(list, 16 /* expected size */);
SpliteratorTester.runSubSizedTests(list, 16 /* expected size */);
+ SpliteratorTester.assertSupportsTrySplit(list);
}
public void test_spliterator_CME() throws Exception {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/LocaleTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/LocaleTest.java
index dfb2d9605..b4cf99bf4 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/LocaleTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/LocaleTest.java
@@ -124,7 +124,7 @@ public void test_equalsLjava_lang_Object() {
* java.util.Locale#getAvailableLocales()
*/
public void test_getAvailableLocales() {
-// BEGIN android-changed
+// BEGIN Android-changed
// Test for method java.util.Locale []
// java.util.Locale.getAvailableLocales()
// Assumes there will generally be about 10+ available locales...
@@ -139,7 +139,7 @@ public void test_getAvailableLocales() {
} catch (Exception e) {
fail("Exception during test : " + e.getMessage());
}
-// END android-changed
+// END Android-changed
}
/**
@@ -172,11 +172,6 @@ public void test_getDisplayCountry() {
assertTrue("Returned incorrect country: "
+ testLocale.getDisplayCountry(), testLocale
.getDisplayCountry().equals("Canada"));
-
- // Regression for Harmony-1146
- Locale l_countryCD = new Locale("", "CD");
- assertEquals("Congo (DRC)",
- l_countryCD.getDisplayCountry());
}
public void test_getDisplayCountryLjava_util_Locale() {
@@ -308,14 +303,14 @@ public void test_getISOLanguages() {
String[] isoLang = Locale.getISOLanguages();
int length = isoLang.length;
- // BEGIN android-changed
+ // BEGIN Android-changed
// Language codes are 2- and 3-letter, with preference given
// to 2-letter codes where possible. 3-letter codes are used
// when lack a 2-letter equivalent.
assertTrue("Random element in wrong format.",
(isoLang[length / 2].length() == 2 || isoLang[length / 2].length() == 3)
&& isoLang[length / 2].toLowerCase().equals(isoLang[length / 2]));
- // END android-changed
+ // END Android-changed
assertTrue("Wrong number of ISOLanguages.", length > 130);
}
@@ -410,7 +405,7 @@ public void test_constantROOT() {
assertEquals("", root.getVariant());
}
-// BEGIN android-removed
+// BEGIN Android-removed
// These locales are not part of the android reference impl
// // Regression Test for HARMONY-2953
// public void test_getISO() {
@@ -426,7 +421,7 @@ public void test_constantROOT() {
// List countries = Arrays.asList(Locale.getISOCountries());
// assertTrue(countries.contains("CS"));
// }
-// END android-removed
+// END Android-removed
/**
* Sets up the fixture, for example, open a network connection. This method
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/PriorityQueueTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/PriorityQueueTest.java
index d4061dc39..b6d95d47c 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/PriorityQueueTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/PriorityQueueTest.java
@@ -800,6 +800,7 @@ public void test_spliterator() throws Exception {
SpliteratorTester.runSizedTests(list, 16 /* expected size */);
SpliteratorTester.runSubSizedTests(list, 16 /* expected size */);
+ SpliteratorTester.assertSupportsTrySplit(list);
}
public void test_spliterator_CME() throws Exception {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/PropertiesTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/PropertiesTest.java
index 27cae4e36..038cc7bf9 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/PropertiesTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/PropertiesTest.java
@@ -20,15 +20,18 @@
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.CharArrayReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.PrintWriter;
+import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.InvalidPropertiesFormatException;
@@ -389,21 +392,21 @@ public void test_loadLjava_io_Reader() throws IOException {
prop = new Properties();
Properties expected = new Properties();
- expected.put("a", "\u0000");
+ expected.put("a", "");
prop.load(new ByteArrayInputStream("a=\\".getBytes()));
- assertEquals("Failed to read trailing slash value", expected, prop);
+ assertEquals("Failed to trim trailing slash value", expected, prop);
prop = new Properties();
expected = new Properties();
- expected.put("a", "\u1234\u0000");
+ expected.put("a", "\u1234");
prop.load(new ByteArrayInputStream("a=\\u1234\\".getBytes()));
- assertEquals("Failed to read trailing slash value #2", expected, prop);
+ assertEquals("Failed to trim trailing slash value #2", expected, prop);
prop = new Properties();
expected = new Properties();
expected.put("a", "q");
prop.load(new ByteArrayInputStream("a=\\q".getBytes()));
- assertEquals("Failed to read slash value #3", expected, prop);
+ assertEquals("Failed to skip slash value #3", expected, prop);
}
/**
@@ -1086,6 +1089,47 @@ public void testLoadReader() throws IOException {
inputStream.close();
}
+ /**
+ * Checks the example given in the documentation of a single property split over
+ * multiple lines separated by a backslash and newline character.
+ */
+ public void testSingleProperty_multipleLinesJoinedByBackslash() throws Exception {
+ String propertyString = "fruits apple, banana, pear, \\\n"
+ + " cantaloupe, watermelon, \\\n"
+ + " kiwi, mango";
+ checkSingleProperty("fruits", "apple, banana, pear, cantaloupe, watermelon, kiwi, mango",
+ propertyString);
+ }
+
+ /**
+ * Checks that a trailing backslash at the end of the single line of input is ignored.
+ * This is similar to a check in {@link #test_loadLjava_io_Reader()} that uses an
+ * InputStream and {@link Properties#equals(Object)} .
+ */
+ public void testSingleProperty_oneLineWithTrailingBackslash() throws Exception {
+ checkSingleProperty("key", "value", "key=value\\");
+ }
+
+ /**
+ * Checks that a trailing backslash at the end of the single line of input is ignored,
+ * even when that line has a newline.
+ */
+ public void testSingleProperty_oneLineWithTrailingBackslash_newline() throws Exception {
+ checkSingleProperty("key", "value", "key=value\\\r");
+ checkSingleProperty("key", "value", "key=value\\\n");
+ checkSingleProperty("key", "value", "key=value\\\r\n");
+ }
+
+ private static void checkSingleProperty(String key, String value, String serialized)
+ throws IOException {
+ Properties properties = new Properties();
+ try (Reader reader = new CharArrayReader(serialized.toCharArray())) {
+ properties.load(reader);
+ assertEquals(Collections.singleton(key), properties.keySet());
+ assertEquals(value, properties.getProperty(key));
+ }
+ }
+
/**
* Sets up the fixture, for example, open a network connection. This method
* is called before a test is executed.
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ResourceBundleTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ResourceBundleTest.java
index db2ee7ab9..5d35e4cbf 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ResourceBundleTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ResourceBundleTest.java
@@ -39,6 +39,17 @@ public void test_getCandidateLocales() throws Exception {
assertEquals("[de_CH, de, ]", c.getCandidateLocales("base", new Locale("de", "CH")).toString());
}
+ public void test_getBaseName() {
+ String name = "tests.support.Support_TestResource";
+ ResourceBundle bundle = ResourceBundle.getBundle(name);
+ assertEquals(name, bundle.getBaseBundleName());
+
+ bundle = ResourceBundle.getBundle(name, Locale.getDefault());
+ assertEquals(name, bundle.getBaseBundleName());
+
+ assertNull(new Mock_ResourceBundle().getBaseBundleName());
+ }
+
/**
* java.util.ResourceBundle#getBundle(java.lang.String,
* java.util.Locale)
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ScannerTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ScannerTest.java
index d67b1c906..909dd27d4 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ScannerTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ScannerTest.java
@@ -46,6 +46,10 @@
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.InputMismatchException;
@@ -118,6 +122,38 @@ public void test_ConstructorLjava_io_File() throws IOException {
// TODO: test if the default charset is used.
}
+
+ /**
+ * @tests java.util.Scanner#Scanner(Path)
+ */
+ public void test_ConstructorLjava_nio_file_Path() throws IOException {
+ Path tmpFilePath = Files.createTempFile("TestFileForScanner", ".tmp");
+ String testString = "test";
+ try (OutputStream os = Files.newOutputStream(tmpFilePath)) {
+ os.write(testString.getBytes());
+ }
+ try (Scanner s = new Scanner(tmpFilePath)){
+ assertEquals(testString, s.next());
+ assertFalse(s.hasNext());
+ }
+ }
+
+ /**
+ * @tests java.util.Scanner#Scanner(Path)
+ */
+ public void test_ConstructorLjava_nio_file_Path_Exception() throws IOException {
+ Path nonExistentFilePath = Paths.get("testPath");
+ try (Scanner s = new Scanner(nonExistentFilePath)) {
+ fail();
+ } catch (NoSuchFileException expected) {
+ }
+
+ try (Scanner s = new Scanner((Path) null)) {
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
/**
* @tests java.util.Scanner#Scanner(File, String)
*/
@@ -185,6 +221,83 @@ public void test_ConstructorLjava_io_FileLjava_lang_String()
// TODO: test if the specified charset is used.
}
+ /**
+ * @tests java.util.Scanner#Scanner(Path, String)
+ */
+ public void test_ConstructorLjava_nio_file_PathLjava_lang_String()
+ throws IOException {
+ Path tmpFilePath = Files.createTempFile("TestFileForScanner", ".tmp");
+ String testString = "परीक्षण";
+ try (OutputStream os = Files.newOutputStream(tmpFilePath)) {
+ os.write(testString.getBytes());
+ }
+ // With correct charset.
+ try (Scanner s = new Scanner(tmpFilePath, Charset.defaultCharset().name())){
+ assertEquals(testString, s.next());
+ assertFalse(s.hasNext());
+ }
+ // With incorrect charset.
+ try (Scanner s = new Scanner(tmpFilePath, "US-ASCII")){
+ if (s.next().equals(testString)) {
+ fail("Should not be able to read with incorrect charset.");
+ }
+ }
+ }
+
+ /**
+ * @tests java.util.Scanner#Scanner(Path, String)
+ */
+ public void test_ConstructorLjava_nio_file_PathLjava_lang_String_Exception()
+ throws IOException {
+ Path nonExistentFilePath = Paths.get("nonExistentFile");
+ Path existentFilePath = Files.createTempFile("TestFileForScanner", ".tmp");
+
+ // File doesn't exist.
+ try (Scanner s = new Scanner(nonExistentFilePath, Charset.defaultCharset().name())) {
+ fail();
+ } catch (NoSuchFileException expected) {
+ }
+
+ // Exception order test.
+ try {
+ s = new Scanner(nonExistentFilePath, null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ // Invalid charset.
+ try {
+ s = new Scanner(existentFilePath, "invalid charset");
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // Scanner(Path = null, Charset = null)
+ try (Scanner s = new Scanner((Path) null, null)) {
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ // Scanner(Path = null, Charset = UTF-8)
+ try (Scanner s = new Scanner((Path) null, "UTF-8")) {
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ // Scanner(Path = null, Charset = invalid)
+ try (Scanner s = new Scanner((Path) null, "invalid")) {
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ // Scanner(Path, Charset = null)
+ try (Scanner s = new Scanner(existentFilePath, null)) {
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+
/**
* @tests java.util.Scanner#Scanner(InputStream)
*/
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/TreeSetTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/TreeSetTest.java
index 8d1c3f841..008701383 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/TreeSetTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/TreeSetTest.java
@@ -344,6 +344,7 @@ public void test_spliterator() throws Exception {
assertTrue(treeSet.spliterator().hasCharacteristics(Spliterator.DISTINCT));
SpliteratorTester.runDistinctTests(keys);
+ SpliteratorTester.assertSupportsTrySplit(treeSet);
}
/**
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/VectorTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/VectorTest.java
index a9f64a2ee..f889c8e7e 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/VectorTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/VectorTest.java
@@ -30,6 +30,7 @@
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.Spliterator;
import java.util.Vector;
@@ -850,6 +851,15 @@ public void test_lastIndexOfLjava_lang_ObjectI() {
}
}
+ // http://b/30974375
+ public void test_listIterator_addAndPrevious() {
+ ListIterator it = new Vector().listIterator();
+ assertFalse(it.hasNext());
+ it.add("value");
+ assertEquals("value", it.previous());
+ assertTrue(it.hasNext());
+ }
+
/**
* java.util.Vector#remove(int)
*/
@@ -1447,6 +1457,7 @@ public void test_spliterator() throws Exception {
SpliteratorTester.runOrderedTests(list);
SpliteratorTester.runSizedTests(list, 16 /* expected size */);
SpliteratorTester.runSubSizedTests(list, 16 /* expected size */);
+ SpliteratorTester.assertSupportsTrySplit(list);
}
public void test_spliterator_CME() throws Exception {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/WeakHashMapTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/WeakHashMapTest.java
index 302b50583..312542d1d 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/WeakHashMapTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/WeakHashMapTest.java
@@ -310,14 +310,20 @@ public void test_keySet() {
long startTime = System.currentTimeMillis();
// We use a busy wait loop here since we cannot know when the ReferenceQueue
// daemon will enqueue the cleared references on their internal reference
- // queues. The current timeout is 5 seconds.
+ // queues.
+ // The timeout after which the reference should be cleared. This test used to
+ // be flaky when it was set to 5 seconds. Daemons.MAX_FINALIZE_NANOS is
+ // currently 10 seconds so that seems like the correct value.
+ // We allow an extra 500msec buffer to minimize races between finalizer,
+ // keySet.size() evaluation and time check.
+ long timeout = 10000 + 500;
do {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
} while (keySet.size() != 99 &&
- System.currentTimeMillis() - startTime < 5000);
+ System.currentTimeMillis() - startTime < timeout);
assertEquals("Incorrect number of keys returned after gc,", 99, keySet.size());
}
@@ -539,6 +545,7 @@ public void test_spliterator_keySet() {
assertTrue(keys.spliterator().hasCharacteristics(Spliterator.DISTINCT));
SpliteratorTester.runDistinctTests(keys);
+ SpliteratorTester.assertSupportsTrySplit(keys);
}
public void test_spliterator_valueSet() {
@@ -602,6 +609,7 @@ public void test_spliterator_entrySet() {
assertTrue(values.spliterator().hasCharacteristics(Spliterator.DISTINCT));
SpliteratorTester.runDistinctTests(values);
+ SpliteratorTester.assertSupportsTrySplit(values);
}
/**
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
index 958d9bcf3..12890c875 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
@@ -36,6 +36,7 @@
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Arrays;
+import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Vector;
@@ -59,7 +60,7 @@
public class JarFileTest extends TestCase {
- // BEGIN android-added
+ // BEGIN Android-added
public byte[] getAllBytesFromStream(InputStream is) throws IOException {
ByteArrayOutputStream bs = new ByteArrayOutputStream();
byte[] buf = new byte[666];
@@ -72,7 +73,7 @@ public byte[] getAllBytesFromStream(InputStream is) throws IOException {
return bs.toByteArray();
}
- // END android-added
+ // END Android-added
private final String jarName = "hyts_patch.jar"; // a 'normal' jar file
@@ -571,9 +572,9 @@ public void test_getInputStreamLjava_util_jar_JarEntry_subtest0() throws Excepti
JarFile jar = new JarFile(signedFile);
JarEntry entry = new JarEntry(entryName3);
InputStream in = jar.getInputStream(entry);
- // BEGIN android-added
+ // BEGIN Android-added
byte[] dummy = getAllBytesFromStream(in);
- // END android-added
+ // END Android-added
assertNull("found certificates", entry.getCertificates());
} catch (Exception e) {
fail("Exception during test 4: " + e);
@@ -584,9 +585,9 @@ public void test_getInputStreamLjava_util_jar_JarEntry_subtest0() throws Excepti
JarEntry entry = jar.getJarEntry(entryName3);
entry.setSize(1076);
InputStream in = jar.getInputStream(entry);
- // BEGIN android-added
+ // BEGIN Android-added
byte[] dummy = getAllBytesFromStream(in);
- // END android-added
+ // END Android-added
fail("SecurityException should be thrown.");
} catch (SecurityException e) {
// expected
@@ -977,9 +978,9 @@ public void test_getInputStreamLjava_util_jar_JarEntry() throws IOException {
try {
JarFile jf = new JarFile(localFile);
java.io.InputStream is = jf.getInputStream(jf.getEntry(entryName));
- // BEGIN android-removed
+ // BEGIN Android-removed
// jf.close();
- // END android-removed
+ // END Android-removed
assertTrue("Returned invalid stream", is.available() > 0);
int r = is.read(b, 0, 1024);
is.close();
@@ -989,9 +990,9 @@ public void test_getInputStreamLjava_util_jar_JarEntry() throws IOException {
}
String contents = sb.toString();
assertTrue("Incorrect stream read", contents.indexOf("bar") > 0);
- // BEGIN android-added
+ // BEGIN Android-added
jf.close();
- // END android-added
+ // END Android-added
} catch (Exception e) {
fail("Exception during test: " + e.toString());
}
@@ -1124,4 +1125,45 @@ protected Object engineGetParameter(String param) throws InvalidParameterExcepti
}
}
}
+
+ /**
+ * java.util.jar.JarFile#stream()
+ */
+ public void test_stream() throws Exception {
+ /*
+ * Note only (and all of) the following should be contained in the file
+ * META-INF/ META-INF/MANIFEST.MF Blah.txt foo/ foo/bar/ foo/bar/A.class
+ */
+ Support_Resources.copyFile(resources, null, jarName);
+ JarFile jarFile = new JarFile(new File(resources, jarName));
+
+ final List names = new ArrayList<>();
+ jarFile.stream().forEach((ZipEntry entry) -> names.add(entry.getName()));
+ assertEquals(Arrays.asList("META-INF/", "META-INF/MANIFEST.MF", "Blah.txt", "foo/", "foo/bar/",
+ "foo/bar/A.class"), names);
+ jarFile.close();
+ }
+
+
+ /**
+ * hyts_metainf.jar contains an additional entry in META-INF (META-INF/bad_checksum.txt),
+ * that has been altered since jar signing - we expect to detect a mismatching digest.
+ */
+ public void test_metainf_verification() throws Exception {
+ String jarFilename = "hyts_metainf.jar";
+ Support_Resources.copyFile(resources, null, jarFilename);
+ try (JarFile jarFile = new JarFile(new File(resources, jarFilename))) {
+
+ JarEntry jre = new JarEntry("META-INF/bad_checksum.txt");
+ InputStream in = jarFile.getInputStream(jre);
+
+ byte[] buffer = new byte[1024];
+ try {
+ while (in.available() > 0) {
+ in.read(buffer);
+ }
+ fail("SecurityException expected");
+ } catch (SecurityException expected) {}
+ }
+ }
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarInputStreamTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarInputStreamTest.java
index 9d4224ae5..bd66bbe4f 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarInputStreamTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarInputStreamTest.java
@@ -403,4 +403,35 @@ public void test_getNextEntry() throws Exception {
// expected
}
}
+
+ /**
+ * hyts_metainf.jar contains an additional entry in META-INF (META-INF/bad_checksum.txt),
+ * that has been altered since jar signing - we expect to detect a mismatching digest.
+ */
+ public void test_metainf_verification() throws Exception {
+ String jarFilename = "hyts_metainf.jar";
+ File resources = Support_Resources.createTempFolder();
+ Support_Resources.copyFile(resources, null, jarFilename);
+ InputStream is = Support_Resources.getStream(jarFilename);
+
+ try (JarInputStream jis = new JarInputStream(is, true)) {
+ JarEntry je = jis.getNextJarEntry();
+ je = jis.getNextJarEntry();
+ je = jis.getNextJarEntry();
+ je = jis.getNextJarEntry();
+
+ if (!je.getName().equals("META-INF/bad_checksum.txt")) {
+ fail("Expected META-INF/bad_checksum.txt as a 4th entry, got:" + je.getName());
+ }
+ byte[] buffer = new byte[1024];
+ int length = 0;
+ try {
+ while (length >= 0) {
+ length = jis.read(buffer);
+ }
+ fail("SecurityException expected");
+ } catch (SecurityException expected) {}
+ }
+ }
+
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/Adler32Test.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/Adler32Test.java
index 755589609..c7e18c072 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/Adler32Test.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/Adler32Test.java
@@ -1,13 +1,13 @@
-/*
+/*
* 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.
@@ -16,6 +16,7 @@
*/
package org.apache.harmony.tests.java.util.zip;
+import java.nio.ByteBuffer;
import java.util.zip.Adler32;
public class Adler32Test extends junit.framework.TestCase {
@@ -158,6 +159,38 @@ public void test_updateI() {
}
+ private void assertChecksumFromByteBuffer(long expectedChecksum, ByteBuffer byteBuffer) {
+ Adler32 checksum = new Adler32();
+ checksum.update(byteBuffer);
+ assertEquals("update(ByteBuffer) failed to update the checksum to the correct value ",
+ expectedChecksum, checksum.getValue());
+ assertEquals(0, byteBuffer.remaining());
+ }
+
+ /**
+ * java.util.zip.Adler32#update(ByteBuffer)
+ */
+ public void test_update$ByteBuffer() {
+ // test methods of java.util.zip.update(ByteBuffer)
+ // Heap ByteBuffer
+ ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[] {1,2,3,4});
+ byteBuffer.position(2);
+ assertChecksumFromByteBuffer(0xc0008, byteBuffer);
+
+ // Direct ByteBuffer
+ byteBuffer.flip();
+ byteBuffer = ByteBuffer.allocateDirect(4).put(byteBuffer);
+ byteBuffer.flip();
+ byteBuffer.position(2);
+ assertChecksumFromByteBuffer(0xc0008, byteBuffer);
+
+ Adler32 checksum = new Adler32();
+ try {
+ checksum.update((ByteBuffer)null);
+ fail();
+ } catch (NullPointerException expected) {}
+ }
+
@Override
protected void setUp() {
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/CRC32Test.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/CRC32Test.java
index 30bdf9f08..3d840cea7 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/CRC32Test.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/CRC32Test.java
@@ -1,13 +1,13 @@
-/*
+/*
* 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.
@@ -16,6 +16,7 @@
*/
package org.apache.harmony.tests.java.util.zip;
+import java.nio.ByteBuffer;
import java.util.zip.CRC32;
public class CRC32Test extends junit.framework.TestCase {
@@ -174,6 +175,39 @@ public void test_updateI() {
2, r);
}
+
+ private void assertChecksumFromByteBuffer(long expectedChecksum, ByteBuffer byteBuffer) {
+ CRC32 checksum = new CRC32();
+ checksum.update(byteBuffer);
+ assertEquals("update(ByteBuffer) failed to update the checksum to the correct value ",
+ expectedChecksum, checksum.getValue());
+ assertEquals(0, byteBuffer.remaining());
+ }
+
+ /**
+ * java.util.zip.CRC32#update(ByteBuffer)
+ */
+ public void test_update$ByteBuffer() {
+ // test methods of java.util.zip.update(ByteBuffer)
+ // Heap ByteBuffer
+ ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[] {1,2,3,4});
+ byteBuffer.position(2);
+ assertChecksumFromByteBuffer(0x6d998525, byteBuffer);
+
+ // Direct ByteBuffer
+ byteBuffer.flip();
+ byteBuffer = ByteBuffer.allocateDirect(4).put(byteBuffer);
+ byteBuffer.flip();
+ byteBuffer.position(2);
+ assertChecksumFromByteBuffer(0x6d998525, byteBuffer);
+
+ CRC32 checksum = new CRC32();
+ try {
+ checksum.update((ByteBuffer)null);
+ fail();
+ } catch (NullPointerException expected) {}
+ }
+
@Override
protected void setUp() {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/DeflaterInputStreamTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/DeflaterInputStreamTest.java
index 7ed59169d..435ffd8c6 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/DeflaterInputStreamTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/DeflaterInputStreamTest.java
@@ -24,11 +24,16 @@
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.DeflaterInputStream;
-
-import junit.framework.TestCase;
import libcore.io.Streams;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector;
+import libcore.junit.util.ResourceLeakageDetector.DisableResourceLeakageDetection;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
-public class DeflaterInputStreamTest extends TestCase {
+public class DeflaterInputStreamTest extends TestCaseWithRules {
+ @Rule
+ public TestRule guardRule = ResourceLeakageDetector.getRule();
private static final String TEST_STR = "Hi,this is a test";
@@ -142,21 +147,24 @@ public void testRead() throws IOException {
}
public void testRead_golden() throws Exception {
- DeflaterInputStream dis = new DeflaterInputStream(is);
- byte[] contents = Streams.readFully(dis);
- assertTrue(Arrays.equals(TEST_STRING_DEFLATED_BYTES, contents));
+ try (DeflaterInputStream dis = new DeflaterInputStream(is)) {
+ byte[] contents = Streams.readFully(dis);
+ assertTrue(Arrays.equals(TEST_STRING_DEFLATED_BYTES, contents));
+ }
- byte[] result = new byte[32];
- dis = new DeflaterInputStream(new ByteArrayInputStream(TEST_STR.getBytes("UTF-8")));
- int count = 0;
- int bytesRead = 0;
- while ((bytesRead = dis.read(result, count, 4)) != -1) {
- count += bytesRead;
+ try (DeflaterInputStream dis = new DeflaterInputStream(
+ new ByteArrayInputStream(TEST_STR.getBytes("UTF-8")))) {
+ byte[] result = new byte[32];
+ int count = 0;
+ int bytesRead;
+ while ((bytesRead = dis.read(result, count, 4)) != -1) {
+ count += bytesRead;
+ }
+ assertEquals(23, count);
+ byte[] splicedResult = new byte[23];
+ System.arraycopy(result, 0, splicedResult, 0, 23);
+ assertTrue(Arrays.equals(TEST_STRING_DEFLATED_BYTES, splicedResult));
}
- assertEquals(23, count);
- byte[] splicedResult = new byte[23];
- System.arraycopy(result, 0, splicedResult, 0, 23);
- assertTrue(Arrays.equals(TEST_STRING_DEFLATED_BYTES, splicedResult));
}
public void testRead_leavesBufUnmodified() throws Exception {
@@ -181,12 +189,16 @@ public void testRead_leavesBufUnmodified() throws Exception {
public void testReadByteArrayIntInt() throws IOException {
byte[] buf1 = new byte[256];
byte[] buf2 = new byte[256];
- DeflaterInputStream dis = new DeflaterInputStream(is);
- assertEquals(23, dis.read(buf1, 0, 256));
- dis = new DeflaterInputStream(is);
- assertEquals(8, dis.read(buf2, 0, 256));
+ try (DeflaterInputStream dis = new DeflaterInputStream(is)) {
+ assertEquals(23, dis.read(buf1, 0, 256));
+ }
+
+ try (DeflaterInputStream dis = new DeflaterInputStream(is)) {
+ assertEquals(8, dis.read(buf2, 0, 256));
+ }
+
is = new ByteArrayInputStream(TEST_STR.getBytes("UTF-8"));
- dis = new DeflaterInputStream(is);
+ DeflaterInputStream dis = new DeflaterInputStream(is);
assertEquals(1, dis.available());
assertEquals(120, dis.read());
assertEquals(1, dis.available());
@@ -300,15 +312,23 @@ public void testReset() throws IOException {
*/
public void testSkip() throws IOException {
byte[] buf = new byte[1024];
- DeflaterInputStream dis = new DeflaterInputStream(is);
- assertEquals(1, dis.available());
- dis.skip(1);
- assertEquals(1, dis.available());
- assertEquals(22, dis.read(buf, 0, 1024));
- assertEquals(0, dis.available());
- assertEquals(0, dis.available());
+ try (DeflaterInputStream dis = new DeflaterInputStream(is)) {
+ assertEquals(1, dis.available());
+ dis.skip(1);
+ assertEquals(1, dis.available());
+ assertEquals(22, dis.read(buf, 0, 1024));
+ assertEquals(0, dis.available());
+ assertEquals(0, dis.available());
+ is = new ByteArrayInputStream(TEST_STR.getBytes("UTF-8"));
+ }
+
is = new ByteArrayInputStream(TEST_STR.getBytes("UTF-8"));
- dis = new DeflaterInputStream(is);
+ try (DeflaterInputStream dis = new DeflaterInputStream(is)) {
+ assertEquals(23, dis.skip(Long.MAX_VALUE));
+ assertEquals(0, dis.available());
+ }
+
+ DeflaterInputStream dis = new DeflaterInputStream(is);
assertEquals(1, dis.available());
dis.skip(56);
assertEquals(0, dis.available());
@@ -324,19 +344,20 @@ public void testSkip() throws IOException {
} catch (IOException e) {
// expected
}
-
- is = new ByteArrayInputStream(TEST_STR.getBytes("UTF-8"));
- dis = new DeflaterInputStream(is);
- assertEquals(23, dis.skip(Long.MAX_VALUE));
- assertEquals(0, dis.available());
}
/**
* DeflaterInputStream#DeflaterInputStream(InputStream)
*/
- public void testDeflaterInputStreamInputStream() {
+ @DisableResourceLeakageDetection(
+ why = "DeflaterInputStream does not clean up the default Deflater created in the"
+ + " constructor if the constructor fails; i.e. constructor calls"
+ + " this(..., new Deflater(), ...) and that constructor fails but does not know"
+ + " that it needs to call Deflater.end() as the caller has no access to it",
+ bug = "31798154")
+ public void testDeflaterInputStreamInputStream() throws IOException {
// ok
- new DeflaterInputStream(is);
+ new DeflaterInputStream(is).close();
// fail
try {
new DeflaterInputStream(null);
@@ -356,21 +377,26 @@ public void testDataFormatException() {
/**
* DeflaterInputStream#DeflaterInputStream(InputStream, Deflater)
*/
- public void testDeflaterInputStreamInputStreamDeflater() {
+ public void testDeflaterInputStreamInputStreamDeflater() throws IOException {
// ok
- new DeflaterInputStream(is, new Deflater());
- // fail
- try {
- new DeflaterInputStream(is, null);
- fail("should throw NullPointerException");
- } catch (NullPointerException e) {
- // expected
- }
+ Deflater deflater = new Deflater();
try {
- new DeflaterInputStream(null, new Deflater());
- fail("should throw NullPointerException");
- } catch (NullPointerException e) {
- // expected
+ new DeflaterInputStream(is, deflater).close();
+ // fail
+ try {
+ new DeflaterInputStream(is, null);
+ fail("should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ try {
+ new DeflaterInputStream(null, deflater);
+ fail("should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ } finally {
+ deflater.end();
}
}
@@ -379,37 +405,42 @@ public void testDeflaterInputStreamInputStreamDeflater() {
*/
public void testDeflaterInputStreamInputStreamDeflaterInt() {
// ok
- new DeflaterInputStream(is, new Deflater(), 1024);
- // fail
+ Deflater deflater = new Deflater();
try {
- new DeflaterInputStream(is, null, 1024);
- fail("should throw NullPointerException");
- } catch (NullPointerException e) {
- // expected
- }
- try {
- new DeflaterInputStream(null, new Deflater(), 1024);
- fail("should throw NullPointerException");
- } catch (NullPointerException e) {
- // expected
- }
- try {
- new DeflaterInputStream(is, new Deflater(), -1);
- fail("should throw IllegalArgumentException");
- } catch (IllegalArgumentException e) {
- // expected
- }
- try {
- new DeflaterInputStream(null, new Deflater(), -1);
- fail("should throw NullPointerException");
- } catch (NullPointerException e) {
- // expected
- }
- try {
- new DeflaterInputStream(is, null, -1);
- fail("should throw NullPointerException");
- } catch (NullPointerException e) {
- // expected
+ new DeflaterInputStream(is, deflater, 1024);
+ // fail
+ try {
+ new DeflaterInputStream(is, null, 1024);
+ fail("should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ try {
+ new DeflaterInputStream(null, deflater, 1024);
+ fail("should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ try {
+ new DeflaterInputStream(is, deflater, -1);
+ fail("should throw IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ new DeflaterInputStream(null, deflater, -1);
+ fail("should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ try {
+ new DeflaterInputStream(is, null, -1);
+ fail("should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ } finally {
+ deflater.end();
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/DeflaterOutputStreamTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/DeflaterOutputStreamTest.java
index e4be19824..30defe239 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/DeflaterOutputStreamTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/DeflaterOutputStreamTest.java
@@ -26,10 +26,15 @@
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector;
+import libcore.junit.util.ResourceLeakageDetector.DisableResourceLeakageDetection;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
-import junit.framework.TestCase;
-
-public class DeflaterOutputStreamTest extends TestCase {
+public class DeflaterOutputStreamTest extends TestCaseWithRules {
+ @Rule
+ public TestRule guardRule = ResourceLeakageDetector.getRule();
private class MyDeflaterOutputStream extends DeflaterOutputStream {
boolean deflateFlag = false;
@@ -105,6 +110,7 @@ public void test_ConstructorLjava_io_OutputStreamLjava_util_zip_Deflater() throw
dos.write(byteArray);
dos.close();
f1.delete();
+ defl.end();
}
/**
@@ -169,19 +175,27 @@ public void test_ConstructorLjava_io_OutputStreamLjava_util_zip_DeflaterI()
dos.write(byteArray);
dos.close();
f1.delete();
+ defl.end();
}
/**
* java.util.zip.DeflaterOutputStream#close()
*/
+ @DisableResourceLeakageDetection(
+ why = "DeflaterOutputStream.close() does not work properly if finish() throws an"
+ + " exception; DeflaterOutputStream.finish() throws an exception if the"
+ + " underlying OutputStream has been closed and the Deflater still has data to"
+ + " write.",
+ bug = "31797037")
public void test_close() throws Exception {
File f1 = File.createTempFile("close", ".tst");
- InflaterInputStream iis = new InflaterInputStream(new FileInputStream(f1));
- try {
- iis.read();
- fail("EOFException Not Thrown");
- } catch (EOFException e) {
+ try (InflaterInputStream iis = new InflaterInputStream(new FileInputStream(f1))) {
+ try {
+ iis.read();
+ fail("EOFException Not Thrown");
+ } catch (EOFException e) {
+ }
}
FileOutputStream fos = new FileOutputStream(f1);
@@ -190,16 +204,15 @@ public void test_close() throws Exception {
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());
- assertEquals("Incorrect Byte Returned.", 4, iis.read());
- assertEquals("Incorrect Byte Returned.", 6, iis.read());
- assertEquals("Incorrect Byte Returned.", -1, iis.read());
- assertEquals("Incorrect Byte Returned.", -1, iis.read());
- iis.close();
+ try (InflaterInputStream 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());
+ assertEquals("Incorrect Byte Returned.", 4, iis.read());
+ assertEquals("Incorrect Byte Returned.", 6, iis.read());
+ assertEquals("Incorrect Byte Returned.", -1, iis.read());
+ assertEquals("Incorrect Byte Returned.", -1, iis.read());
+ }
// Not sure if this test will stay.
FileOutputStream fos2 = new FileOutputStream(f1);
@@ -255,8 +268,8 @@ public void test_finish() throws Exception {
// Test for writing with a new FileOutputStream using the same
// DeflaterOutputStream.
FileOutputStream fos2 = new FileOutputStream(f1);
- dos = new DeflaterOutputStream(fos2);
- dos.write(1);
+ DeflaterOutputStream dos4 = new DeflaterOutputStream(fos2);
+ dos4.write(1);
// Test for writing to FileOutputStream fos1, which should be open.
fos1.write(("testing").getBytes());
@@ -273,17 +286,22 @@ public void test_finish() throws Exception {
fail("IOException not thrown");
} catch (IOException e) {
}
+ dos3.close();
- // dos.close() won't close fos1 because it has been re-assigned to
- // fos2
- fos1.close();
dos.close();
+ dos4.close();
f1.delete();
}
/**
* java.util.zip.DeflaterOutputStream#write(int)
*/
+ @DisableResourceLeakageDetection(
+ why = "DeflaterOutputStream.close() does not work properly if finish() throws an"
+ + " exception; DeflaterOutputStream.finish() throws an exception if the"
+ + " underlying OutputStream has been closed and the Deflater still has data to"
+ + " write.",
+ bug = "31797037")
public void test_writeI() throws Exception {
File f1 = File.createTempFile("writeIL", ".tst");
FileOutputStream fos = new FileOutputStream(f1);
@@ -313,6 +331,12 @@ public void test_writeI() throws Exception {
fail("IOException not thrown");
} catch (IOException e) {
}
+ // Close to try and free up the resources.
+ try {
+ dos2.close();
+ fail("IOException not thrown");
+ } catch (IOException e) {
+ }
f1.delete();
}
@@ -320,6 +344,12 @@ public void test_writeI() throws Exception {
/**
* java.util.zip.DeflaterOutputStream#write(byte[], int, int)
*/
+ @DisableResourceLeakageDetection(
+ why = "DeflaterOutputStream.close() does not work properly if finish() throws an"
+ + " exception; DeflaterOutputStream.finish() throws an exception if the"
+ + " underlying OutputStream has been closed and the Deflater still has data to"
+ + " write.",
+ bug = "31797037")
public void test_write$BII() throws Exception {
byte byteArray[] = { 1, 3, 4, 7, 8, 3, 6 };
@@ -384,6 +414,12 @@ public void test_writeI() throws Exception {
fail("IOException not thrown");
} catch (IOException e) {
}
+ // Close to try and free up the resources.
+ try {
+ dos3.close();
+ fail("IOException not thrown");
+ } catch (IOException e) {
+ }
f2.delete();
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/DeflaterTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/DeflaterTest.java
index 75e4a643b..1ba418759 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/DeflaterTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/DeflaterTest.java
@@ -23,11 +23,15 @@
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
-
-import junit.framework.TestCase;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
import tests.support.resource.Support_Resources;
-public class DeflaterTest extends TestCase {
+public class DeflaterTest extends TestCaseWithRules {
+ @Rule
+ public TestRule guardRule = ResourceLeakageDetector.getRule();
class MyDeflater extends Deflater {
MyDeflater() {
@@ -339,6 +343,7 @@ public void test_getTotalOut() {
x += defl.deflate(outPutBuf);
}
assertEquals(x, defl.getTotalOut());
+ defl.end();
}
/**
@@ -438,6 +443,7 @@ public void test_reset() {
}
assertEquals(0, outPutInf[curArray.length]);
}
+ defl.end();
}
/**
@@ -539,6 +545,7 @@ public void test_reset() {
} catch (ArrayIndexOutOfBoundsException e) {
}
}
+ defl.end();
}
/**
@@ -629,6 +636,7 @@ public void test_reset() {
} catch (ArrayIndexOutOfBoundsException e) {
}
}
+ defl.end();
}
/**
@@ -673,8 +681,8 @@ public void test_setLevelI() throws Exception {
}
// testing boundaries
+ Deflater boundDefl = new Deflater();
try {
- Deflater boundDefl = new Deflater();
// Level must be between 0-9
boundDefl.setLevel(-2);
fail(
@@ -682,12 +690,12 @@ public void test_setLevelI() throws Exception {
} catch (IllegalArgumentException e) {
}
try {
- Deflater boundDefl = new Deflater();
boundDefl.setLevel(10);
fail(
"IllegalArgumentException not thrown when setting level to a number > 9.");
} catch (IllegalArgumentException e) {
}
+ boundDefl.end();
}
/**
@@ -742,13 +750,13 @@ public void test_setStrategyI() throws Exception {
}
// Attempting to setStrategy to an invalid value
+ Deflater defl = new Deflater();
try {
- Deflater defl = new Deflater();
defl.setStrategy(-412);
- fail(
- "IllegalArgumentException not thrown when setting strategy to an invalid value.");
+ fail("IllegalArgumentException not thrown when setting strategy to an invalid value.");
} catch (IllegalArgumentException e) {
}
+ defl.end();
}
/**
@@ -775,6 +783,8 @@ public void test_Constructor() throws Exception {
// creating a Deflater using the DEFAULT_COMPRESSION as the int
MyDeflater mdefl = new MyDeflater();
+ mdefl.end();
+
mdefl = new MyDeflater(mdefl.getDefCompression());
outPutBuf = new byte[500];
mdefl.setInput(byteArray);
@@ -866,31 +876,31 @@ public void test_ConstructorIZ() throws Exception {
} catch (DataFormatException e) {
r = 1;
}
+ infl.end();
assertEquals("header option did not correspond", 1, r);
// testing boundaries
+ Deflater boundDefl = new Deflater();
try {
- Deflater boundDefl = new Deflater();
// Level must be between 0-9
boundDefl.setLevel(-2);
fail("IllegalArgumentException not thrown when setting level to a number < 0.");
} catch (IllegalArgumentException e) {
}
try {
- Deflater boundDefl = new Deflater();
boundDefl.setLevel(10);
fail("IllegalArgumentException not thrown when setting level to a number > 9.");
} catch (IllegalArgumentException e) {
}
-
+ boundDefl.end();
try {
- Deflater boundDefl = new Deflater(-2, true);
+ new Deflater(-2, true).end();
fail("IllegalArgumentException not thrown when passing level to a number < 0.");
} catch (IllegalArgumentException e) {
}
try {
- Deflater boundDefl = new Deflater(10, true);
+ new Deflater(10, true).end();
fail("IllegalArgumentException not thrown when passing level to a number > 9.");
} catch (IllegalArgumentException e) {
}
@@ -935,19 +945,19 @@ public void test_ConstructorI() throws Exception {
defl.end();
// testing boundaries
+ Deflater boundDefl = new Deflater();
try {
- Deflater boundDefl = new Deflater();
// Level must be between 0-9
boundDefl.setLevel(-2);
fail("IllegalArgumentException not thrown when setting level to a number < 0.");
} catch (IllegalArgumentException e) {
}
try {
- Deflater boundDefl = new Deflater();
boundDefl.setLevel(10);
fail("IllegalArgumentException not thrown when setting level to a number > 9.");
} catch (IllegalArgumentException e) {
}
+ boundDefl.end();
}
private void helper_end_test(Deflater defl, String desc) {
@@ -1061,6 +1071,7 @@ public void test_needsDictionary() {
assertEquals(0, inf.getTotalOut());
assertEquals(0, inf.getBytesRead());
assertEquals(0, inf.getBytesWritten());
+ inf.end();
}
/**
@@ -1087,6 +1098,7 @@ public void test_getBytesRead() throws DataFormatException,
assertEquals(14, def.getTotalIn());
assertEquals(compressedDataLength, def.getTotalOut());
assertEquals(14, def.getBytesRead());
+ def.end();
}
/**
@@ -1113,6 +1125,7 @@ public void test_getBytesWritten() throws DataFormatException,
assertEquals(14, def.getTotalIn());
assertEquals(compressedDataLength, def.getTotalOut());
assertEquals(compressedDataLength, def.getBytesWritten());
+ def.end();
}
//Regression Test for HARMONY-2481
@@ -1125,5 +1138,6 @@ public void test_deflate_beforeSetInput() throws Exception {
for (int i = 0; i < expectedBytes.length; i++) {
assertEquals(expectedBytes[i], buffer[i]);
}
+ deflater.end();
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/GZIPInputStreamTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/GZIPInputStreamTest.java
index 567189df0..4f44ec077 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/GZIPInputStreamTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/GZIPInputStreamTest.java
@@ -27,10 +27,17 @@
import java.util.zip.Checksum;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
-
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector;
+import libcore.junit.util.ResourceLeakageDetector.DisableResourceLeakageDetection;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
import tests.support.resource.Support_Resources;
-public class GZIPInputStreamTest extends junit.framework.TestCase {
+public class GZIPInputStreamTest extends TestCaseWithRules {
+ @Rule
+ public TestRule guardRule = ResourceLeakageDetector.getRule();
+
File resources;
class TestGZIPInputStream extends GZIPInputStream {
@@ -76,6 +83,12 @@ public void test_ConstructorLjava_io_InputStream() {
* @tests java.util.zip.GZIPInputStream#GZIPInputStream(java.io.InputStream,
*int)
*/
+ @DisableResourceLeakageDetection(
+ why = "InflaterInputStream does not clean up the default Inflater created in the"
+ + " constructor if the constructor fails; i.e. constructor calls"
+ + " this(..., new Inflater(), ...) and that constructor fails but does not know"
+ + " that it needs to call Inflater.end() as the caller has no access to it",
+ bug = "31798154")
public void test_ConstructorLjava_io_InputStreamI() {
// test method java.util.zip.GZIPInputStream.constructorI
try {
@@ -162,68 +175,71 @@ public void test_ConstructorLjava_io_InputStreamI() {
out.write(test);
out.close();
byte[] comp = bout.toByteArray();
- GZIPInputStream gin2 = new GZIPInputStream(new ByteArrayInputStream(
- comp), 512);
- int total = 0;
- while ((result = gin2.read(test)) != -1) {
- total += result;
+ int total;
+ try (GZIPInputStream gin2 = new GZIPInputStream(new ByteArrayInputStream(comp), 512)) {
+ total = 0;
+ while ((result = gin2.read(test)) != -1) {
+ total += result;
+ }
+ assertEquals("Should return -1", -1, gin2.read());
}
- assertEquals("Should return -1", -1, gin2.read());
- gin2.close();
assertEquals("Incorrectly decompressed", test.length, total);
- gin2 = new GZIPInputStream(new ByteArrayInputStream(comp), 512);
- total = 0;
- while ((result = gin2.read(new byte[200])) != -1) {
- total += result;
+ try (GZIPInputStream gin2 = new GZIPInputStream(new ByteArrayInputStream(comp), 512)) {
+ total = 0;
+ while ((result = gin2.read(new byte[200])) != -1) {
+ total += result;
+ }
+ assertEquals("Should return -1", -1, gin2.read());
}
- assertEquals("Should return -1", -1, gin2.read());
- gin2.close();
assertEquals("Incorrectly decompressed", test.length, total);
- gin2 = new GZIPInputStream(new ByteArrayInputStream(comp), 516);
- total = 0;
- while ((result = gin2.read(new byte[200])) != -1) {
- total += result;
+ try (GZIPInputStream gin2 = new GZIPInputStream(new ByteArrayInputStream(comp), 516)) {
+ total = 0;
+ while ((result = gin2.read(new byte[200])) != -1) {
+ total += result;
+ }
+ assertEquals("Should return -1", -1, gin2.read());
}
- assertEquals("Should return -1", -1, gin2.read());
- gin2.close();
assertEquals("Incorrectly decompressed", test.length, total);
comp[40] = 0;
- gin2 = new GZIPInputStream(new ByteArrayInputStream(comp), 512);
- boolean exception = false;
- try {
- while (gin2.read(test) != -1) {
- ;
+ try (GZIPInputStream gin2 = new GZIPInputStream(new ByteArrayInputStream(comp), 512)) {
+ boolean exception = false;
+ try {
+ while (gin2.read(test) != -1) {
+ ;
+ }
+ } catch (IOException e) {
+ exception = true;
}
- } catch (IOException e) {
- exception = true;
+ assertTrue("Exception expected", exception);
}
- assertTrue("Exception expected", exception);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- GZIPOutputStream zipout = new GZIPOutputStream(baos);
- zipout.write(test);
- zipout.close();
- outBuf = new byte[530];
- GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(baos.toByteArray()));
- try {
- in.read(outBuf, 530, 1);
- fail("Test failed IOOBE was not thrown");
- } catch (IndexOutOfBoundsException e) {
+ try (GZIPOutputStream zipout = new GZIPOutputStream(baos)) {
+ zipout.write(test);
}
- while (true) {
- result = in.read(outBuf, 0, 5);
- if (result == -1) {
- //"EOF was reached";
- break;
+ outBuf = new byte[530];
+ try (GZIPInputStream in = new GZIPInputStream(
+ new ByteArrayInputStream(baos.toByteArray()))) {
+ try {
+ in.read(outBuf, 530, 1);
+ fail("Test failed IOOBE was not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ while (true) {
+ result = in.read(outBuf, 0, 5);
+ if (result == -1) {
+ //"EOF was reached";
+ break;
+ }
}
+ result = -10;
+ result = in.read(null, 100, 1);
+ result = in.read(outBuf, -100, 1);
+ result = in.read(outBuf, -1, 1);// 100, 1);
}
- result = -10;
- result = in.read(null, 100, 1);
- result = in.read(outBuf, -100, 1);
- result = in.read(outBuf, -1, 1);// 100, 1);
}
/**
@@ -264,7 +280,6 @@ public void test_close() {
* @tests java.util.zip.GZIPInputStream#read()
*/
public void test_read() throws IOException {
- GZIPInputStream gis = null;
int result = 0;
byte[] buffer = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
File f = new File(resources.getAbsolutePath() + "test.gz");
@@ -278,8 +293,9 @@ public void test_read() throws IOException {
gout.finish();
out.write(1);
out.close();
+ gout.close();
- gis = new GZIPInputStream(new FileInputStream(f));
+ GZIPInputStream gis = new GZIPInputStream(new FileInputStream(f));
buffer = new byte[100];
gis.read(buffer);
result = gis.read();
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/GZIPOutputStreamTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/GZIPOutputStreamTest.java
index 30a94f06d..d6c87a92f 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/GZIPOutputStreamTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/GZIPOutputStreamTest.java
@@ -25,8 +25,14 @@
import java.util.zip.Checksum;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
-public class GZIPOutputStreamTest extends junit.framework.TestCase {
+public class GZIPOutputStreamTest extends TestCaseWithRules {
+ @Rule
+ public TestRule guardRule = ResourceLeakageDetector.getRule();
class TestGZIPOutputStream extends GZIPOutputStream {
TestGZIPOutputStream(OutputStream out) throws IOException {
@@ -169,9 +175,12 @@ public void test_close() {
public void testSyncFlush() throws IOException {
PipedOutputStream pout = new PipedOutputStream();
PipedInputStream pin = new PipedInputStream(pout);
+ // Must create in this order so that GZIPOutputStream writes the header before
+ // GZIPInputStream tries to read it otherwise it will deadlock with GZIPInputStream waiting
+ // for the header to be written but it cannot be written until after GZIPInputStream has
+ // read it.
GZIPOutputStream out = new GZIPOutputStream(pout, true /* syncFlush */);
GZIPInputStream in = new GZIPInputStream(pin);
-
out.write(1);
out.write(2);
out.write(3);
@@ -183,5 +192,7 @@ public void testSyncFlush() throws IOException {
assertEquals(1, in.read());
assertEquals(2, in.read());
assertEquals(3, in.read());
+ out.close();
+ in.close();
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/InflaterInputStreamTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/InflaterInputStreamTest.java
index 6930c59f4..6109762c8 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/InflaterInputStreamTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/InflaterInputStreamTest.java
@@ -18,19 +18,22 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
import java.io.File;
import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
-
-import junit.framework.TestCase;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
import tests.support.resource.Support_Resources;
-public class InflaterInputStreamTest extends TestCase {
+public class InflaterInputStreamTest extends TestCaseWithRules {
+ @Rule
+ public TestRule guardRule = ResourceLeakageDetector.getRule();
// files hyts_construO,hyts_construOD,hyts_construODI needs to be
// included as resources
@@ -116,51 +119,54 @@ public void test_ConstructorLjava_io_InputStreamLjava_util_zip_InflaterI() throw
*java.util.zip.Inflater, int)
*/
public void test_ConstructorLjava_io_InputStreamLjava_util_zip_InflaterI_1() throws IOException {
- InputStream infile = Support_Resources.getStream("hyts_construODI.bin");
- Inflater inflate = new Inflater();
- InflaterInputStream inflatIP = null;
- try {
- inflatIP = new InflaterInputStream(infile, null, 1);
- fail("NullPointerException expected");
- } catch (NullPointerException NPE) {
- //expected
- }
+ try (InputStream infile = Support_Resources.getStream("hyts_construODI.bin")) {
+ Inflater inflate = new Inflater();
+ try {
+ new InflaterInputStream(infile, null, 1);
+ fail("NullPointerException expected");
+ } catch (NullPointerException NPE) {
+ //expected
+ }
- try {
- inflatIP = new InflaterInputStream(null, inflate, 1);
- fail("NullPointerException expected");
- } catch (NullPointerException NPE) {
- //expected
- }
+ try {
+ new InflaterInputStream(null, inflate, 1);
+ fail("NullPointerException expected");
+ } catch (NullPointerException NPE) {
+ //expected
+ }
- try {
- inflatIP = new InflaterInputStream(infile, inflate, -1);
- fail("IllegalArgumentException expected");
- } catch (IllegalArgumentException iae) {
- //expected
+ try {
+ new InflaterInputStream(infile, inflate, -1);
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException iae) {
+ //expected
+ }
+ inflate.end();
}
}
/**
* java.util.zip.InflaterInputStream#mark(int)
*/
- public void test_markI() {
+ public void test_markI() throws IOException {
InputStream is = new ByteArrayInputStream(new byte[10]);
- InflaterInputStream iis = new InflaterInputStream(is);
- // mark do nothing, do no check
- iis.mark(0);
- iis.mark(-1);
- iis.mark(10000000);
+ try (InflaterInputStream iis = new InflaterInputStream(is)) {
+ // mark do nothing, do no check
+ iis.mark(0);
+ iis.mark(-1);
+ iis.mark(10000000);
+ }
}
/**
* java.util.zip.InflaterInputStream#markSupported()
*/
- public void test_markSupported() {
+ public void test_markSupported() throws IOException {
InputStream is = new ByteArrayInputStream(new byte[10]);
- InflaterInputStream iis = new InflaterInputStream(is);
- assertFalse(iis.markSupported());
- assertTrue(is.markSupported());
+ try (InflaterInputStream iis = new InflaterInputStream(is)) {
+ assertFalse(iis.markSupported());
+ assertTrue(is.markSupported());
+ }
}
/**
@@ -228,37 +234,40 @@ public void test_read_LBII() throws IOException {
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());
+ try (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());
+ try (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());
+ try (InputStream in = new InflaterInputStream(new ByteArrayInputStream(deflated))) {
+ assertEquals(-1, in.read());
+ assertEquals(-1, in.read());
+ assertEquals(0, in.available());
+ }
}
/**
@@ -273,25 +282,26 @@ public void testAvailableEmptySource() throws Exception {
test[i] = (byte) (256 - i);
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- DeflaterOutputStream dos = new DeflaterOutputStream(baos);
- dos.write(test);
- dos.close();
- InputStream is = new ByteArrayInputStream(baos.toByteArray());
- InflaterInputStream iis = new InflaterInputStream(is);
- byte[] outBuf = new byte[530];
- int result = 0;
- while (true) {
- result = iis.read(outBuf, 0, 5);
- if (result == -1) {
- //"EOF was reached";
- break;
- }
+ try (DeflaterOutputStream dos = new DeflaterOutputStream(baos)) {
+ dos.write(test);
}
- try {
- iis.read(outBuf, -1, 10);
- fail("should throw IOOBE.");
- } catch (IndexOutOfBoundsException e) {
- // expected;
+ try (InflaterInputStream iis = new InflaterInputStream(
+ new ByteArrayInputStream(baos.toByteArray()))) {
+ byte[] outBuf = new byte[530];
+ int result = 0;
+ while (true) {
+ result = iis.read(outBuf, 0, 5);
+ if (result == -1) {
+ //"EOF was reached";
+ break;
+ }
+ }
+ try {
+ iis.read(outBuf, -1, 10);
+ fail("should throw IOOBE.");
+ } catch (IndexOutOfBoundsException e) {
+ // expected;
+ }
}
}
@@ -317,28 +327,28 @@ public void testAvailableEmptySource() throws Exception {
Support_Resources.copyFile(resources, null, "Broken_manifest.jar");
FileInputStream fis = new FileInputStream(new File(resources,
"Broken_manifest.jar"));
- InflaterInputStream iis = new InflaterInputStream(fis);
- byte[] outBuf = new byte[530];
-
- try {
- iis.read();
- fail("IOException expected.");
- } catch (IOException ee) {
- // expected
+ try (InflaterInputStream iis = new InflaterInputStream(fis)) {
+ try {
+ iis.read();
+ fail("IOException expected.");
+ } catch (IOException ee) {
+ // expected
+ }
}
}
/**
* java.util.zip.InflaterInputStream#reset()
*/
- public void test_reset() {
+ public void test_reset() throws IOException {
InputStream is = new ByteArrayInputStream(new byte[10]);
- InflaterInputStream iis = new InflaterInputStream(is);
- try {
- iis.reset();
- fail("Should throw IOException");
- } catch (IOException e) {
- // correct
+ try (InflaterInputStream iis = new InflaterInputStream(is)) {
+ try {
+ iis.reset();
+ fail("Should throw IOException");
+ } catch (IOException e) {
+ // correct
+ }
}
}
@@ -390,11 +400,9 @@ public void test_skipJ2() throws IOException {
byte orgBuffer[] = { 1, 3, 4, 7, 8 };
// testing for negative input to skip
- InputStream infile = Support_Resources
- .getStream("hyts_construOD.bin");
+ InputStream infile = Support_Resources.getStream("hyts_construOD.bin");
Inflater inflate = new Inflater();
- InflaterInputStream inflatIP = new InflaterInputStream(infile,
- inflate, 10);
+ InflaterInputStream inflatIP = new InflaterInputStream(infile, inflate, 10);
long skip;
try {
skip = inflatIP.skip(Integer.MIN_VALUE);
@@ -405,32 +413,33 @@ public void test_skipJ2() throws IOException {
inflatIP.close();
// testing for number of bytes greater than input.
- InputStream infile2 = Support_Resources
- .getStream("hyts_construOD.bin");
- InflaterInputStream inflatIP2 = new InflaterInputStream(infile2);
+ InputStream infile2 = Support_Resources.getStream("hyts_construOD.bin");
+ try (InflaterInputStream inflatIP2 = new InflaterInputStream(infile2)) {
- // looked at how many bytes the skip skipped. It is
- // 5 and its supposed to be the entire input stream.
+ // looked at how many bytes the skip skipped. It is
+ // 5 and its supposed to be the entire input stream.
- skip = inflatIP2.skip(Integer.MAX_VALUE);
- // System.out.println(skip);
- assertEquals("method skip() returned wrong number of bytes skipped",
- 5, skip);
+ skip = inflatIP2.skip(Integer.MAX_VALUE);
+ // System.out.println(skip);
+ assertEquals("method skip() returned wrong number of bytes skipped",
+ 5, skip);
+ inflatIP2.close();
+ }
// test for skipping of 2 bytes
- InputStream infile3 = Support_Resources
- .getStream("hyts_construOD.bin");
- InflaterInputStream inflatIP3 = new InflaterInputStream(infile3);
- skip = inflatIP3.skip(2);
- assertEquals("the number of bytes returned by skip did not correspond with its input parameters",
- 2, skip);
- int i = 0;
- result = 0;
- while ((result = inflatIP3.read()) != -1) {
- buffer[i] = result;
- i++;
+ InputStream infile3 = Support_Resources.getStream("hyts_construOD.bin");
+ try (InflaterInputStream inflatIP3 = new InflaterInputStream(infile3)) {
+ skip = inflatIP3.skip(2);
+ assertEquals(
+ "the number of bytes returned by skip did not correspond with its input parameters",
+ 2, skip);
+ int i = 0;
+ result = 0;
+ while ((result = inflatIP3.read()) != -1) {
+ buffer[i] = result;
+ i++;
+ }
}
- inflatIP2.close();
for (int j = 2; j < orgBuffer.length; j++) {
assertEquals(
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/InflaterOutputStreamTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/InflaterOutputStreamTest.java
index ab856b11a..dcde2428a 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/InflaterOutputStreamTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/InflaterOutputStreamTest.java
@@ -23,10 +23,15 @@
import java.util.zip.Inflater;
import java.util.zip.InflaterOutputStream;
import java.util.zip.ZipException;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector;
+import libcore.junit.util.ResourceLeakageDetector.DisableResourceLeakageDetection;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
-import junit.framework.TestCase;
-
-public class InflaterOutputStreamTest extends TestCase {
+public class InflaterOutputStreamTest extends TestCaseWithRules {
+ @Rule
+ public TestRule guardRule = ResourceLeakageDetector.getRule();
private ByteArrayOutputStream os = new ByteArrayOutputStream();
@@ -37,8 +42,14 @@ public class InflaterOutputStreamTest extends TestCase {
/**
* java.util.zip.InflaterOutputStream#InflaterOutputStream(java.io.OutputStream)
*/
+ @DisableResourceLeakageDetection(
+ why = "InflaterOutputStream does not clean up the default Inflater created in the"
+ + " constructor if the constructor fails; i.e. constructor calls"
+ + " this(..., new Inflater(), ...) and that constructor fails but does not know"
+ + " that it needs to call Inflater.end() as the caller has no access to it",
+ bug = "31798154")
public void test_ConstructorLjava_io_OutputStream() throws IOException {
- new InflaterOutputStream(os);
+ new InflaterOutputStream(os).close();
try {
new InflaterOutputStream(null);
@@ -51,11 +62,12 @@ public void test_ConstructorLjava_io_OutputStream() throws IOException {
/**
* java.util.zip.InflaterOutputStream#InflaterOutputStream(java.io.OutputStream, Inflater)
*/
- public void test_ConstructorLjava_io_OutputStreamLjava_util_zip_Inflater() {
- new InflaterOutputStream(os, new Inflater());
+ public void test_ConstructorLjava_io_OutputStreamLjava_util_zip_Inflater() throws IOException {
+ Inflater inflater = new Inflater();
+ new InflaterOutputStream(os, inflater).close();
try {
- new InflaterOutputStream(null, new Inflater());
+ new InflaterOutputStream(null, inflater);
fail("Should throw NullPointerException");
} catch (NullPointerException e) {
// expected
@@ -67,13 +79,16 @@ public void test_ConstructorLjava_io_OutputStreamLjava_util_zip_Inflater() {
} catch (NullPointerException e) {
// expected
}
+
+ inflater.end();
}
/**
* java.util.zip.InflaterOutputStream#InflaterOutputStream(java.io.OutputStream, Inflater, int)
*/
- public void test_ConstructorLjava_io_OutputStreamLjava_util_zip_InflaterI() {
- new InflaterOutputStream(os, new Inflater(), 20);
+ public void test_ConstructorLjava_io_OutputStreamLjava_util_zip_InflaterI() throws IOException {
+ Inflater inflater = new Inflater();
+ new InflaterOutputStream(os, inflater, 20).close();
try {
new InflaterOutputStream(null, null, 10);
@@ -83,7 +98,7 @@ public void test_ConstructorLjava_io_OutputStreamLjava_util_zip_InflaterI() {
}
try {
- new InflaterOutputStream(null, new Inflater(), -1);
+ new InflaterOutputStream(null, inflater, -1);
fail("Should throw NullPointerException");
} catch (NullPointerException e) {
// expected
@@ -104,18 +119,20 @@ public void test_ConstructorLjava_io_OutputStreamLjava_util_zip_InflaterI() {
}
try {
- new InflaterOutputStream(os, new Inflater(), 0);
+ new InflaterOutputStream(os, inflater, 0);
fail("Should throw IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
try {
- new InflaterOutputStream(os, new Inflater(), -10000);
+ new InflaterOutputStream(os, inflater, -10000);
fail("Should throw IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
+
+ inflater.end();
}
/**
@@ -144,6 +161,7 @@ public void test_flush() throws IOException {
ios = new InflaterOutputStream(os);
ios.flush();
ios.flush();
+ ios.close();
}
/**
@@ -165,18 +183,21 @@ public void test_finish() throws IOException {
ios.flush();
ios.flush();
ios.finish();
+ ios.close();
byte[] bytes1 = { 10, 20, 30, 40, 50 };
Deflater defaultDeflater = new Deflater(Deflater.BEST_SPEED);
defaultDeflater.setInput(bytes1);
defaultDeflater.finish();
int length1 = defaultDeflater.deflate(compressedBytes);
+ defaultDeflater.end();
byte[] bytes2 = { 100, 90, 80, 70, 60 };
Deflater bestDeflater = new Deflater(Deflater.BEST_COMPRESSION);
bestDeflater.setInput(bytes2);
bestDeflater.finish();
int length2 = bestDeflater.deflate(compressedBytes, length1, compressedBytes.length - length1);
+ bestDeflater.end();
ios = new InflaterOutputStream(os);
for (int i = 0; i < length1; i++) {
@@ -211,13 +232,14 @@ public void test_write_I() throws IOException {
int length = compressToBytes(testString);
// uncompress the data stored in the compressedBytes
- InflaterOutputStream ios = new InflaterOutputStream(os);
- for (int i = 0; i < length; i++) {
- ios.write(compressedBytes[i]);
- }
+ try (InflaterOutputStream ios = new InflaterOutputStream(os)) {
+ for (int i = 0; i < length; i++) {
+ ios.write(compressedBytes[i]);
+ }
- String result = new String(os.toByteArray());
- assertEquals(testString, result);
+ String result = new String(os.toByteArray());
+ assertEquals(testString, result);
+ }
}
/**
@@ -243,20 +265,25 @@ public void test_write_I_Illegal() throws IOException {
int length = compressToBytes(testString);
// uncompress the data stored in the compressedBytes
- InflaterOutputStream ios = new InflaterOutputStream(os);
- ios.write(compressedBytes, 0, length);
+ try (InflaterOutputStream ios = new InflaterOutputStream(os)) {
+ ios.write(compressedBytes, 0, length);
- String result = new String(os.toByteArray());
- assertEquals(testString, result);
+ String result = new String(os.toByteArray());
+ assertEquals(testString, result);
+ }
}
/**
* java.util.zip.InflaterOutputStream#write(byte[], int, int)
*/
+ @DisableResourceLeakageDetection(
+ why = "InflaterOutputStream.close() does not work properly if finish() throws an"
+ + " exception; finish() throws an exception if the output is invalid.",
+ bug = "31797037")
public void test_write_$BII_Illegal() throws IOException {
// write error compression (ZIP) format
- InflaterOutputStream ios = new InflaterOutputStream(os);
byte[] bytes = { 0, 1, 2, 3 };
+ InflaterOutputStream ios = new InflaterOutputStream(os);
try {
ios.write(bytes, 0, 4);
fail("Should throw ZipException");
@@ -304,70 +331,72 @@ public void test_write_I_Illegal() throws IOException {
// expected
}
- ios = new InflaterOutputStream(os);
- try {
- ios.write(null, 0, 4);
- fail("Should throw NullPointerException");
- } catch (NullPointerException e) {
- // expected
- }
- try {
- ios.write(null, -1, 4);
- fail("Should throw NullPointerException");
- } catch (NullPointerException e) {
- // expected
- }
- try {
- ios.write(null, 0, -4);
- fail("Should throw NullPointerException");
- } catch (NullPointerException e) {
- // expected
- }
- try {
- ios.write(null, 0, 1000);
- fail("Should throw NullPointerException");
- } catch (NullPointerException e) {
- // expected
- }
- try {
- ios.write(bytes, -1, 4);
- fail("Should throw IndexOutOfBoundsException");
- } catch (IndexOutOfBoundsException e) {
- // expected
- }
- try {
- ios.write(bytes, 0, -4);
- fail("Should throw IndexOutOfBoundsException");
- } catch (IndexOutOfBoundsException e) {
- // expected
- }
- try {
- ios.write(bytes, 0, 100);
- fail("Should throw IndexOutOfBoundsException");
- } catch (IndexOutOfBoundsException e) {
- // expected
- }
- try {
- ios.write(bytes, -100, 100);
- fail("Should throw IndexOutOfBoundsException");
- } catch (IndexOutOfBoundsException e) {
- // expected
- }
-
- ios = new InflaterOutputStream(os);
- ios.finish();
-
- try {
- ios.write(bytes, -1, -100);
- fail("Should throw IndexOutOfBoundsException");
- } catch (IndexOutOfBoundsException e) {
- // expected
- }
- try {
- ios.write(null, -1, -100);
- fail("Should throw NullPointerException");
- } catch (NullPointerException e) {
- // expected
+ try (InflaterOutputStream ios2 = new InflaterOutputStream(os)) {
+ try {
+ ios2.write(null, 0, 4);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ try {
+ ios2.write(null, -1, 4);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ try {
+ ios2.write(null, 0, -4);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ try {
+ ios2.write(null, 0, 1000);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ try {
+ ios2.write(bytes, -1, 4);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+ try {
+ ios2.write(bytes, 0, -4);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+ try {
+ ios2.write(bytes, 0, 100);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+ try {
+ ios2.write(bytes, -100, 100);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+ }
+
+ try (InflaterOutputStream ios2 = new InflaterOutputStream(os)) {
+ ios2.finish();
+
+ try {
+ ios2.write(bytes, -1, -100);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+ try {
+ ios2.write(null, -1, -100);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
}
ios = new InflaterOutputStream(os);
@@ -384,9 +413,12 @@ public void test_write_I_Illegal() throws IOException {
private int compressToBytes(String string) {
byte[] input = string.getBytes();
Deflater deflater = new Deflater();
- deflater.setInput(input);
- deflater.finish();
- return deflater.deflate(compressedBytes);
+ try {
+ deflater.setInput(input);
+ deflater.finish();
+ return deflater.deflate(compressedBytes);
+ } finally {
+ deflater.end();
+ }
}
-
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/InflaterTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/InflaterTest.java
index a16fab7e8..a15a5cf30 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/InflaterTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/InflaterTest.java
@@ -27,9 +27,16 @@
import java.util.zip.DeflaterOutputStream;
import java.util.zip.Inflater;
import java.util.zip.ZipException;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
import tests.support.resource.Support_Resources;
-public class InflaterTest extends junit.framework.TestCase {
+public class InflaterTest extends TestCaseWithRules {
+ @Rule
+ public TestRule guardRule = ResourceLeakageDetector.getRule();
+
byte outPutBuff1[] = new byte[500];
byte outPutDiction[] = new byte[500];
@@ -81,6 +88,7 @@ public void test_finished() {
} catch (DataFormatException e) {
fail("Invalid input to be decompressed");
}
+ inflate.end();
for (int i = 0; i < byteArray.length; i++) {
assertEquals(
"Final decompressed data does not equal the original data",
@@ -108,6 +116,7 @@ public void test_getAdler() {
"the checksum value returned by getAdler() is not the same as the checksum returned by creating the adler32 instance",
inflateDiction.getAdler(), checkSumR);
}
+ inflateDiction.end();
}
/**
@@ -123,6 +132,7 @@ public void test_getRemaining() {
assertTrue(
"getRemaining returned zero when there is input in the input buffer",
inflate.getRemaining() != 0);
+ inflate.end();
}
/**
@@ -161,6 +171,8 @@ public void test_getTotalIn() {
assertEquals(
"the total byte in outPutBuf did not equal the byte returned in getTotalIn",
deflate.getTotalOut(), inflate.getTotalIn());
+ deflate.end();
+ inflate.end();
Inflater inflate2 = new Inflater();
int offSet = 0;// seems only can start as 0
@@ -180,6 +192,7 @@ public void test_getTotalIn() {
assertEquals(
"total byte dictated by length did not equal byte returned in getTotalIn",
length, inflate2.getTotalIn());
+ inflate2.end();
}
/**
@@ -246,6 +259,9 @@ public void test_getTotalOut() {
assertEquals(
"the total number of bytes to be compressed does not equal the total bytes decompressed",
deflate.getTotalIn(), inflate.getTotalOut());
+
+ deflate.end();
+ inflate.end();
}
/**
@@ -256,14 +272,15 @@ public void test_getTotalOut() {
byte byteArray[] = { 1, 3, 4, 7, 8, 'e', 'r', 't', 'y', '5' };
byte outPutInf[] = new byte[500];
- Inflater inflate = new Inflater();
try {
+ Inflater inflate = new Inflater();
while (!(inflate.finished())) {
if (inflate.needsInput()) {
inflate.setInput(outPutBuff1);
}
inflate.inflate(outPutInf);
}
+ inflate.end();
} catch (DataFormatException e) {
fail("Invalid input to be decompressed");
}
@@ -293,14 +310,16 @@ public void test_getTotalOut() {
assertEquals(
"the number of input byte from the array did not correspond with getTotalIn - inflate(byte)",
emptyArray.length, defEmpty.getTotalIn());
- Inflater infEmpty = new Inflater();
+ defEmpty.end();
try {
+ Inflater infEmpty = new Inflater();
while (!(infEmpty.finished())) {
if (infEmpty.needsInput()) {
infEmpty.setInput(outPutBuf);
}
infEmpty.inflate(outPutInf);
}
+ infEmpty.end();
} catch (DataFormatException e) {
fail("Invalid input to be decompressed");
}
@@ -476,8 +495,8 @@ public void testInflateZero() throws Exception {
public void test_Constructor() {
// test method of java.util.zip.inflater.Inflater()
Inflater inflate = new Inflater();
- assertNotNull("failed to create the instance of inflater",
- inflate);
+ assertNotNull("failed to create the instance of inflater", inflate);
+ inflate.end();
}
/**
@@ -501,15 +520,15 @@ public void test_ConstructorZ() {
inflate.inflate(outPutInf);
}
for (int i = 0; i < byteArray.length; i++) {
- assertEquals("the output array from inflate should contain 0 because the header of inflate and deflate did not match, but this failed",
+ assertEquals("the output array from inflate should contain 0 because the"
+ + " header of inflate and deflate did not match, but this failed",
0, outPutBuff1[i]);
}
} catch (DataFormatException e) {
r = 1;
}
- assertEquals("Error: exception should be thrown because of header inconsistency",
- 1, r);
-
+ assertEquals("Error: exception should be thrown because of header inconsistency", 1, r);
+ inflate.end();
}
/**
@@ -534,15 +553,17 @@ public void test_needsDictionary() {
assertTrue(
"method needsDictionary returned false when dictionary was used in deflater",
inflateDiction.needsDictionary());
+ inflateDiction.end();
// testing without dictionary
- Inflater inflate = new Inflater();
try {
+ Inflater inflate = new Inflater();
inflate.setInput(outPutBuff1);
inflate.inflate(outPutInf);
assertFalse(
"method needsDictionary returned true when dictionary was not used in deflater",
inflate.needsDictionary());
+ inflate.end();
} catch (DataFormatException e) {
fail(
"Input to inflate is invalid or corrupted - needsDictionary");
@@ -556,6 +577,7 @@ public void test_needsDictionary() {
assertEquals(0, inf.getBytesRead());
assertEquals(0, inf.getBytesWritten());
assertEquals(1, inf.getAdler());
+ inf.end();
}
/**
@@ -580,6 +602,7 @@ public void test_needsInput() {
assertTrue(
"needsInput give wrong boolean value as a result of an empty input buffer",
inflate.needsInput());
+ inflate.end();
}
/**
@@ -623,6 +646,7 @@ public void test_reset() {
} catch (DataFormatException e) {
fail("Invalid input to be decompressed");
}
+ inflate.end();
for (int i = 0; i < byteArray.length; i++) {
assertEquals(
"Final decompressed data does not equal the original data",
@@ -698,6 +722,7 @@ public void test_reset() {
inflate.setInput(byteArray);
assertTrue("setInputB did not deliver any byte to the input buffer",
inflate.getRemaining() != 0);
+ inflate.end();
}
/**
@@ -721,6 +746,7 @@ public void test_reset() {
} catch (ArrayIndexOutOfBoundsException e) {
r = 1;
}
+ inflate.end();
assertEquals("boundary check is not present for setInput", 1, r);
}
@@ -779,6 +805,8 @@ public void test_getBytesRead() throws DataFormatException,
assertEquals(16, inf.getTotalIn());
assertEquals(compressedDataLength, inf.getTotalOut());
assertEquals(16, inf.getBytesRead());
+ def.end();
+ inf.end();
}
/**
@@ -805,6 +833,8 @@ public void test_getBytesWritten() throws DataFormatException, UnsupportedEncodi
assertEquals(16, inf.getTotalIn());
assertEquals(compressedDataLength, inf.getTotalOut());
assertEquals(14, inf.getBytesWritten());
+ def.end();
+ inf.end();
}
/**
@@ -814,6 +844,7 @@ public void testInflate() throws Exception {
// Regression for HARMONY-81
Inflater inf = new Inflater();
int res = inf.inflate(new byte[0], 0, 0);
+ inf.end();
assertEquals(0, res);
@@ -837,6 +868,7 @@ public void testInflate() throws Exception {
} catch (DataFormatException e) {
// expected
}
+ inflater.end();
inflater = new Inflater();
inflater.setInput(new byte[] { -1, -1, -1 });
@@ -845,6 +877,7 @@ public void testInflate() throws Exception {
} catch (DataFormatException e) {
// expected
}
+ inflater.end();
}
public void testSetDictionary$B() throws Exception {
@@ -875,6 +908,10 @@ public void testInflate() throws Exception {
int dataLen1 = defDict1.deflate(output1);
int dataLen2 = defDict2.deflate(output2);
+ defDictNo.end();
+ defDict1.end();
+ defDict2.end();
+
boolean passNo1 = false;
boolean passNo2 = false;
boolean pass12 = false;
@@ -1001,6 +1038,10 @@ public void testInflate() throws Exception {
int dataLen2 = defDict2.deflate(output2);
int dataLen3 = defDict3.deflate(output3);
+ defDict1.end();
+ defDict2.end();
+ defDict3.end();
+
boolean pass12 = false;
boolean pass23 = false;
boolean pass13 = true;
@@ -1083,6 +1124,7 @@ public void testInflate() throws Exception {
} catch (ArrayIndexOutOfBoundsException aiob) {
//expected
}
+ infl4.end();
}
public void testExceptions() throws Exception {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/ZipEntryTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/ZipEntryTest.java
index f034639bd..360264bcd 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/ZipEntryTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/ZipEntryTest.java
@@ -1,13 +1,13 @@
-/*
+/*
* 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.
@@ -20,13 +20,21 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.file.attribute.FileTime;
import java.util.TimeZone;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import libcore.io.Streams;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
import tests.support.resource.Support_Resources;
-public class ZipEntryTest extends junit.framework.TestCase {
+public class ZipEntryTest extends TestCaseWithRules {
+ @Rule
+ public TestRule guardRule = ResourceLeakageDetector.getRule();
+
// zip file hyts_ZipFile.zip must be included as a resource
private ZipEntry zentry;
private ZipFile zfile;
@@ -154,6 +162,27 @@ public void test_getTime() {
assertEquals("Failed to get time", orgTime, zentry.getTime());
}
+ /**
+ * java.util.zip.ZipEntry#getCreationTime()
+ */
+ public void test_getCreationTime() {
+ assertNull(zentry.getCreationTime());
+ }
+
+ /**
+ * java.util.zip.ZipEntry#getLastAccessTime()
+ */
+ public void test_getLastAccessTime() {
+ assertNull(zentry.getLastAccessTime());
+ }
+
+ /**
+ * java.util.zip.ZipEntry#getLastModifiedTime()
+ */
+ public void test_getLastModifiedTime() {
+ assertEquals(orgTime, zentry.getLastModifiedTime().toMillis());
+ }
+
/**
* java.util.zip.ZipEntry#isDirectory()
*/
@@ -341,29 +370,70 @@ public void test_setTimeJ() {
zentry.getTime());
TimeZone zone = TimeZone.getDefault();
try {
+ // These cases are supported since Android O thanks to
+ // Info-ZIP Extended Timestamp. Before Android O/openJdk8
+ // these cases would behave differently.
TimeZone.setDefault(TimeZone.getTimeZone("EST"));
zentry.setTime(0);
assertEquals("Test 3: Failed to set time: " + zentry.getTime(),
- 315550800000L, zentry.getTime());
+ 0L, zentry.getTime());
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
assertEquals("Test 3a: Failed to set time: " + zentry.getTime(),
- 315532800000L, zentry.getTime());
+ 0L, zentry.getTime());
zentry.setTime(0);
TimeZone.setDefault(TimeZone.getTimeZone("EST"));
assertEquals("Test 3b: Failed to set time: " + zentry.getTime(),
- 315550800000L, zentry.getTime());
+ 0L, zentry.getTime());
zentry.setTime(-25);
assertEquals("Test 4: Failed to set time: " + zentry.getTime(),
- 315550800000L, zentry.getTime());
+ -25L, zentry.getTime());
zentry.setTime(4354837200000L);
assertEquals("Test 5: Failed to set time: " + zentry.getTime(),
- 315550800000L, zentry.getTime());
+ 4354837200000L, zentry.getTime());
} finally {
TimeZone.setDefault(zone);
}
}
+ /**
+ * java.util.zip.ZipEntry#setLastModifiedTime(FileTime)
+ */
+ public void test_setLastModifiedTime() {
+ zentry.setLastModifiedTime(FileTime.fromMillis(0));
+ assertEquals(0, zentry.getLastModifiedTime().toMillis());
+ assertEquals(0, zentry.getTime());
+
+ final long someTimestampValue = 1478624967000L;
+ zentry.setLastModifiedTime(FileTime.fromMillis(someTimestampValue));
+ assertEquals(someTimestampValue, zentry.getLastModifiedTime().toMillis());
+ assertEquals(someTimestampValue, zentry.getTime());
+ }
+
+ /**
+ * java.util.zip.ZipEntry#setCreationTime(FileTime)
+ */
+ public void test_setCreationTime() {
+ zentry.setCreationTime(FileTime.fromMillis(0));
+ assertEquals(0, zentry.getCreationTime().toMillis());
+
+ final long someTimestampValue = 1478624967000L;
+ zentry.setCreationTime(FileTime.fromMillis(someTimestampValue));
+ assertEquals(someTimestampValue, zentry.getCreationTime().toMillis());
+ }
+
+ /**
+ * java.util.zip.ZipEntry#setLastAccessTime(FileTime)
+ */
+ public void test_setLastAccessTime() {
+ zentry.setLastAccessTime(FileTime.fromMillis(0));
+ assertEquals(0, zentry.getLastAccessTime().toMillis());
+
+ final long someTimestampValue = 1478624967000L;
+ zentry.setLastAccessTime(FileTime.fromMillis(someTimestampValue));
+ assertEquals(someTimestampValue, zentry.getLastAccessTime().toMillis());
+ }
+
/**
* java.util.zip.ZipEntry#toString()
*/
@@ -450,4 +520,3 @@ protected void tearDown() {
}
}
}
-
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/ZipFileTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/ZipFileTest.java
index 5b966333e..c5a41029f 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/ZipFileTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/ZipFileTest.java
@@ -23,9 +23,14 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+import java.util.HashSet;
import libcore.io.Streams;
import libcore.java.lang.ref.FinalizationTester;
import tests.support.resource.Support_Resources;
@@ -396,6 +401,48 @@ public void test_reset_subtest0() throws IOException {
is.close();
}
+ /**
+ * java.util.zip.ZipFile#stream()
+ */
+ public void test_stream() {
+ assertEquals(6, zfile.stream().count());
+ final List names = new ArrayList<>();
+ zfile.stream().forEach((ZipEntry entry) -> names.add(entry.getName()));
+ assertEquals(Arrays.asList("File1.txt","File2.txt","File3.txt",
+ "testdir1/","testdir1/File1.txt",
+ "testdir1/testdir1"), names);
+ }
+
+ public void test_sameNamesDifferentCase() throws Exception {
+ // Create a
+ final File tempFile = File.createTempFile("smdc", "zip");
+ try {
+ // Create a zip file with multiple entries with same text and different
+ // capitalization
+ FileOutputStream tempFileStream = new FileOutputStream(tempFile);
+ ZipOutputStream zipOutputStream = new ZipOutputStream(tempFileStream);
+ zipOutputStream.putNextEntry(new ZipEntry("test.txt"));
+ zipOutputStream.write(new byte[2]);
+ zipOutputStream.closeEntry();
+ zipOutputStream.putNextEntry(new ZipEntry("Test.txt"));
+ zipOutputStream.write(new byte[2]);
+ zipOutputStream.closeEntry();
+ zipOutputStream.putNextEntry(new ZipEntry("TEST.TXT"));
+ zipOutputStream.write(new byte[2]);
+ zipOutputStream.closeEntry();
+ zipOutputStream.close();
+ tempFileStream.close();
+
+ ZipFile zipFile = new ZipFile(tempFile);
+ final List names = new ArrayList<>();
+ zipFile.stream().forEach((ZipEntry entry) -> names.add(entry.getName()));
+ assertEquals(Arrays.asList("test.txt", "Test.txt", "TEST.TXT"), names);
+ } finally {
+ tempFile.delete();
+ }
+
+ }
+
@Override
protected void setUp() throws IOException {
// Create a local copy of the file since some tests want to alter information.
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/ZipInputStreamTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/ZipInputStreamTest.java
index adfe7e1e3..49a15bb87 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/ZipInputStreamTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/ZipInputStreamTest.java
@@ -27,11 +27,16 @@
import java.util.zip.ZipException;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
-
-import junit.framework.TestCase;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
import tests.support.resource.Support_Resources;
-public class ZipInputStreamTest extends TestCase {
+public class ZipInputStreamTest extends TestCaseWithRules {
+ @Rule
+ public TestRule guardRule = ResourceLeakageDetector.getRule();
+
// the file hyts_zipFile.zip used in setup needs to included as a resource
private ZipEntry zentry;
@@ -171,11 +176,11 @@ public int read(byte[] buffer) throws IOException {
}
};
- zis = new ZipInputStream(in);
- while ((zentry = zis.getNextEntry()) != null) {
- zentry.getName();
+ try (ZipInputStream zis = new ZipInputStream(in)) {
+ while ((zentry = zis.getNextEntry()) != null) {
+ zentry.getName();
+ }
}
- zis.close();
}
/**
@@ -193,18 +198,19 @@ public void test_skipJ() throws Exception {
long s = zis.skip(1025);
assertEquals("invalid skip: " + s, 1025, s);
- ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(zipBytes));
- zis.getNextEntry();
- long skipLen = dataBytes.length / 2;
- assertEquals("Assert 0: failed valid skip", skipLen, zis.skip(skipLen));
- zis.skip(dataBytes.length);
- assertEquals("Assert 1: performed invalid skip", 0, zis.skip(1));
- assertEquals("Assert 2: failed zero len skip", 0, zis.skip(0));
- try {
- zis.skip(-1);
- fail("Assert 3: Expected Illegal argument exception");
- } catch (IllegalArgumentException e) {
- // Expected
+ try (ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(zipBytes))) {
+ zis.getNextEntry();
+ long skipLen = dataBytes.length / 2;
+ assertEquals("Assert 0: failed valid skip", skipLen, zis.skip(skipLen));
+ zis.skip(dataBytes.length);
+ assertEquals("Assert 1: performed invalid skip", 0, zis.skip(1));
+ assertEquals("Assert 2: failed zero len skip", 0, zis.skip(0));
+ try {
+ zis.skip(-1);
+ fail("Assert 3: Expected Illegal argument exception");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/ZipOutputStreamTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/ZipOutputStreamTest.java
index 7f42fa84d..09e4f6601 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/ZipOutputStreamTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/zip/ZipOutputStreamTest.java
@@ -1,13 +1,13 @@
-/*
+/*
* 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.
@@ -21,13 +21,24 @@
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.lang.reflect.Field;
+import java.nio.file.attribute.FileTime;
+import java.util.ArrayList;
+import java.util.List;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.ResourceLeakageDetector.DisableResourceLeakageDetection;
+import libcore.junit.util.ResourceLeakageDetector;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
-public class ZipOutputStreamTest extends junit.framework.TestCase {
+public class ZipOutputStreamTest extends TestCaseWithRules {
+ @Rule
+ public TestRule guardRule = ResourceLeakageDetector.getRule();
ZipOutputStream zos;
@@ -41,7 +52,6 @@ public class ZipOutputStreamTest extends junit.framework.TestCase {
* java.util.zip.ZipOutputStream#close()
*/
public void test_close() throws Exception {
- zos = new ZipOutputStream(bos);
zos.putNextEntry(new ZipEntry("XX"));
zos.closeEntry();
zos.close();
@@ -115,6 +125,11 @@ public void test_putNextEntryLjava_util_zip_ZipEntry() throws IOException {
/**
* java.util.zip.ZipOutputStream#setComment(java.lang.String)
*/
+ @DisableResourceLeakageDetection(
+ why = "InflaterOutputStream.close() does not work properly if finish() throws an"
+ + " exception; finish() throws an exception if the output is invalid; this is"
+ + " an issue with the ZipOutputStream created in setUp()",
+ bug = "31797037")
public void test_setCommentLjava_lang_String() {
// There is no way to get the comment back, so no way to determine if
// the comment is set correct
@@ -168,6 +183,10 @@ public void test_setMethodI() throws IOException {
/**
* java.util.zip.ZipOutputStream#write(byte[], int, int)
*/
+ @DisableResourceLeakageDetection(
+ why = "InflaterOutputStream.close() does not work properly if finish() throws an"
+ + " exception; finish() throws an exception if the output is invalid.",
+ bug = "31797037")
public void test_write$BII() throws IOException {
ZipEntry ze = new ZipEntry("test");
zos.putNextEntry(ze);
@@ -241,6 +260,11 @@ public void test_setMethodI() throws IOException {
/**
* java.util.zip.ZipOutputStream#write(byte[], int, int)
*/
+ @DisableResourceLeakageDetection(
+ why = "InflaterOutputStream.close() does not work properly if finish() throws an"
+ + " exception; finish() throws an exception if the output is invalid; this is"
+ + " an issue with the ZipOutputStream created in setUp()",
+ bug = "31797037")
public void test_write$BII_2() throws IOException {
// Regression for HARMONY-577
File f1 = File.createTempFile("testZip1", "tst");
@@ -269,6 +293,116 @@ public void test_setMethodI() throws IOException {
zip1.close();
}
+ /**
+ * Test standard and info-zip-extended timestamp rounding
+ */
+ public void test_timeSerializationRounding() throws Exception {
+ List entries = new ArrayList<>();
+ ZipEntry zipEntry;
+
+ entries.add(zipEntry = new ZipEntry("test1"));
+ final long someTimestamp = 1479139143200L;
+ zipEntry.setTime(someTimestamp);
+
+ entries.add(zipEntry = new ZipEntry("test2"));
+ zipEntry.setLastModifiedTime(FileTime.fromMillis(someTimestamp));
+
+ for (ZipEntry entry : entries) {
+ zos.putNextEntry(entry);
+ zos.write(data.getBytes());
+ zos.closeEntry();
+ }
+ zos.close();
+
+ try (ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(bos.toByteArray()))) {
+ // getTime should be rounded down to a multiple of 2s
+ ZipEntry readEntry = zis.getNextEntry();
+ assertEquals((someTimestamp / 2000) * 2000,
+ readEntry.getTime());
+
+ // With extended timestamp getTime&getLastModifiedTime should berounded down to a
+ // multiple of 1s
+ readEntry = zis.getNextEntry();
+ assertEquals((someTimestamp / 1000) * 1000,
+ readEntry.getLastModifiedTime().toMillis());
+ assertEquals((someTimestamp / 1000) * 1000,
+ readEntry.getTime());
+ }
+ }
+
+ /**
+ * Test info-zip extended timestamp support
+ */
+ public void test_exttSupport() throws Exception {
+ List entries = new ArrayList<>();
+
+ ZipEntry zipEntry;
+
+ // There's no sane way to access ONLY mtime
+ Field mtimeField = ZipEntry.class.getDeclaredField("mtime");
+ mtimeField.setAccessible(true);
+
+ // Serialized DOS timestamp resolution is 2s. Serialized extended
+ // timestamp resolution is 1s. If we won't use rounded values then
+ // asserting time equality would be more complicated (resolution of
+ // getTime depends weather we use extended timestamp).
+ //
+ // We have to call setTime on all entries. If it's not set then
+ // ZipOutputStream will call setTime(System.currentTimeMillis()) on it.
+ // I will use this as a excuse to test whether setting particular time
+ // values (~< 1980 ~> 2099) triggers use of the extended last-modified
+ // timestamp.
+ final long timestampWithinDostimeBound = ZipEntry.UPPER_DOSTIME_BOUND;
+ assertEquals(0, timestampWithinDostimeBound % 1000);
+ final long timestampBeyondDostimeBound = ZipEntry.UPPER_DOSTIME_BOUND + 2000;
+ assertEquals(0, timestampBeyondDostimeBound % 1000);
+
+ // This will set both dos timestamp and last-modified timestamp (because < 1980)
+ entries.add(zipEntry = new ZipEntry("test_setTime"));
+ zipEntry.setTime(0);
+ assertNotNull(mtimeField.get(zipEntry));
+
+ // Explicitly set info-zip last-modified extended timestamp
+ entries.add(zipEntry = new ZipEntry("test_setLastModifiedTime"));
+ zipEntry.setLastModifiedTime(FileTime.fromMillis(1000));
+
+ // Set creation time and (since we have to call setTime on ZipEntry, otherwise
+ // ZipOutputStream will call setTime(System.currentTimeMillis()) and the getTime()
+ // assert will fail due to low serialization resolution) test that calling
+ // setTime with value <= ZipEntry.UPPER_DOSTIME_BOUND won't set the info-zip
+ // last-modified extended timestamp.
+ entries.add(zipEntry = new ZipEntry("test_setCreationTime"));
+ zipEntry.setCreationTime(FileTime.fromMillis(1000));
+ zipEntry.setTime(timestampWithinDostimeBound);
+ assertNull(mtimeField.get(zipEntry));
+
+ // Set last access time and test that calling setTime with value >
+ // ZipEntry.UPPER_DOSTIME_BOUND will set the info-zip last-modified extended
+ // timestamp
+ entries.add(zipEntry = new ZipEntry("test_setLastAccessTime"));
+ zipEntry.setLastAccessTime(FileTime.fromMillis(3000));
+ zipEntry.setTime(timestampBeyondDostimeBound);
+ assertNotNull(mtimeField.get(zipEntry));
+
+ for (ZipEntry entry : entries) {
+ zos.putNextEntry(entry);
+ zos.write(data.getBytes());
+ zos.closeEntry();
+ }
+ zos.close();
+
+ try (ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(bos.toByteArray()))) {
+ for (ZipEntry entry : entries) {
+ ZipEntry readEntry = zis.getNextEntry();
+ assertEquals(entry.getName(), readEntry.getName());
+ assertEquals(entry.getName(), entry.getTime(), readEntry.getTime());
+ assertEquals(entry.getName(), entry.getLastModifiedTime(), readEntry.getLastModifiedTime());
+ assertEquals(entry.getLastAccessTime(), readEntry.getLastAccessTime());
+ assertEquals(entry.getCreationTime(), readEntry.getCreationTime());
+ }
+ }
+ }
+
@Override
protected void setUp() throws Exception {
@@ -279,12 +413,14 @@ protected void setUp() throws Exception {
@Override
protected void tearDown() throws Exception {
try {
- if (zos != null) {
- zos.close();
- }
+ // Close the ZipInputStream first as that does not fail.
if (zis != null) {
zis.close();
}
+ if (zos != null) {
+ // This will throw a ZipException if nothing is written to the ZipOutputStream.
+ zos.close();
+ }
} catch (Exception e) {
}
super.tearDown();
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/SocketFactoryTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/SocketFactoryTest.java
index 649be0950..52d914232 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/SocketFactoryTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/SocketFactoryTest.java
@@ -126,30 +126,12 @@ public final void test_createSocket_InetAddressI() throws Exception {
public final void test_createSocket_InetAddressIInetAddressI() throws Exception {
SocketFactory sf = SocketFactory.getDefault();
int sport = new ServerSocket(0).getLocalPort();
- int[] invalidPorts = {Integer.MIN_VALUE, -1, 65536, Integer.MAX_VALUE};
Socket s = sf.createSocket(InetAddress.getLocalHost(), sport,
- InetAddress.getLocalHost(), 0);
+ InetAddress.getLocalHost(), 0);
assertNotNull(s);
assertTrue("1: Failed to create socket", s.getPort() == sport);
int portNumber = s.getLocalPort();
-
- for (int i = 0; i < invalidPorts.length; i++) {
- try {
- sf.createSocket(InetAddress.getLocalHost(), invalidPorts[i],
- InetAddress.getLocalHost(), portNumber);
- fail("IllegalArgumentException wasn't thrown for " + invalidPorts[i]);
- } catch (IllegalArgumentException expected) {
- }
-
- try {
- sf.createSocket(InetAddress.getLocalHost(), sport,
- InetAddress.getLocalHost(), invalidPorts[i]);
- fail("IllegalArgumentException wasn't thrown for " + invalidPorts[i]);
- } catch (IllegalArgumentException expected) {
- }
- }
-
try {
sf.createSocket(InetAddress.getLocalHost(), sport,
InetAddress.getLocalHost(), portNumber);
@@ -165,6 +147,64 @@ public final void test_createSocket_InetAddressIInetAddressI() throws Exception
}
}
+ // Checks the behavior of createSocket(InetAddress, int, InetAddress, int) when the
+ // ports are invalid.
+ public void test_createSocket_InetAddressIInetAddressI_IllegalArgumentException()
+ throws Exception {
+ SocketFactory sf = SocketFactory.getDefault();
+ int validPort = new ServerSocket(0).getLocalPort();
+ int[] invalidPorts = {Integer.MIN_VALUE, -1, 65536, Integer.MAX_VALUE};
+
+ for (int i = 0; i < invalidPorts.length; i++) {
+ // Check invalid server port.
+ try (Socket s = sf.createSocket(InetAddress.getLocalHost() /* ServerAddress */,
+ invalidPorts[i] /* ServerPort */,
+ InetAddress.getLocalHost() /* ClientAddress */,
+ validPort /* ClientPort */)) {
+ fail("IllegalArgumentException wasn't thrown for " + invalidPorts[i]);
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // Check invalid client port.
+ try (Socket s = sf.createSocket(InetAddress.getLocalHost() /* ServerAddress */,
+ validPort /* ServerPort */,
+ InetAddress.getLocalHost() /* ClientAddress */,
+ invalidPorts[i]) /* ClientPort */){
+ fail("IllegalArgumentException wasn't thrown for " + invalidPorts[i]);
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+ }
+
+ // b/31019685
+ // Checks the ordering of port number validation (IllegalArgumentException) and binding error.
+ public void test_createSocket_InetAddressIInetAddressI_ExceptionOrder() throws IOException {
+ int invalidPort = Integer.MAX_VALUE;
+ SocketFactory sf = SocketFactory.getDefault();
+ int validServerPortNumber = new ServerSocket(0).getLocalPort();
+
+ // Create a socket with localhost as the client address so that another attempt to bind
+ // would fail.
+ Socket s = sf.createSocket(InetAddress.getLocalHost() /* ServerAddress */,
+ validServerPortNumber /* ServerPortNumber */,
+ InetAddress.getLocalHost() /* ClientAddress */,
+ 0 /* ClientPortNumber */);
+
+ int assignedLocalPortNumber = s.getLocalPort();
+
+ // Create a socket with an invalid port and localhost as the client address. Both
+ // BindException and IllegalArgumentException are expected in this case as the address is
+ // already bound to the socket above and port is invalid, however, to preserve the
+ // precedence order, IllegalArgumentException should be thrown.
+ try (Socket s1 = sf.createSocket(InetAddress.getLocalHost() /* ServerAddress */,
+ invalidPort /* ServerPortNumber */,
+ InetAddress.getLocalHost() /* ClientAddress */,
+ assignedLocalPortNumber /* ClientPortNumber */)) {
+ fail("IllegalArgumentException wasn't thrown for " + invalidPort);
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
/**
* javax.net.SocketFactory#createSocket(String host, int port,
* InetAddress localHost, int localPort)
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HandshakeCompletedEventTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HandshakeCompletedEventTest.java
index bb2265fb7..74c3a7faf 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HandshakeCompletedEventTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HandshakeCompletedEventTest.java
@@ -25,6 +25,7 @@
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
+import java.util.Base64;
import javax.net.ssl.HandshakeCompletedEvent;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.KeyManager;
@@ -39,7 +40,6 @@
import javax.net.ssl.X509TrustManager;
import javax.security.cert.X509Certificate;
import junit.framework.TestCase;
-import libcore.io.Base64;
import org.apache.harmony.xnet.tests.support.mySSLSession;
/**
@@ -535,7 +535,7 @@ public X509Certificate[] getChain() {
* for the result.
*/
private KeyManager[] getKeyManagers(String keys) throws Exception {
- byte[] bytes = Base64.decode(keys.getBytes());
+ byte[] bytes = Base64.getDecoder().decode(keys.getBytes());
InputStream inputStream = new ByteArrayInputStream(bytes);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HostnameVerifierTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HostnameVerifierTest.java
index 013c49bf6..b21b9acc1 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HostnameVerifierTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HostnameVerifierTest.java
@@ -71,22 +71,15 @@ public void testVerify() throws Exception {
in = new ByteArrayInputStream(X509_FOO_BAR_HANAKO);
x509 = (X509Certificate) cf.generateCertificate(in);
session = new mySSLSession(new X509Certificate[] {x509});
- assertTrue(verifier.verify("foo.com", session));
- assertFalse(verifier.verify("a.foo.com", session));
- // these checks test alternative subjects. The test data contains an
- // alternative subject starting with a japanese kanji character. This is
- // not supported by Android because the underlying implementation from
- // harmony follows the definition from rfc 1034 page 10 for alternative
- // subject names. This causes the code to drop all alternative subjects.
- // assertTrue(verifier.verify("bar.com", session));
- // assertFalse(verifier.verify("a.bar.com", session));
- // assertFalse(verifier.verify("a.\u82b1\u5b50.co.jp", session));
-
- in = new ByteArrayInputStream(X509_NO_CNS_FOO);
- x509 = (X509Certificate) cf.generateCertificate(in);
- session = new mySSLSession(new X509Certificate[] {x509});
- assertTrue(verifier.verify("foo.com", session));
+ assertFalse(verifier.verify("foo.com", session));
assertFalse(verifier.verify("a.foo.com", session));
+ assertTrue(verifier.verify("bar.com", session));
+ assertFalse(verifier.verify("a.bar.com", session));
+ // The certificate has this name in the altnames section, but Conscrypt drops
+ // any altnames that are improperly encoded according to RFC 5280, which requires
+ // non-ASCII characters to be encoded in ASCII via Punycode.
+ assertFalse(verifier.verify("\u82b1\u5b50.co.jp", session));
+ assertFalse(verifier.verify("a.\u82b1\u5b50.co.jp", session));
in = new ByteArrayInputStream(X509_NO_CNS_FOO);
x509 = (X509Certificate) cf.generateCertificate(in);
@@ -123,18 +116,18 @@ public void testVerify() throws Exception {
session = new mySSLSession(new X509Certificate[] {x509});
// try the foo.com variations
assertFalse(verifier.verify("foo.com", session));
- assertTrue(verifier.verify("www.foo.com", session));
- assertTrue(verifier.verify("\u82b1\u5b50.foo.com", session));
+ assertFalse(verifier.verify("www.foo.com", session));
+ assertFalse(verifier.verify("\u82b1\u5b50.foo.com", session));
assertFalse(verifier.verify("a.b.foo.com", session));
- // these checks test alternative subjects. The test data contains an
- // alternative subject starting with a japanese kanji character. This is
- // not supported by Android because the underlying implementation from
- // harmony follows the definition from rfc 1034 page 10 for alternative
- // subject names. This causes the code to drop all alternative subjects.
- // assertFalse(verifier.verify("bar.com", session));
- // assertTrue(verifier.verify("www.bar.com", session));
- // assertTrue(verifier.verify("\u82b1\u5b50.bar.com", session));
- // assertTrue(verifier.verify("a.b.bar.com", session));
+ assertFalse(verifier.verify("bar.com", session));
+ assertTrue(verifier.verify("www.bar.com", session));
+ assertTrue(verifier.verify("\u82b1\u5b50.bar.com", session));
+ assertFalse(verifier.verify("a.b.bar.com", session));
+ // The certificate has this name in the altnames section, but Conscrypt drops
+ // any altnames that are improperly encoded according to RFC 5280, which requires
+ // non-ASCII characters to be encoded in ASCII via Punycode.
+ assertFalse(verifier.verify("\u82b1\u5b50.co.jp", session));
+ assertFalse(verifier.verify("a.\u82b1\u5b50.co.jp", session));
}
public void testSubjectAlt() throws Exception {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HttpsURLConnectionTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HttpsURLConnectionTest.java
index 2b4b91685..feac5cb25 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HttpsURLConnectionTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HttpsURLConnectionTest.java
@@ -43,6 +43,13 @@
*/
public class HttpsURLConnectionTest extends TestCase {
+ @Override
+ public void setUp() throws Exception {
+ // Set the default SSL Socket factory to avoid an unmatched SSLSocketFactory
+ HttpsURLConnection.setDefaultSSLSocketFactory(
+ (SSLSocketFactory)SSLSocketFactory.getDefault());
+ }
+
/**
* javax.net.ssl.HttpsURLConnection#HttpsURLConnection(java_net_URL)
*/
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineTest.java
index 9360c00e0..f8d2847cf 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineTest.java
@@ -310,7 +310,7 @@ public void test_unwrap_01() throws Exception {
doHandshake();
ByteBuffer bbs = ByteBuffer.wrap(new byte[] {1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,31,2,3,1,2,3,1,2,3,1,2,3});
- ByteBuffer bbd = ByteBuffer.allocate(100);
+ ByteBuffer bbd = ByteBuffer.allocate(clientEngine.engine.getSession().getApplicationBufferSize());
try {
clientEngine.engine.unwrap(bbs, new ByteBuffer[] { bbd }, 0, 1);
fail("SSLException wasn't thrown");
@@ -895,6 +895,7 @@ public void test_wrap_ByteBuffer_ByteBuffer_04() throws Exception {
try {
SSLEngineResult result = sse.wrap(bbs, bbd);
+ fail();
} catch (IllegalStateException expected) {
}
}
@@ -992,8 +993,11 @@ public void test_wrap_ByteBuffer_ByteBuffer_05() throws Exception {
ByteBuffer[] bbA = { ByteBuffer.allocate(5), ByteBuffer.allocate(10), ByteBuffer.allocate(5) };
SSLEngine sse = getEngine(host, port);
- SSLEngineResult result = sse.wrap(bbA, bb);
- assertEquals(Status.BUFFER_OVERFLOW, result.getStatus());
+ try {
+ SSLEngineResult result = sse.wrap(bbA, bb);
+ fail();
+ } catch (IllegalStateException expected) {
+ }
}
/**
@@ -1009,7 +1013,11 @@ public void test_wrap_ByteBuffer_ByteBuffer_05() throws Exception {
SSLEngineResult res = sse.wrap(bbA, bb);
assertEquals(0, res.bytesConsumed());
- assertEquals(0, res.bytesProduced());
+ if (res.bytesProduced() == 0) {
+ assertEquals(HandshakeStatus.NEED_WRAP, res.getHandshakeStatus());
+ } else {
+ assertEquals(HandshakeStatus.NEED_UNWRAP, res.getHandshakeStatus());
+ }
}
private SSLEngine getEngine() throws Exception {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLServerSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLServerSocketTest.java
index 5a0cf6f84..117a1a078 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLServerSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLServerSocketTest.java
@@ -18,8 +18,6 @@
import junit.framework.TestCase;
-import libcore.io.Base64;
-
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -27,6 +25,7 @@
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.Arrays;
+import java.util.Base64;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
@@ -391,7 +390,7 @@ public void test_WantClientAuth() throws Exception {
*/
private KeyManager[] getKeyManagers() throws Exception {
String keys = (useBKS ? SERVER_KEYS_BKS : SERVER_KEYS_JKS);
- byte[] bytes = Base64.decode(keys.getBytes());
+ byte[] bytes = Base64.getDecoder().decode(keys.getBytes());
InputStream inputStream = new ByteArrayInputStream(bytes);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionTest.java
index 018de8ce6..fde1ff809 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionTest.java
@@ -26,6 +26,7 @@
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Arrays;
+import java.util.Base64;
import javax.net.ssl.ExtendedSSLSession;
import javax.net.ssl.KeyManager;
@@ -42,7 +43,6 @@
import org.apache.harmony.tests.javax.net.ssl.HandshakeCompletedEventTest.TestTrustManager;
import junit.framework.TestCase;
-import libcore.io.Base64;
import libcore.java.security.StandardNames;
public class SSLSessionTest extends TestCase {
@@ -643,7 +643,7 @@ public KeyStore getStore() {
* for the result.
*/
private KeyStore getKeyStore(String keys) throws Exception {
- byte[] bytes = Base64.decode(keys.getBytes());
+ byte[] bytes = Base64.getDecoder().decode(keys.getBytes());
InputStream inputStream = new ByteArrayInputStream(bytes);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSocketTest.java
index 861f4a89d..5712a48bd 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSocketTest.java
@@ -24,6 +24,7 @@
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.Arrays;
+import java.util.Base64;
import javax.net.ssl.HandshakeCompletedEvent;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.KeyManager;
@@ -35,7 +36,6 @@
import javax.net.ssl.TrustManager;
import javax.security.cert.X509Certificate;
import junit.framework.TestCase;
-import libcore.io.Base64;
import libcore.java.security.StandardNames;
import org.apache.harmony.tests.javax.net.ssl.HandshakeCompletedEventTest.TestTrustManager;
@@ -249,6 +249,7 @@ public void test_removeHandshakeCompletedListener() throws IOException {
try {
ssl.removeHandshakeCompletedListener(ls);
+ fail();
} catch (IllegalArgumentException expected) {
}
@@ -586,7 +587,7 @@ public X509Certificate[] getChain() {
* for the result.
*/
private KeyManager[] getKeyManagers(String keys) throws Exception {
- byte[] bytes = Base64.decode(keys.getBytes());
+ byte[] bytes = Base64.getDecoder().decode(keys.getBytes());
InputStream inputStream = new ByteArrayInputStream(bytes);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/TrustManagerFactory1Test.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/TrustManagerFactory1Test.java
index 9b5b9296c..176a832ae 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/TrustManagerFactory1Test.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/TrustManagerFactory1Test.java
@@ -295,6 +295,7 @@ public void test_getInstanceLjava_lang_StringLjava_security_Provider01() throws
for (String validValue : getValidValues()) {
try {
TrustManagerFactory.getInstance(validValue, (Provider) null);
+ fail();
} catch (IllegalArgumentException expected) {
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/SubjectTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/SubjectTest.java
index f2ef564eb..6d775ecbc 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/SubjectTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/SubjectTest.java
@@ -19,12 +19,18 @@
import junit.framework.TestCase;
import javax.security.auth.Subject;
+import javax.security.auth.x500.X500Principal;
+
import java.security.AccessControlContext;
import java.security.AccessController;
+import java.security.Principal;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
+import java.util.HashSet;
+import java.util.Set;
+
import org.apache.harmony.testframework.serialization.SerializationTest;
/**
@@ -48,6 +54,29 @@ public void test_Constructor_01() {
}
}
+ public void test_Constructor_failsWithNullArguments() {
+ try {
+ new Subject(false /* readOnly */,
+ null /* principals */,
+ new HashSet() /* pubCredentials */,
+ new HashSet() /* privCredentials */);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ new Subject(false , new HashSet(), null, new HashSet());
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ new Subject(false , new HashSet(), new HashSet(), null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
/**
* javax.security.auth.Subject#doAs(Subject subject, PrivilegedAction action)
*/
@@ -234,6 +263,36 @@ public void testSerializationGolden() throws Exception {
SerializationTest.verifyGolden(this, getSerializationData());
}
+ public void testSerialization_nullPrincipalsAllowed() throws Exception {
+ Set principalsSet = new HashSet<>();
+ principalsSet.add(new X500Principal("CN=SomePrincipal"));
+ principalsSet.add(null);
+ principalsSet.add(new X500Principal("CN=SomeOtherPrincipal"));
+ Subject subject = new Subject(
+ false /* readOnly */, principalsSet, new HashSet(), new HashSet());
+ SerializationTest.verifySelf(subject);
+ }
+
+ public void testSecureTest_removeAllNull_throwsException() throws Exception {
+ Subject subject = new Subject(
+ false, new HashSet(), new HashSet(), new HashSet());
+ try {
+ subject.getPrincipals().removeAll(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ public void testSecureTest_retainAllNull_throwsException() throws Exception {
+ Subject subject = new Subject(
+ false, new HashSet(), new HashSet(), new HashSet());
+ try {
+ subject.getPrincipals().retainAll(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
private Object[] getSerializationData() {
Subject subject = new Subject();
return new Object[] { subject, subject.getPrincipals(),
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/callback/PasswordCallbackTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/callback/PasswordCallbackTest.java
index 024c9e90b..8682de77b 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/callback/PasswordCallbackTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/callback/PasswordCallbackTest.java
@@ -93,7 +93,7 @@ public void test_Password() {
}
pc.clearPassword();
res = pc.getPassword();
- if (res.equals(psw2)) {
+ if (Arrays.equals(res, psw2)) {
fail("Incorrect password was returned after clear");
}
pc.setPassword(psw1);
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/x500/X500PrincipalTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/x500/X500PrincipalTest.java
index 1933eb78b..14b21f7bf 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/x500/X500PrincipalTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/x500/X500PrincipalTest.java
@@ -1322,6 +1322,25 @@ public void testSemiIllegalInputName_14() {
new X500Principal(dn);
}
+ /**
+ * Change rev/d1c04dac850d upstream addresses the case of the string CN=prefix\<>suffix.
+ *
+ * Before said change, the string can be used to construct an X500Principal, although according
+ * to RFC2253 is not possible. Also, characters after '<' are ignored. We have tests documenting
+ * that we allow such strings, like testIllegalInputName_07, so we modified the change as to
+ * allow the string. We check that the characters after '<' are not ignored.
+ *
+ * Note: the string CN=prefix\<>suffix in the test is escaped as CN=prefix\\<>suffix
+ */
+ public void testSemiIllegalInputName_15() {
+ String dn = "CN=prefix\\<>suffix";
+
+ X500Principal principal = new X500Principal(dn);
+ assertEquals("CN=\"prefix<>suffix\"", principal.getName(X500Principal.RFC1779));
+ assertEquals("CN=prefix\\<\\>suffix", principal.getName(X500Principal.RFC2253));
+ assertEquals("cn=prefix\\<\\>suffix", principal.getName(X500Principal.CANONICAL));
+ }
+
public void testInitClause() {
try {
byte[] mess = { 0x30, 0x18, 0x31, 0x0A, 0x30, 0x08, 0x06, 0x03,
diff --git a/harmony-tests/src/test/resources/serialization/org/apache/harmony/tests/java/text/ParseException.ser b/harmony-tests/src/test/resources/serialization/org/apache/harmony/tests/java/text/ParseException.ser
new file mode 100644
index 000000000..a25d6b104
Binary files /dev/null and b/harmony-tests/src/test/resources/serialization/org/apache/harmony/tests/java/text/ParseException.ser differ
diff --git a/include/LocalArray.h b/include/LocalArray.h
deleted file mode 100644
index 2ab708aff..000000000
--- a/include/LocalArray.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef LOCAL_ARRAY_H_included
-#define LOCAL_ARRAY_H_included
-
-#include
-#include
-
-/**
- * A fixed-size array with a size hint. That number of bytes will be allocated
- * on the stack, and used if possible, but if more bytes are requested at
- * construction time, a buffer will be allocated on the heap (and deallocated
- * by the destructor).
- *
- * The API is intended to be a compatible subset of C++0x's std::array.
- */
-template
-class LocalArray {
-public:
- /**
- * Allocates a new fixed-size array of the given size. If this size is
- * less than or equal to the template parameter STACK_BYTE_COUNT, an
- * internal on-stack buffer will be used. Otherwise a heap buffer will
- * be allocated.
- */
- LocalArray(size_t desiredByteCount) : mSize(desiredByteCount) {
- if (desiredByteCount > STACK_BYTE_COUNT) {
- mPtr = new char[mSize];
- } else {
- mPtr = &mOnStackBuffer[0];
- }
- }
-
- /**
- * Frees the heap-allocated buffer, if there was one.
- */
- ~LocalArray() {
- if (mPtr != &mOnStackBuffer[0]) {
- delete[] mPtr;
- }
- }
-
- // Capacity.
- size_t size() { return mSize; }
- bool empty() { return mSize == 0; }
-
- // Element access.
- char& operator[](size_t n) { return mPtr[n]; }
- const char& operator[](size_t n) const { return mPtr[n]; }
-
-private:
- char mOnStackBuffer[STACK_BYTE_COUNT];
- char* mPtr;
- size_t mSize;
-
- // Disallow copy and assignment.
- LocalArray(const LocalArray&);
- void operator=(const LocalArray&);
-};
-
-#endif // LOCAL_ARRAY_H_included
diff --git a/include/ScopedPthreadMutexLock.h b/include/ScopedPthreadMutexLock.h
deleted file mode 100644
index 90f4596cc..000000000
--- a/include/ScopedPthreadMutexLock.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#ifndef SCOPED_PTHREAD_MUTEX_LOCK_H_included
-#define SCOPED_PTHREAD_MUTEX_LOCK_H_included
-
-#include
-
-/**
- * Locks and unlocks a pthread_mutex_t as it goes in and out of scope.
- */
-class ScopedPthreadMutexLock {
-public:
- explicit ScopedPthreadMutexLock(pthread_mutex_t* mutex) : mMutexPtr(mutex) {
- pthread_mutex_lock(mMutexPtr);
- }
-
- ~ScopedPthreadMutexLock() {
- pthread_mutex_unlock(mMutexPtr);
- }
-
-private:
- pthread_mutex_t* mMutexPtr;
-
- // Disallow copy and assignment.
- ScopedPthreadMutexLock(const ScopedPthreadMutexLock&);
- void operator=(const ScopedPthreadMutexLock&);
-};
-
-#endif // SCOPED_PTHREAD_MUTEX_LOCK_H_included
diff --git a/json/src/main/java/org/json/JSONObject.java b/json/src/main/java/org/json/JSONObject.java
index 9ea91a6a1..790238979 100644
--- a/json/src/main/java/org/json/JSONObject.java
+++ b/json/src/main/java/org/json/JSONObject.java
@@ -21,6 +21,7 @@
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
// Note: this class was written without inspecting the non-free org.json sourcecode.
@@ -100,6 +101,8 @@ public class JSONObject {
@Override public boolean equals(Object o) {
return o == this || o == null; // API specifies this broken equals implementation
}
+ // at least make the broken equals(null) consistent with Objects.hashCode(null).
+ @Override public int hashCode() { return Objects.hashCode(null); }
@Override public String toString() {
return "null";
}
diff --git a/json/src/test/java/org/json/JSONObjectTest.java b/json/src/test/java/org/json/JSONObjectTest.java
index 9029ec6c6..07d1cf643 100644
--- a/json/src/test/java/org/json/JSONObjectTest.java
+++ b/json/src/test/java/org/json/JSONObjectTest.java
@@ -27,6 +27,7 @@
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import junit.framework.TestCase;
@@ -825,6 +826,12 @@ public void testNullValue() throws JSONException {
assertTrue(object.isNull("bar"));
}
+ public void testNullValue_equalsAndHashCode() {
+ assertTrue(JSONObject.NULL.equals(null)); // guaranteed by javadoc
+ // not guaranteed by javadoc, but seems like a good idea
+ assertEquals(Objects.hashCode(null), JSONObject.NULL.hashCode());
+ }
+
public void testHas() throws JSONException {
JSONObject object = new JSONObject();
object.put("foo", 5);
diff --git a/jsr166-tests/src/test/java/jsr166/CompletableFutureTest.java b/jsr166-tests/src/test/java/jsr166/CompletableFutureTest.java
index 37bc28560..28517aab0 100644
--- a/jsr166-tests/src/test/java/jsr166/CompletableFutureTest.java
+++ b/jsr166-tests/src/test/java/jsr166/CompletableFutureTest.java
@@ -3730,9 +3730,10 @@ public void testMinimalCompletionStage_minimality() {
(method) -> method.getName() + Arrays.toString(method.getParameterTypes());
Predicate isNotStatic =
(method) -> (method.getModifiers() & Modifier.STATIC) == 0;
+ // Android-changed: Added a cast to workaround an ECJ bug. http://b/33371837
List minimalMethods =
Stream.of(Object.class, CompletionStage.class)
- .flatMap((klazz) -> Stream.of(klazz.getMethods()))
+ .flatMap((klazz) -> (Stream) Stream.of(klazz.getMethods()))
.filter(isNotStatic)
.collect(Collectors.toList());
// Methods from CompletableFuture permitted NOT to throw UOE
diff --git a/jsr166-tests/src/test/java/jsr166/DelayQueueTest.java b/jsr166-tests/src/test/java/jsr166/DelayQueueTest.java
index e42ac2dfb..61e8f8bd0 100644
--- a/jsr166-tests/src/test/java/jsr166/DelayQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/DelayQueueTest.java
@@ -27,7 +27,7 @@
public class DelayQueueTest extends JSR166TestCase {
- // android-changed: Extend BlockingQueueTest directly instead of creating
+ // Android-changed: Extend BlockingQueueTest directly instead of creating
// an inner class and its associated suite.
//
// public static class Generic extends BlockingQueueTest {
diff --git a/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java b/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java
index fc1632cb8..ea6e57657 100644
--- a/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java
+++ b/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java
@@ -1089,7 +1089,7 @@ public void shouldThrow(String exceptionName) {
* getPolicy/setPolicy.
*/
public void runWithPermissions(Runnable r, Permission... permissions) {
- // Android-changed - no SecurityManager
+ // Android-changed: no SecurityManager
// SecurityManager sm = System.getSecurityManager();
// if (sm == null) {
// r.run();
@@ -1107,7 +1107,7 @@ public void runWithPermissions(Runnable r, Permission... permissions) {
*/
public void runWithSecurityManagerWithPermissions(Runnable r,
Permission... permissions) {
- // Android-changed - no SecurityManager
+ // Android-changed: no SecurityManager
// SecurityManager sm = System.getSecurityManager();
// if (sm == null) {
// Policy savedPolicy = Policy.getPolicy();
@@ -1221,20 +1221,60 @@ else if (s == Thread.State.TERMINATED)
fail("Unexpected thread termination");
else if (millisElapsedSince(startTime) > timeoutMillis) {
threadAssertTrue(thread.isAlive());
- return;
+ fail("timed out waiting for thread to enter wait state");
}
Thread.yield();
}
}
/**
- * Waits up to LONG_DELAY_MS for the given thread to enter a wait
- * state: BLOCKED, WAITING, or TIMED_WAITING.
+ * Spin-waits up to the specified number of milliseconds for the given
+ * thread to enter a wait state: BLOCKED, WAITING, or TIMED_WAITING,
+ * and additionally satisfy the given condition.
+ */
+ void waitForThreadToEnterWaitState(
+ Thread thread, long timeoutMillis, Callable waitingForGodot) {
+ long startTime = 0L;
+ for (;;) {
+ Thread.State s = thread.getState();
+ if (s == Thread.State.BLOCKED ||
+ s == Thread.State.WAITING ||
+ s == Thread.State.TIMED_WAITING) {
+ try {
+ if (waitingForGodot.call())
+ return;
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+ else if (s == Thread.State.TERMINATED)
+ fail("Unexpected thread termination");
+ else if (startTime == 0L)
+ startTime = System.nanoTime();
+ else if (millisElapsedSince(startTime) > timeoutMillis) {
+ threadAssertTrue(thread.isAlive());
+ fail("timed out waiting for thread to enter wait state");
+ }
+ Thread.yield();
+ }
+ }
+
+ /**
+ * Spin-waits up to LONG_DELAY_MS milliseconds for the given thread to
+ * enter a wait state: BLOCKED, WAITING, or TIMED_WAITING.
*/
void waitForThreadToEnterWaitState(Thread thread) {
waitForThreadToEnterWaitState(thread, LONG_DELAY_MS);
}
+ /**
+ * Spin-waits up to LONG_DELAY_MS milliseconds for the given thread to
+ * enter a wait state: BLOCKED, WAITING, or TIMED_WAITING,
+ * and additionally satisfy the given condition.
+ */
+ void waitForThreadToEnterWaitState(
+ Thread thread, Callable waitingForGodot) {
+ waitForThreadToEnterWaitState(thread, LONG_DELAY_MS, waitingForGodot);
+ }
+
/**
* Returns the number of milliseconds since time given by
* startNanoTime, which must have been previously returned from a
diff --git a/jsr166-tests/src/test/java/jsr166/LinkedTransferQueueTest.java b/jsr166-tests/src/test/java/jsr166/LinkedTransferQueueTest.java
index 05fc68911..efe5a5828 100644
--- a/jsr166-tests/src/test/java/jsr166/LinkedTransferQueueTest.java
+++ b/jsr166-tests/src/test/java/jsr166/LinkedTransferQueueTest.java
@@ -17,6 +17,7 @@
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
@@ -750,9 +751,11 @@ public void realRun() throws InterruptedException {
}});
threadStarted.await();
- waitForThreadToEnterWaitState(t);
- assertEquals(1, q.getWaitingConsumerCount());
- assertTrue(q.hasWaitingConsumer());
+ Callable oneConsumer
+ = new Callable() { public Boolean call() {
+ return q.hasWaitingConsumer()
+ && q.getWaitingConsumerCount() == 1; }};
+ waitForThreadToEnterWaitState(t, oneConsumer);
assertTrue(q.offer(one));
assertEquals(0, q.getWaitingConsumerCount());
@@ -789,8 +792,11 @@ public void realRun() throws InterruptedException {
}});
threadStarted.await();
- waitForThreadToEnterWaitState(t);
- assertEquals(1, q.size());
+ Callable oneElement
+ = new Callable() { public Boolean call() {
+ return !q.isEmpty() && q.size() == 1; }};
+ waitForThreadToEnterWaitState(t, oneElement);
+
assertSame(five, q.poll());
checkEmpty(q);
awaitTermination(t);
diff --git a/jsr166-tests/src/test/java/jsr166/PhaserTest.java b/jsr166-tests/src/test/java/jsr166/PhaserTest.java
index 673e556a1..121901776 100644
--- a/jsr166-tests/src/test/java/jsr166/PhaserTest.java
+++ b/jsr166-tests/src/test/java/jsr166/PhaserTest.java
@@ -527,7 +527,7 @@ public void realRun() {
}});
await(pleaseArrive);
- waitForThreadToEnterWaitState(t, SHORT_DELAY_MS);
+ waitForThreadToEnterWaitState(t);
assertEquals(0, phaser.arrive());
awaitTermination(t);
@@ -555,7 +555,7 @@ public void realRun() {
}});
await(pleaseArrive);
- waitForThreadToEnterWaitState(t, SHORT_DELAY_MS);
+ waitForThreadToEnterWaitState(t);
t.interrupt();
assertEquals(0, phaser.arrive());
awaitTermination(t);
@@ -571,20 +571,20 @@ public void realRun() {
public void testArriveAndAwaitAdvanceAfterInterrupt() {
final Phaser phaser = new Phaser();
assertEquals(0, phaser.register());
- final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ final CountDownLatch pleaseArrive = new CountDownLatch(1);
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() {
Thread.currentThread().interrupt();
assertEquals(0, phaser.register());
- pleaseInterrupt.countDown();
+ pleaseArrive.countDown();
assertTrue(Thread.currentThread().isInterrupted());
assertEquals(1, phaser.arriveAndAwaitAdvance());
- assertTrue(Thread.currentThread().isInterrupted());
+ assertTrue(Thread.interrupted());
}});
- await(pleaseInterrupt);
- waitForThreadToEnterWaitState(t, SHORT_DELAY_MS);
+ await(pleaseArrive);
+ waitForThreadToEnterWaitState(t);
Thread.currentThread().interrupt();
assertEquals(1, phaser.arriveAndAwaitAdvance());
assertTrue(Thread.interrupted());
@@ -605,11 +605,11 @@ public void realRun() {
assertFalse(Thread.currentThread().isInterrupted());
pleaseInterrupt.countDown();
assertEquals(1, phaser.arriveAndAwaitAdvance());
- assertTrue(Thread.currentThread().isInterrupted());
+ assertTrue(Thread.interrupted());
}});
await(pleaseInterrupt);
- waitForThreadToEnterWaitState(t, SHORT_DELAY_MS);
+ waitForThreadToEnterWaitState(t);
t.interrupt();
Thread.currentThread().interrupt();
assertEquals(1, phaser.arriveAndAwaitAdvance());
@@ -784,7 +784,7 @@ public void realRun() {
assertEquals(THREADS, phaser.getArrivedParties());
assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
for (Thread thread : threads)
- waitForThreadToEnterWaitState(thread, SHORT_DELAY_MS);
+ waitForThreadToEnterWaitState(thread);
for (Thread thread : threads)
assertTrue(thread.isAlive());
assertState(phaser, 0, THREADS + 1, 1);
diff --git a/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorTest.java b/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorTest.java
index 2546626e8..0865ed4f6 100644
--- a/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorTest.java
+++ b/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorTest.java
@@ -1371,11 +1371,11 @@ public void testPoolSizeInvariants() {
assertEquals(s, p.getMaximumPoolSize());
try {
p.setCorePoolSize(s + 1);
- // android-changed: changeset dfec9b5386ca028cc1468f3e2717120ab6274702
+ // Android-changed: changeset dfec9b5386ca028cc1468f3e2717120ab6274702
// disables this check for compatibility reason.
// shouldThrow();
} catch (IllegalArgumentException success) {}
- // android-changed: changeset dfec9b5386ca028cc1468f3e2717120ab6274702
+ // Android-changed: changeset dfec9b5386ca028cc1468f3e2717120ab6274702
// disables maximumpoolsize check for compatibility reason.
// assertEquals(s, p.getCorePoolSize());
assertEquals(s + 1, p.getCorePoolSize());
diff --git a/libart/src/main/java/dalvik/system/ClassExt.java b/libart/src/main/java/dalvik/system/ClassExt.java
new file mode 100644
index 000000000..3daa971e3
--- /dev/null
+++ b/libart/src/main/java/dalvik/system/ClassExt.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 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;
+
+/**
+ * Holder class for extraneous Class data.
+ *
+ * This class holds data for Class objects that is either rarely useful, only necessary for
+ * debugging purposes or both. This allows us to extend the Class class without impacting memory
+ * use.
+ *
+ * @hide For internal runtime use only.
+ */
+public final class ClassExt {
+ /**
+ * An array of all obsolete DexCache objects that are needed for obsolete methods.
+ *
+ * These entries are associated with the obsolete ArtMethod pointers at the same indexes in the
+ * obsoleteMethods array.
+ *
+ * This field has native components and is a logical part of the 'Class' type.
+ */
+ private Object[] obsoleteDexCaches;
+
+ /**
+ * An array of all native obsolete ArtMethod pointers.
+ *
+ * These are associated with their DexCaches at the same index in the obsoleteDexCaches array.
+ *
+ * This field is actually either an int[] or a long[] depending on size of a pointer.
+ *
+ * This field contains native pointers and is a logical part of the 'Class' type.
+ */
+ private Object obsoleteMethods;
+
+ /**
+ * If set, the bytes or DexCache of the original dex-file associated with the related class.
+ *
+ * In this instance 'original' means either (1) the dex-file loaded for this class when it was
+ * first loaded after all non-retransformation capable transformations had been performed but
+ * before any retransformation capable ones had been done or (2) the most recent dex-file bytes
+ * given for a class redefinition.
+ *
+ * Needed in order to implement retransformation of classes.
+ *
+ * This field is a logical part of the 'Class' type.
+ */
+ private Object originalDexFile;
+
+ /**
+ * If class verify fails, we must return same error on subsequent tries. We may store either
+ * the class of the error, or an actual instance of Throwable here.
+ *
+ * This field is a logical part of the 'Class' type.
+ */
+ private Object verifyError;
+
+ /**
+ * Private constructor.
+ *
+ * Only created by the runtime.
+ */
+ private ClassExt() {}
+}
diff --git a/libart/src/main/java/dalvik/system/VMRuntime.java b/libart/src/main/java/dalvik/system/VMRuntime.java
index e53e1032b..6a673f2a4 100644
--- a/libart/src/main/java/dalvik/system/VMRuntime.java
+++ b/libart/src/main/java/dalvik/system/VMRuntime.java
@@ -16,6 +16,7 @@
package dalvik.system;
+import dalvik.annotation.optimization.FastNative;
import java.lang.ref.FinalizerReference;
import java.util.HashMap;
import java.util.Map;
@@ -50,7 +51,15 @@ public final class VMRuntime {
ABI_TO_INSTRUCTION_SET_MAP.put("arm64-v8a", "arm64");
}
- private int targetSdkVersion;
+ /**
+ * Magic version number for a current development build, which has not
+ * yet turned into an official release. This number must be larger than
+ * any released version in {@code android.os.Build.VERSION_CODES}.
+ * @hide
+ */
+ public static final int SDK_VERSION_CUR_DEVELOPMENT = 10000;
+
+ private int targetSdkVersion = SDK_VERSION_CUR_DEVELOPMENT;
/**
* Prevents this class from being instantiated.
@@ -102,11 +111,13 @@ public static VMRuntime getRuntime() {
/**
* Returns whether the VM is running in 64-bit mode.
*/
+ @FastNative
public native boolean is64Bit();
/**
* Returns whether the VM is running with JNI checking enabled.
*/
+ @FastNative
public native boolean isCheckJniEnabled();
/**
@@ -151,10 +162,7 @@ public float setTargetHeapUtilization(float newTarget) {
/**
* Sets the target SDK version. Should only be called before the
* app starts to run, because it may change the VM's behavior in
- * dangerous ways. Use 0 to mean "current" (since callers won't
- * necessarily know the actual current SDK version, and the
- * allocated version numbers start at 1), and 10000 to mean
- * CUR_DEVELOPMENT.
+ * dangerous ways. Defaults to {@link #SDK_VERSION_CUR_DEVELOPMENT}.
*/
public synchronized void setTargetSdkVersion(int targetSdkVersion) {
this.targetSdkVersion = targetSdkVersion;
@@ -255,6 +263,7 @@ public long getExternalBytesAllocated() {
* This is used to implement native allocations on the Java heap, such as DirectByteBuffers
* and Bitmaps.
*/
+ @FastNative
public native Object newNonMovableArray(Class> componentType, int length);
/**
@@ -262,12 +271,14 @@ public long getExternalBytesAllocated() {
* avoiding any padding after the array. The amount of padding varies depending on the
* componentType and the memory allocator implementation.
*/
+ @FastNative
public native Object newUnpaddedArray(Class> componentType, int minLength);
/**
* Returns the address of array[0]. This differs from using JNI in that JNI might lie and
* give you the address of a copy of the array when in forcecopy mode.
*/
+ @FastNative
public native long addressOf(Object array);
/**
@@ -285,11 +296,13 @@ public long getExternalBytesAllocated() {
/**
* Returns true if either a Java debugger or native debugger is active.
*/
+ @FastNative
public native boolean isDebuggerActive();
/**
* Returns true if native debugging is on.
*/
+ @FastNative
public native boolean isNativeDebuggable();
/**
@@ -352,10 +365,11 @@ public static void runFinalization(long timeout) {
public native void preloadDexCaches();
/**
- * Register application info
+ * Register application info.
+ * @param profileFile the path of the file where the profile information should be stored.
+ * @param codePaths the code paths that should be profiled.
*/
- public static native void registerAppInfo(String packageName, String appDir,
- String[] codePaths, String foreignDexProfileDir);
+ public static native void registerAppInfo(String profileFile, String[] codePaths);
/**
* Returns the runtime instruction set corresponding to a given ABI. Multiple
diff --git a/libart/src/main/java/dalvik/system/VMStack.java b/libart/src/main/java/dalvik/system/VMStack.java
index b69ab6009..ef911c438 100644
--- a/libart/src/main/java/dalvik/system/VMStack.java
+++ b/libart/src/main/java/dalvik/system/VMStack.java
@@ -16,6 +16,8 @@
package dalvik.system;
+import dalvik.annotation.optimization.FastNative;
+
/**
* Provides a limited interface to the Dalvik VM stack. This class is mostly
* used for implementing security checks.
@@ -29,6 +31,7 @@ public final class VMStack {
* @return the requested class loader, or {@code null} if this is the
* bootstrap class loader.
*/
+ @FastNative
native public static ClassLoader getCallingClassLoader();
/**
@@ -45,12 +48,14 @@ public static Class> getStackClass1() {
*
* @return the requested class, or {@code null}.
*/
+ @FastNative
native public static Class> getStackClass2();
/**
* Returns the first ClassLoader on the call stack that isn't the
* bootstrap class loader.
*/
+ @FastNative
public native static ClassLoader getClosestUserClassLoader();
/**
@@ -61,6 +66,7 @@ public static Class> getStackClass1() {
* @return an array of stack trace elements, or null if the thread
* doesn't have a stack trace (e.g. because it exited)
*/
+ @FastNative
native public static StackTraceElement[] getThreadStackTrace(Thread t);
/**
@@ -74,6 +80,7 @@ public static Class> getStackClass1() {
* desired. Unused elements will be filled with null values.
* @return the number of elements filled
*/
+ @FastNative
native public static int fillStackTraceElements(Thread t,
StackTraceElement[] stackTraceElements);
}
diff --git a/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java b/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java
index 13e931786..5a84c8e53 100644
--- a/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java
+++ b/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java
@@ -106,6 +106,9 @@ public final class AndroidHardcodedSystemProperties {
// Hardcode default value for AVA. b/28174137
{ "com.sun.security.preserveOldDCEncoding", null },
+
+ // Hardcode default value for LogManager. b/28174137
+ { "java.util.logging.manager", null },
};
}
diff --git a/libart/src/main/java/java/lang/CaseMapper.java b/libart/src/main/java/java/lang/CaseMapper.java
index 7f9d2e307..66d503085 100644
--- a/libart/src/main/java/java/lang/CaseMapper.java
+++ b/libart/src/main/java/java/lang/CaseMapper.java
@@ -50,7 +50,7 @@ public static String toLowerCase(Locale locale, String s) {
return ICU.toLowerCase(s, locale);
}
- String newString = null;
+ char[] newValue = null;
for (int i = 0, end = s.length(); i < end; ++i) {
char ch = s.charAt(i);
char newCh;
@@ -63,13 +63,14 @@ public static String toLowerCase(Locale locale, String s) {
newCh = Character.toLowerCase(ch);
}
if (ch != newCh) {
- if (newString == null) {
- newString = StringFactory.newStringFromString(s);
+ if (newValue == null) {
+ newValue = new char[end];
+ s.getCharsNoCheck(0, end, newValue, 0);
}
- newString.setCharAt(i, newCh);
+ newValue[i] = newCh;
}
}
- return newString != null ? newString : s;
+ return newValue != null ? new String(newValue) : s;
}
/**
@@ -152,9 +153,8 @@ public static String toUpperCase(Locale locale, String s, int count) {
}
char[] output = null;
- String newString = null;
int i = 0;
- for (int o = 0, end = count; o < end; o++) {
+ for (int o = 0; o < count; o++) {
char ch = s.charAt(o);
if (Character.isHighSurrogate(ch)) {
return ICU.toUpperCase(s, locale);
@@ -170,10 +170,10 @@ public static String toUpperCase(Locale locale, String s, int count) {
if (output != null) {
output[i++] = upch;
} else if (ch != upch) {
- if (newString == null) {
- newString = StringFactory.newStringFromString(s);
- }
- newString.setCharAt(o, upch);
+ output = new char[count];
+ i = o;
+ s.getCharsNoCheck(0, i, output, 0);
+ output[i++] = upch;
}
} else {
int target = index * 3;
@@ -181,11 +181,7 @@ public static String toUpperCase(Locale locale, String s, int count) {
if (output == null) {
output = new char[count + (count / 6) + 2];
i = o;
- if (newString != null) {
- System.arraycopy(newString.toCharArray(), 0, output, 0, i);
- } else {
- System.arraycopy(s.toCharArray(), 0, output, 0, i);
- }
+ s.getCharsNoCheck(0, i, output, 0);
} else if (i + (val3 == 0 ? 1 : 2) >= output.length) {
char[] newoutput = new char[output.length + (count / 6) + 3];
System.arraycopy(output, 0, newoutput, 0, output.length);
@@ -202,11 +198,7 @@ public static String toUpperCase(Locale locale, String s, int count) {
}
}
if (output == null) {
- if (newString != null) {
- return newString;
- } else {
- return s;
- }
+ return s;
}
return output.length == i || output.length - i < 8 ? new String(0, i, output) : new String(output, 0, i);
}
diff --git a/libart/src/main/java/java/lang/DexCache.java b/libart/src/main/java/java/lang/DexCache.java
index 37c1a1df0..864196df9 100644
--- a/libart/src/main/java/java/lang/DexCache.java
+++ b/libart/src/main/java/java/lang/DexCache.java
@@ -32,27 +32,36 @@
package java.lang;
-import com.android.dex.Dex;
+import dalvik.annotation.optimization.FastNative;
/**
* A dex cache holds resolved copies of strings, fields, methods, and classes from the dexfile.
*/
final class DexCache {
- /** Lazily initialized dex file wrapper. Volatile to avoid double-check locking issues. */
- private volatile Dex dex;
-
/** The location of the associated dex file. */
- String location;
+ private String location;
/** Holds C pointer to dexFile. */
private long dexFile;
+ /**
+ * References to CallSite (C array pointer) as they become resolved following
+ * interpreter semantics.
+ */
+ private long resolvedCallSites;
+
/**
* References to fields (C array pointer) as they become resolved following
* interpreter semantics. May refer to fields defined in other dex files.
*/
private long resolvedFields;
+ /**
+ * References to MethodType (C array pointer) as they become resolved following
+ * interpreter semantics.
+ */
+ private long resolvedMethodTypes;
+
/**
* References to methods (C array pointer) as they become resolved following
* interpreter semantics. May refer to methods defined in other dex files.
@@ -71,11 +80,21 @@ final class DexCache {
*/
private long strings;
+ /**
+ * The number of elements in the native call sites array.
+ */
+ private int numResolvedCallSites;
+
/**
* The number of elements in the native resolvedFields array.
*/
private int numResolvedFields;
+ /**
+ * The number of elements in the native method types array.
+ */
+ private int numResolvedMethodTypes;
+
/**
* The number of elements in the native resolvedMethods array.
*/
@@ -93,24 +112,5 @@ final class DexCache {
// Only created by the VM.
private DexCache() {}
-
- Dex getDex() {
- Dex result = dex;
- if (result == null) {
- synchronized (this) {
- result = dex;
- if (result == null) {
- dex = result = getDexNative();
- }
- }
- }
- return result;
- }
-
- native Class> getResolvedType(int typeIndex);
- native String getResolvedString(int stringIndex);
- native void setResolvedType(int typeIndex, Class> type);
- native void setResolvedString(int stringIndex, String string);
- private native Dex getDexNative();
}
diff --git a/libart/src/main/java/java/lang/StringFactory.java b/libart/src/main/java/java/lang/StringFactory.java
index 0a8974041..208a657fb 100644
--- a/libart/src/main/java/java/lang/StringFactory.java
+++ b/libart/src/main/java/java/lang/StringFactory.java
@@ -17,6 +17,7 @@
package java.lang;
+import dalvik.annotation.optimization.FastNative;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
@@ -53,6 +54,7 @@ public static String newStringFromBytes(byte[] data, int offset, int byteCount)
return newStringFromBytes(data, offset, byteCount, Charset.defaultCharset());
}
+ @FastNative
public static native String newStringFromBytes(byte[] data, int high, int offset, int byteCount);
public static String newStringFromBytes(byte[] data, int offset, int byteCount, String charsetName) throws UnsupportedEncodingException {
@@ -219,8 +221,10 @@ public static String newStringFromChars(char[] data, int offset, int charCount)
}
// The char array passed as {@code java_data} must not be a null reference.
+ @FastNative
static native String newStringFromChars(int offset, int charCount, char[] data);
+ @FastNative
public static native String newStringFromString(String toCopy);
public static String newStringFromStringBuffer(StringBuffer stringBuffer) {
diff --git a/libart/src/main/java/java/lang/VMClassLoader.java b/libart/src/main/java/java/lang/VMClassLoader.java
index a9d6253ad..d44f888f4 100644
--- a/libart/src/main/java/java/lang/VMClassLoader.java
+++ b/libart/src/main/java/java/lang/VMClassLoader.java
@@ -16,6 +16,7 @@
package java.lang;
+import dalvik.annotation.optimization.FastNative;
import java.io.File;
import java.io.IOException;
import java.net.URL;
@@ -37,7 +38,6 @@ class VMClassLoader {
*/
private static ClassPathURLStreamHandler[] createBootClassPathUrlHandlers() {
String[] bootClassPathEntries = getBootClassPathEntries();
- ArrayList zipFileUris = new ArrayList(bootClassPathEntries.length);
ArrayList urlStreamHandlers =
new ArrayList(bootClassPathEntries.length);
for (String bootClassPathEntry : bootClassPathEntries) {
@@ -47,7 +47,6 @@ private static ClassPathURLStreamHandler[] createBootClassPathUrlHandlers() {
// We assume all entries are zip or jar files.
URLStreamHandler urlStreamHandler =
new ClassPathURLStreamHandler(bootClassPathEntry);
- zipFileUris.add(entryUri);
urlStreamHandlers.add(urlStreamHandler);
} catch (IOException e) {
// Skip it
@@ -87,6 +86,7 @@ static List getResources(String name) {
return list;
}
+ @FastNative
native static Class findLoadedClass(ClassLoader cl, String name);
/**
diff --git a/libart/src/main/java/java/lang/reflect/AbstractMethod.java b/libart/src/main/java/java/lang/reflect/AbstractMethod.java
deleted file mode 100644
index 01267655a..000000000
--- a/libart/src/main/java/java/lang/reflect/AbstractMethod.java
+++ /dev/null
@@ -1,372 +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.
- */
-/*
- * Copyright (C) 2012 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 java.lang.reflect;
-
-import com.android.dex.Dex;
-import java.lang.annotation.Annotation;
-import java.util.List;
-import libcore.reflect.GenericSignatureParser;
-import libcore.reflect.ListOfTypes;
-import libcore.reflect.Types;
-import libcore.util.EmptyArray;
-
-/**
- * This class represents an abstract method. Abstract methods are either methods or constructors.
- * @hide
- */
-public abstract class AbstractMethod extends AccessibleObject {
- /** Bits encoding access (e.g. public, private) as well as other runtime specific flags */
- protected int accessFlags;
-
- /**
- * The ArtMethod associated with this Method, requried for dispatching due to entrypoints
- * Classloader is held live by the declaring class.
- * Hidden to workaround b/16828157.
- * @hide
- */
- protected long artMethod;
-
- /** Method's declaring class */
- protected Class> declaringClass;
-
- /** Overriden method's declaring class (same as declaringClass unless declaringClass
- * is a proxy class) */
- protected Class> declaringClassOfOverriddenMethod;
-
- /** The method index of this method within its defining dex file */
- protected int dexMethodIndex;
-
- /**
- * Hidden to workaround b/16828157.
- * @hide
- */
- protected AbstractMethod() {
- }
-
- public T getAnnotation(Class annotationClass) {
- return super.getAnnotation(annotationClass);
- }
-
- /**
- * We insert native method stubs for abstract methods so we don't have to
- * check the access flags at the time of the method call. This results in
- * "native abstract" methods, which can't exist. If we see the "abstract"
- * flag set, clear the "native" flag.
- *
- * We also move the DECLARED_SYNCHRONIZED flag into the SYNCHRONIZED
- * position, because the callers of this function are trying to convey
- * the "traditional" meaning of the flags to their callers.
- */
- private static int fixMethodFlags(int flags) {
- if ((flags & Modifier.ABSTRACT) != 0) {
- flags &= ~Modifier.NATIVE;
- }
- flags &= ~Modifier.SYNCHRONIZED;
- int ACC_DECLARED_SYNCHRONIZED = 0x00020000;
- if ((flags & ACC_DECLARED_SYNCHRONIZED) != 0) {
- flags |= Modifier.SYNCHRONIZED;
- }
- return flags & 0xffff; // mask out bits not used by Java
- }
-
- int getModifiers() {
- return fixMethodFlags(accessFlags);
- }
-
- boolean isVarArgs() {
- return (accessFlags & Modifier.VARARGS) != 0;
- }
-
- boolean isBridge() {
- return (accessFlags & Modifier.BRIDGE) != 0;
- }
-
- boolean isSynthetic() {
- return (accessFlags & Modifier.SYNTHETIC) != 0;
- }
-
- boolean isDefault() {
- return (accessFlags & Modifier.DEFAULT) != 0;
- }
-
- /**
- * @hide
- */
- public final int getAccessFlags() {
- return accessFlags;
- }
-
- /**
- * Returns the class that declares this constructor or method.
- */
- Class> getDeclaringClass() {
- return declaringClass;
- }
-
- /**
- * Returns the index of this method's ID in its dex file.
- *
- * @hide
- */
- public final int getDexMethodIndex() {
- return dexMethodIndex;
- }
-
- /**
- * Returns the name of the method or constructor represented by this
- * instance.
- *
- * @return the name of this method
- */
- abstract public String getName();
-
- /**
- * Returns an array of {@code Class} objects associated with the parameter types of this
- * abstract method. If the method was declared with no parameters, an
- * empty array will be returned.
- *
- * @return the parameter types
- */
- Class>[] getParameterTypes() {
- Dex dex = declaringClassOfOverriddenMethod.getDex();
- short[] types = dex.parameterTypeIndicesFromMethodIndex(dexMethodIndex);
- if (types.length == 0) {
- return EmptyArray.CLASS;
- }
- Class>[] parametersArray = new Class[types.length];
- for (int i = 0; i < types.length; i++) {
- // Note, in the case of a Proxy the dex cache types are equal.
- parametersArray[i] = declaringClassOfOverriddenMethod.getDexCacheType(dex, types[i]);
- }
- return parametersArray;
- }
-
- /**
- * Returns true if {@code other} has the same declaring class, name,
- * parameters and return type as this method.
- */
- @Override public boolean equals(Object other) {
- if (!(other instanceof AbstractMethod)) {
- return false;
- }
- // Exactly one instance of each member in this runtime, todo, does this work for proxies?
- AbstractMethod otherMethod = (AbstractMethod) other;
- return this.declaringClass == otherMethod.declaringClass &&
- this.dexMethodIndex == otherMethod.dexMethodIndex;
- }
-
- String toGenericString() {
- return toGenericStringHelper();
- }
-
- Type[] getGenericParameterTypes() {
- return Types.getTypeArray(getMethodOrConstructorGenericInfo().genericParameterTypes, false);
- }
-
- Type[] getGenericExceptionTypes() {
- return Types.getTypeArray(getMethodOrConstructorGenericInfo().genericExceptionTypes, false);
- }
-
- @Override public native Annotation[] getDeclaredAnnotations();
-
- @Override public boolean isAnnotationPresent(Class extends Annotation> annotationType) {
- if (annotationType == null) {
- throw new NullPointerException("annotationType == null");
- }
- return isAnnotationPresentNative(annotationType);
- }
-
- private native boolean isAnnotationPresentNative(Class extends Annotation> annotationType);
-
- public Annotation[] getAnnotations() {
- return super.getAnnotations();
- }
-
- /**
- * Returns an array of arrays that represent the annotations of the formal
- * parameters of this method. If there are no parameters on this method,
- * then an empty array is returned. If there are no annotations set, then
- * and array of empty arrays is returned.
- *
- * @return an array of arrays of {@code Annotation} instances
- */
- public abstract Annotation[][] getParameterAnnotations();
-
- /**
- * Returns the constructor's signature in non-printable form. This is called
- * (only) from IO native code and needed for deriving the serialVersionUID
- * of the class
- *
- * @return The constructor's signature.
- */
- @SuppressWarnings("unused")
- abstract String getSignature();
-
- static final class GenericInfo {
- final ListOfTypes genericExceptionTypes;
- final ListOfTypes genericParameterTypes;
- final Type genericReturnType;
- final TypeVariable>[] formalTypeParameters;
-
- GenericInfo(ListOfTypes exceptions, ListOfTypes parameters, Type ret,
- TypeVariable>[] formal) {
- genericExceptionTypes = exceptions;
- genericParameterTypes = parameters;
- genericReturnType = ret;
- formalTypeParameters = formal;
- }
- }
-
- /**
- * Returns generic information associated with this method/constructor member.
- */
- final GenericInfo getMethodOrConstructorGenericInfo() {
- String signatureAttribute = getSignatureAttribute();
- Member member;
- Class>[] exceptionTypes;
- boolean method = this instanceof Method;
- if (method) {
- Method m = (Method) this;
- member = m;
- exceptionTypes = m.getExceptionTypes();
- } else {
- Constructor> c = (Constructor>) this;
- member = c;
- exceptionTypes = c.getExceptionTypes();
- }
- GenericSignatureParser parser =
- new GenericSignatureParser(member.getDeclaringClass().getClassLoader());
- if (method) {
- parser.parseForMethod((GenericDeclaration) this, signatureAttribute, exceptionTypes);
- } else {
- parser.parseForConstructor((GenericDeclaration) this,
- signatureAttribute,
- exceptionTypes);
- }
- return new GenericInfo(parser.exceptionTypes, parser.parameterTypes,
- parser.returnType, parser.formalTypeParameters);
- }
-
- private String getSignatureAttribute() {
- String[] annotation = getSignatureAnnotation();
- if (annotation == null) {
- return null;
- }
- StringBuilder result = new StringBuilder();
- for (String s : annotation) {
- result.append(s);
- }
- return result.toString();
- }
-
- private native String[] getSignatureAnnotation();
-
- protected boolean equalMethodParameters(Class>[] params) {
- Dex dex = declaringClassOfOverriddenMethod.getDex();
- short[] types = dex.parameterTypeIndicesFromMethodIndex(dexMethodIndex);
- if (types.length != params.length) {
- return false;
- }
- for (int i = 0; i < types.length; i++) {
- if (declaringClassOfOverriddenMethod.getDexCacheType(dex, types[i]) != params[i]) {
- return false;
- }
- }
- return true;
- }
-
- protected int compareParameters(Class>[] params) {
- Dex dex = declaringClassOfOverriddenMethod.getDex();
- short[] types = dex.parameterTypeIndicesFromMethodIndex(dexMethodIndex);
- int length = Math.min(types.length, params.length);
- for (int i = 0; i < length; i++) {
- Class> aType = declaringClassOfOverriddenMethod.getDexCacheType(dex, types[i]);
- Class> bType = params[i];
- if (aType != bType) {
- int comparison = aType.getName().compareTo(bType.getName());
- if (comparison != 0) {
- return comparison;
- }
- }
- }
- return types.length - params.length;
- }
-
- /**
- * Helper for Method and Constructor for toGenericString
- */
- final String toGenericStringHelper() {
- StringBuilder sb = new StringBuilder(80);
- GenericInfo info = getMethodOrConstructorGenericInfo();
- int modifiers = ((Member)this).getModifiers();
- // append modifiers if any
- if (modifiers != 0) {
- sb.append(Modifier.toString(modifiers & ~Modifier.VARARGS)).append(' ');
- }
- // append type parameters
- if (info.formalTypeParameters != null && info.formalTypeParameters.length > 0) {
- sb.append('<');
- for (int i = 0; i < info.formalTypeParameters.length; i++) {
- Types.appendGenericType(sb, info.formalTypeParameters[i]);
- if (i < info.formalTypeParameters.length - 1) {
- sb.append(",");
- }
- }
- sb.append("> ");
- }
- Class> declaringClass = ((Member) this).getDeclaringClass();
- if (this instanceof Constructor) {
- // append constructor name
- Types.appendTypeName(sb, declaringClass);
- } else {
- // append return type
- Types.appendGenericType(sb, Types.getType(info.genericReturnType));
- sb.append(' ');
- // append method name
- Types.appendTypeName(sb, declaringClass);
- sb.append(".").append(((Method) this).getName());
- }
- // append parameters
- sb.append('(');
- Types.appendArrayGenericType(sb, info.genericParameterTypes.getResolvedTypes());
- sb.append(')');
- // append exceptions if any
- Type[] genericExceptionTypeArray =
- Types.getTypeArray(info.genericExceptionTypes, false);
- if (genericExceptionTypeArray.length > 0) {
- sb.append(" throws ");
- Types.appendArrayGenericType(sb, genericExceptionTypeArray);
- }
- return sb.toString();
- }
-}
diff --git a/luni/src/benchmark/native/libcore_io_Memory_bench.cpp b/luni/src/benchmark/native/libcore_io_Memory_bench.cpp
index b5a9d5f3d..ce66067e0 100644
--- a/luni/src/benchmark/native/libcore_io_Memory_bench.cpp
+++ b/luni/src/benchmark/native/libcore_io_Memory_bench.cpp
@@ -21,7 +21,7 @@
template
void swap_bench(benchmark::State& state, void (*swap_func)(T*, const T*, size_t)) {
- size_t num_elements = state.range_x();
+ size_t num_elements = state.range(0);
T* src;
T* dst;
diff --git a/luni/src/main/java/android/system/Os.java b/luni/src/main/java/android/system/Os.java
index c43c1ba21..7db7f75e2 100644
--- a/luni/src/main/java/android/system/Os.java
+++ b/luni/src/main/java/android/system/Os.java
@@ -62,6 +62,25 @@ private Os() {}
/** @hide */ public static void bind(FileDescriptor fd, SocketAddress address) throws ErrnoException, SocketException { Libcore.os.bind(fd, address); }
+ /**
+ * See capget(2) .
+ *
+ * @hide
+ */
+ public static StructCapUserData[] capget(StructCapUserHeader hdr) throws ErrnoException {
+ return Libcore.os.capget(hdr);
+ }
+
+ /**
+ * See capset(2) .
+ *
+ * @hide
+ */
+ public static void capset(StructCapUserHeader hdr, StructCapUserData[] data)
+ throws ErrnoException {
+ Libcore.os.capset(hdr, data);
+ }
+
/**
* See chmod(2) .
*/
@@ -173,6 +192,11 @@ private Os() {}
*/
public static String getenv(String name) { return Libcore.os.getenv(name); }
+ /**
+ * See getifaddrs(3) .
+ */
+ /** @hide */ public static StructIfaddrs[] getifaddrs() throws ErrnoException { return Libcore.os.getifaddrs(); }
+
/** @hide */ public static String getnameinfo(InetAddress address, int flags) throws GaiException { return Libcore.os.getnameinfo(address, flags); }
/**
@@ -221,13 +245,21 @@ private Os() {}
*/
public static int getuid() { return Libcore.os.getuid(); }
- /** @hide */ public static int getxattr(String path, String name, byte[] outValue) throws ErrnoException { return Libcore.os.getxattr(path, name, outValue); }
+ /**
+ * See getxattr(2)
+ */
+ public static byte[] getxattr(String path, String name) throws ErrnoException { return Libcore.os.getxattr(path, name); }
/**
* See if_indextoname(3) .
*/
public static String if_indextoname(int index) { return Libcore.os.if_indextoname(index); }
+ /**
+ * See if_nametoindex(3) .
+ */
+ public static int if_nametoindex(String name) { return Libcore.os.if_nametoindex(name); }
+
/**
* See inet_pton(3) .
*/
@@ -261,6 +293,11 @@ private Os() {}
*/
public static void listen(FileDescriptor fd, int backlog) throws ErrnoException { Libcore.os.listen(fd, backlog); }
+ /**
+ * See listxattr(2)
+ */
+ public static String[] listxattr(String path) throws ErrnoException { return Libcore.os.listxattr(path); }
+
/**
* See lseek(2) .
*/
@@ -333,7 +370,7 @@ private Os() {}
public static int poll(StructPollfd[] fds, int timeoutMs) throws ErrnoException { return Libcore.os.poll(fds, timeoutMs); }
/**
- * See posix_fallocate(2) .
+ * See posix_fallocate(3) .
*/
public static void posix_fallocate(FileDescriptor fd, long offset, long length) throws ErrnoException { Libcore.os.posix_fallocate(fd, offset, length); }
@@ -397,7 +434,10 @@ private Os() {}
*/
public static void remove(String path) throws ErrnoException { Libcore.os.remove(path); }
- /** @hide */ public static void removexattr(String path, String name) throws ErrnoException { Libcore.os.removexattr(path, name); }
+ /**
+ * See removexattr(2) .
+ */
+ public static void removexattr(String path, String name) throws ErrnoException { Libcore.os.removexattr(path, name); }
/**
* See rename(2) .
@@ -466,7 +506,12 @@ private Os() {}
/** @hide */ public static void setsockoptByte(FileDescriptor fd, int level, int option, int value) throws ErrnoException { Libcore.os.setsockoptByte(fd, level, option, value); }
/** @hide */ public static void setsockoptIfreq(FileDescriptor fd, int level, int option, String value) throws ErrnoException { Libcore.os.setsockoptIfreq(fd, level, option, value); }
- /** @hide */ public static void setsockoptInt(FileDescriptor fd, int level, int option, int value) throws ErrnoException { Libcore.os.setsockoptInt(fd, level, option, value); }
+
+ /**
+ * See setsockopt(2) .
+ */
+ public static void setsockoptInt(FileDescriptor fd, int level, int option, int value) throws ErrnoException { Libcore.os.setsockoptInt(fd, level, option, value); }
+
/** @hide */ public static void setsockoptIpMreqn(FileDescriptor fd, int level, int option, int value) throws ErrnoException { Libcore.os.setsockoptIpMreqn(fd, level, option, value); }
/** @hide */ public static void setsockoptGroupReq(FileDescriptor fd, int level, int option, StructGroupReq value) throws ErrnoException { Libcore.os.setsockoptGroupReq(fd, level, option, value); }
/** @hide */ public static void setsockoptGroupSourceReq(FileDescriptor fd, int level, int option, StructGroupSourceReq value) throws ErrnoException { Libcore.os.setsockoptGroupSourceReq(fd, level, option, value); }
@@ -478,7 +523,10 @@ private Os() {}
*/
public static void setuid(int uid) throws ErrnoException { Libcore.os.setuid(uid); }
- /** @hide */ public static void setxattr(String path, String name, byte[] value, int flags) throws ErrnoException { Libcore.os.setxattr(path, name, value, flags); };
+ /**
+ * See setxattr(2)
+ */
+ public static void setxattr(String path, String name, byte[] value, int flags) throws ErrnoException { Libcore.os.setxattr(path, name, value, flags); };
/**
* See shutdown(2) .
diff --git a/luni/src/main/java/android/system/OsConstants.java b/luni/src/main/java/android/system/OsConstants.java
index 31f84e9af..adad301e0 100644
--- a/luni/src/main/java/android/system/OsConstants.java
+++ b/luni/src/main/java/android/system/OsConstants.java
@@ -23,6 +23,20 @@ public final class OsConstants {
private OsConstants() {
}
+ /**
+ * Returns the index of the element in the cap_user_data array that this capability is stored
+ * in.
+ * @hide
+ */
+ public static int CAP_TO_INDEX(int x) { return x >>> 5; }
+
+ /**
+ * Returns the mask for the given capability. This is relative to the capability's cap_user_data
+ * element, the index of which can be retrieved with CAP_TO_INDEX.
+ * @hide
+ */
+ public static int CAP_TO_MASK(int x) { return 1 << (x & 31); }
+
/**
* Tests whether the given mode is a block device.
*/
@@ -264,6 +278,10 @@ private OsConstants() {
public static final int F_SETOWN = placeholder();
public static final int F_UNLCK = placeholder();
public static final int F_WRLCK = placeholder();
+ /** @hide */ public static final int ICMP_ECHO = placeholder();
+ /** @hide */ public static final int ICMP_ECHOREPLY = placeholder();
+ /** @hide */ public static final int ICMP6_ECHO_REQUEST = placeholder();
+ /** @hide */ public static final int ICMP6_ECHO_REPLY = placeholder();
public static final int IFA_F_DADFAILED = placeholder();
public static final int IFA_F_DEPRECATED = placeholder();
public static final int IFA_F_HOMEADDRESS = placeholder();
@@ -309,12 +327,14 @@ private OsConstants() {
public static final int IPV6_TCLASS = placeholder();
public static final int IPV6_UNICAST_HOPS = placeholder();
public static final int IPV6_V6ONLY = placeholder();
+ /** @hide */ public static final int IP_MULTICAST_ALL = placeholder();
public static final int IP_MULTICAST_IF = placeholder();
public static final int IP_MULTICAST_LOOP = placeholder();
public static final int IP_MULTICAST_TTL = placeholder();
/** @hide */ public static final int IP_RECVTOS = placeholder();
public static final int IP_TOS = placeholder();
public static final int IP_TTL = placeholder();
+ /** @hide */ public static final int _LINUX_CAPABILITY_VERSION_3 = placeholder();
public static final int MAP_FIXED = placeholder();
/** @hide */ public static final int MAP_POPULATE = placeholder();
public static final int MAP_PRIVATE = placeholder();
@@ -367,6 +387,8 @@ private OsConstants() {
public static final int POLLRDNORM = placeholder();
public static final int POLLWRBAND = placeholder();
public static final int POLLWRNORM = placeholder();
+ /** @hide */ public static final int PR_CAP_AMBIENT = placeholder();
+ /** @hide */ public static final int PR_CAP_AMBIENT_RAISE = placeholder();
public static final int PR_GET_DUMPABLE = placeholder();
public static final int PR_SET_DUMPABLE = placeholder();
public static final int PR_SET_NO_NEW_PRIVS = placeholder();
@@ -444,6 +466,7 @@ private OsConstants() {
public static final int SO_BINDTODEVICE = placeholder();
public static final int SO_BROADCAST = placeholder();
public static final int SO_DEBUG = placeholder();
+ /** @hide */ public static final int SO_DOMAIN = placeholder();
public static final int SO_DONTROUTE = placeholder();
public static final int SO_ERROR = placeholder();
public static final int SO_KEEPALIVE = placeholder();
@@ -451,6 +474,7 @@ private OsConstants() {
public static final int SO_OOBINLINE = placeholder();
public static final int SO_PASSCRED = placeholder();
public static final int SO_PEERCRED = placeholder();
+ /** @hide */ public static final int SO_PROTOCOL = placeholder();
public static final int SO_RCVBUF = placeholder();
public static final int SO_RCVLOWAT = placeholder();
public static final int SO_RCVTIMEO = placeholder();
@@ -495,6 +519,7 @@ private OsConstants() {
public static final int S_IXOTH = placeholder();
public static final int S_IXUSR = placeholder();
public static final int TCP_NODELAY = placeholder();
+ public static final int TCP_USER_TIMEOUT = placeholder();
/** @hide */ public static final int TIOCOUTQ = placeholder();
/** @hide */ public static final int UNIX_PATH_MAX = placeholder();
public static final int WCONTINUED = placeholder();
diff --git a/luni/src/main/java/android/system/StructCapUserData.java b/luni/src/main/java/android/system/StructCapUserData.java
new file mode 100644
index 000000000..af63caf76
--- /dev/null
+++ b/luni/src/main/java/android/system/StructCapUserData.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 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 android.system;
+
+import libcore.util.Objects;
+
+/**
+ * Corresponds to Linux' __user_cap_data_struct for capget and capset.
+ *
+ * @hide
+ */
+public final class StructCapUserData {
+ /** Effective capability mask. */
+ public final int effective; /* __u32 */
+
+ /** Permitted capability mask. */
+ public final int permitted; /* __u32 */
+
+ /** Inheritable capability mask. */
+ public final int inheritable; /* __u32 */
+
+ /**
+ * Constructs an instance with the given field values.
+ */
+ public StructCapUserData(int effective, int permitted, int inheritable) {
+ this.effective = effective;
+ this.permitted = permitted;
+ this.inheritable = inheritable;
+ }
+
+ @Override public String toString() {
+ return Objects.toString(this);
+ }
+}
diff --git a/luni/src/main/java/android/system/StructCapUserHeader.java b/luni/src/main/java/android/system/StructCapUserHeader.java
new file mode 100644
index 000000000..abbb3954c
--- /dev/null
+++ b/luni/src/main/java/android/system/StructCapUserHeader.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 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 android.system;
+
+import libcore.util.Objects;
+
+/**
+ * Corresponds to Linux' __user_cap_header_struct for capget and capset.
+ *
+ * @hide
+ */
+public final class StructCapUserHeader {
+ /**
+ * Version of the header. Note this is not final as capget() may mutate the field when an
+ * invalid version is provided. See
+ * capget(2) .
+ */
+ public int version; /* __u32 */
+
+ /** Pid of the header. The pid a call applies to. */
+ public final int pid;
+
+ /**
+ * Constructs an instance with the given field values.
+ */
+ public StructCapUserHeader(int version, int pid) {
+ this.version = version;
+ this.pid = pid;
+ }
+
+ @Override public String toString() {
+ return Objects.toString(this);
+ }
+}
diff --git a/luni/src/main/java/android/system/StructIcmpHdr.java b/luni/src/main/java/android/system/StructIcmpHdr.java
new file mode 100644
index 000000000..87ae679da
--- /dev/null
+++ b/luni/src/main/java/android/system/StructIcmpHdr.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 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 android.system;
+
+import static android.system.OsConstants.ICMP6_ECHO_REQUEST;
+import static android.system.OsConstants.ICMP_ECHO;
+
+/**
+ * Corresponds to C's {@code struct icmphdr} from linux/icmp.h and {@code struct icmp6hdr} from
+ * linux/icmpv6.h
+ *
+ * @hide
+ */
+public final class StructIcmpHdr {
+ private byte[] packet;
+
+ private StructIcmpHdr() {
+ packet = new byte[8];
+ }
+
+ /*
+ * Echo or Echo Reply Message
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type | Code | Checksum |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Identifier | Sequence Number |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Data ...
+ * +-+-+-+-+-
+ */
+ public static StructIcmpHdr IcmpEchoHdr(boolean ipv4, int seq) {
+ StructIcmpHdr hdr = new StructIcmpHdr();
+ hdr.packet[0] = ipv4 ? (byte) ICMP_ECHO : (byte) ICMP6_ECHO_REQUEST;
+ // packet[1]: Code is always zero.
+ // packet[2,3]: Checksum is computed by kernel.
+ // packet[4,5]: ID (= port) inserted by kernel.
+ hdr.packet[6] = (byte) (seq >> 8);
+ hdr.packet[7] = (byte) seq;
+ return hdr;
+ }
+
+ public byte[] getBytes() {
+ return packet.clone();
+ }
+}
diff --git a/luni/src/main/java/android/system/StructIfaddrs.java b/luni/src/main/java/android/system/StructIfaddrs.java
new file mode 100644
index 000000000..7769f282a
--- /dev/null
+++ b/luni/src/main/java/android/system/StructIfaddrs.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 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 android.system;
+
+import java.net.InetAddress;
+
+/**
+ * Information returned by {@link Os#getifaddrs}. Loosely corresponds to C's
+ * {@code struct ifaddrs} from {@code }.
+ *
+ * @hide
+ */
+public final class StructIfaddrs {
+ public final String ifa_name;
+ public final int ifa_flags;
+ public final InetAddress ifa_addr;
+ public final InetAddress ifa_netmask;
+ public final InetAddress ifa_broadaddr;
+ public final byte[] hwaddr;
+
+ /**
+ * Constructs an instance with the given field values.
+ */
+ public StructIfaddrs(String ifa_name, int ifa_flags, InetAddress ifa_addr, InetAddress ifa_netmask,
+ InetAddress ifa_broadaddr, byte[] hwaddr) {
+ this.ifa_name = ifa_name;
+ this.ifa_flags = ifa_flags;
+ this.ifa_addr = ifa_addr;
+ this.ifa_netmask = ifa_netmask;
+ this.ifa_broadaddr = ifa_broadaddr;
+ this.hwaddr = hwaddr;
+ }
+}
diff --git a/luni/src/main/java/java/lang/ref/FinalizerReference.java b/luni/src/main/java/java/lang/ref/FinalizerReference.java
index 02cfa01cd..d7e803e4f 100644
--- a/luni/src/main/java/java/lang/ref/FinalizerReference.java
+++ b/luni/src/main/java/java/lang/ref/FinalizerReference.java
@@ -16,6 +16,8 @@
package java.lang.ref;
+import dalvik.annotation.optimization.FastNative;
+
/**
* @hide
*/
@@ -100,9 +102,12 @@ private static boolean enqueueSentinelReference(Sentinel sentinel) {
// We search the list for that FinalizerReference (it should be at or near the head),
// and then put it on the queue so that it can be finalized.
for (FinalizerReference> r = head; r != null; r = r.next) {
- if (r.referent == sentinel) {
+ // Use getReferent() instead of directly accessing the referent field not to race
+ // with GC reference processing. Can't use get() either because it's overridden to
+ // return the zombie.
+ if (r.getReferent() == sentinel) {
FinalizerReference sentinelReference = (FinalizerReference) r;
- sentinelReference.referent = null;
+ sentinelReference.clearReferent();
sentinelReference.zombie = sentinel;
// Make a single element list, then enqueue the reference on the daemon unenqueued
// list. This is required instead of enqueuing directly on the finalizer queue
@@ -126,6 +131,9 @@ private static boolean enqueueSentinelReference(Sentinel sentinel) {
throw new AssertionError("newly-created live Sentinel not on list!");
}
+ @FastNative
+ private final native T getReferent();
+ @FastNative
private native boolean makeCircularListIfUnenqueued();
/**
diff --git a/luni/src/main/java/java/math/BigDecimal.java b/luni/src/main/java/java/math/BigDecimal.java
index 0e8976248..d03b66fe9 100644
--- a/luni/src/main/java/java/math/BigDecimal.java
+++ b/luni/src/main/java/java/math/BigDecimal.java
@@ -937,8 +937,14 @@ public BigDecimal multiply(BigDecimal multiplicand) {
}
/* Let be: this = [u1,s1] and multiplicand = [u2,s2] so:
* this x multiplicand = [ s1 * s2 , s1 + s2 ] */
- if(this.bitLength + multiplicand.bitLength < 64) {
- return valueOf(this.smallValue*multiplicand.smallValue, safeLongToInt(newScale));
+ if (this.bitLength + multiplicand.bitLength < 64) {
+ long unscaledValue = this.smallValue * multiplicand.smallValue;
+ // b/19185440 Case where result should be +2^63 but unscaledValue overflowed to -2^63
+ boolean longMultiplicationOverflowed = (unscaledValue == Long.MIN_VALUE) &&
+ (Math.signum(smallValue) * Math.signum(multiplicand.smallValue) > 0);
+ if (!longMultiplicationOverflowed) {
+ return valueOf(unscaledValue, safeLongToInt(newScale));
+ }
}
return new BigDecimal(this.getUnscaledValue().multiply(
multiplicand.getUnscaledValue()), safeLongToInt(newScale));
@@ -1035,10 +1041,13 @@ public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMod
if(this.bitLength < 64 && divisor.bitLength < 64 ) {
if(diffScale == 0) {
- return dividePrimitiveLongs(this.smallValue,
- divisor.smallValue,
- scale,
- roundingMode );
+ // http://b/26105053 - corner case: Long.MIN_VALUE / (-1) overflows a long
+ if (this.smallValue != Long.MIN_VALUE || divisor.smallValue != -1) {
+ return dividePrimitiveLongs(this.smallValue,
+ divisor.smallValue,
+ scale,
+ roundingMode);
+ }
} else if(diffScale > 0) {
if(diffScale < MathUtils.LONG_POWERS_OF_TEN.length &&
divisor.bitLength + LONG_POWERS_OF_TEN_BIT_LENGTH[(int)diffScale] < 64) {
@@ -1085,7 +1094,7 @@ private static BigDecimal divideBigIntegers(BigInteger scaledDividend, BigIntege
if(scaledDivisor.bitLength() < 63) { // 63 in order to avoid out of long after *2
long rem = remainder.longValue();
long divisor = scaledDivisor.longValue();
- compRem = longCompareTo(Math.abs(rem) * 2,Math.abs(divisor));
+ compRem = compareForRounding(rem, divisor);
// To look if there is a carry
compRem = roundingBehavior(quotient.testBit(0) ? 1 : 0,
sign * (5 + compRem), roundingMode);
@@ -1113,8 +1122,7 @@ private static BigDecimal dividePrimitiveLongs(long scaledDividend, long scaledD
int sign = Long.signum( scaledDividend ) * Long.signum( scaledDivisor );
if (remainder != 0) {
// Checking if: remainder * 2 >= scaledDivisor
- int compRem; // 'compare to remainder'
- compRem = longCompareTo(Math.abs(remainder) * 2,Math.abs(scaledDivisor));
+ int compRem = compareForRounding(remainder, scaledDivisor); // 'compare to remainder'
// To look if there is a carry
quotient += roundingBehavior(((int)quotient) & 1,
sign * (5 + compRem),
@@ -1340,7 +1348,7 @@ public BigDecimal divide(BigDecimal divisor, MathContext mc) {
public BigDecimal divideToIntegralValue(BigDecimal divisor) {
BigInteger integralValue; // the integer of result
BigInteger powerOfTen; // some power of ten
- BigInteger quotAndRem[] = {getUnscaledValue()};
+
long newScale = (long)this.scale - divisor.scale;
long tempScale = 0;
int i = 1;
@@ -1365,7 +1373,7 @@ public BigDecimal divideToIntegralValue(BigDecimal divisor) {
integralValue = getUnscaledValue().multiply(powerOfTen).divide( divisor.getUnscaledValue() );
// To strip trailing zeros approximating to the preferred scale
while (!integralValue.testBit(0)) {
- quotAndRem = integralValue.divideAndRemainder(TEN_POW[i]);
+ BigInteger[] quotAndRem = integralValue.divideAndRemainder(TEN_POW[i]);
if ((quotAndRem[1].signum() == 0)
&& (tempScale - i >= newScale)) {
tempScale -= i;
@@ -2700,9 +2708,56 @@ private void inplaceRound(MathContext mc) {
setUnscaledValue(integerAndFraction[0]);
}
- private static int longCompareTo(long value1, long value2) {
+ /**
+ * Returns -1, 0, and 1 if {@code value1 < value2}, {@code value1 == value2},
+ * and {@code value1 > value2}, respectively, when comparing without regard
+ * to the values' sign.
+ *
+ * Note that this implementation deals correctly with Long.MIN_VALUE,
+ * whose absolute magnitude is larger than any other {@code long} value.
+ */
+ private static int compareAbsoluteValues(long value1, long value2) {
+ // Map long values to the range -1 .. Long.MAX_VALUE so that comparison
+ // of absolute magnitude can be done using regular long arithmetics.
+ // This deals correctly with Long.MIN_VALUE, whose absolute magnitude
+ // is larger than any other long value, and which is mapped to
+ // Long.MAX_VALUE here.
+ // Values that only differ by sign get mapped to the same value, for
+ // example both +3 and -3 get mapped to +2.
+ value1 = Math.abs(value1) - 1;
+ value2 = Math.abs(value2) - 1;
+ // Unlike Long.compare(), we guarantee to return specifically -1 and +1
return value1 > value2 ? 1 : (value1 < value2 ? -1 : 0);
}
+
+ /**
+ * Compares {@code n} against {@code 0.5 * d} in absolute terms (ignoring sign)
+ * and with arithmetics that are safe against overflow or loss of precision.
+ * Returns -1 if {@code n} is less than {@code 0.5 * d}, 0 if {@code n == 0.5 * d},
+ * or +1 if {@code n > 0.5 * d} when comparing the absolute values under such
+ * arithmetics.
+ */
+ private static int compareForRounding(long n, long d) {
+ long halfD = d / 2; // rounds towards 0
+ if (n == halfD || n == -halfD) {
+ // In absolute terms: Because n == halfD, we know that 2 * n + lsb == d
+ // for some lsb value 0 or 1. This means that n == d/2 (result 0) if
+ // lsb is 0, or n < d/2 (result -1) if lsb is 1. In either case, the
+ // result is -lsb.
+ // Since we're calculating in absolute terms, we need the absolute lsb
+ // (d & 1) as opposed to the signed lsb (d % 2) which would be -1 for
+ // negative odd values of d.
+ int lsb = (int) d & 1;
+ return -lsb; // returns 0 or -1
+ } else {
+ // In absolute terms, either 2 * n + 1 < d (in the case of n < halfD),
+ // or 2 * n > d (in the case of n > halfD).
+ // In either case, comparing n against halfD gets the right result
+ // -1 or +1, respectively.
+ return compareAbsoluteValues(n, halfD);
+ }
+ }
+
/**
* This method implements an efficient rounding for numbers which unscaled
* value fits in the type {@code long}.
@@ -2724,7 +2779,7 @@ private void smallRound(MathContext mc, int discardedPrecision) {
// If the discarded fraction is non-zero perform rounding
if (fraction != 0) {
// To check if the discarded fraction >= 0.5
- compRem = longCompareTo(Math.abs(fraction) * 2, sizeOfFraction);
+ compRem = compareForRounding(fraction, sizeOfFraction);
// To look if there is a carry
integer += roundingBehavior( ((int)integer) & 1,
Long.signum(fraction) * (5 + compRem),
diff --git a/luni/src/main/java/java/math/BigInt.java b/luni/src/main/java/java/math/BigInt.java
index 2cffee652..5e28a73df 100644
--- a/luni/src/main/java/java/math/BigInt.java
+++ b/luni/src/main/java/java/math/BigInt.java
@@ -334,11 +334,11 @@ static BigInt modInverse(BigInt a, BigInt m) {
static BigInt generatePrimeDefault(int bitLength) {
BigInt r = newBigInt();
- NativeBN.BN_generate_prime_ex(r.bignum, bitLength, false, 0, 0, 0);
+ NativeBN.BN_generate_prime_ex(r.bignum, bitLength, false, 0, 0);
return r;
}
boolean isPrime(int certainty) {
- return NativeBN.BN_is_prime_ex(bignum, certainty, 0);
+ return NativeBN.BN_primality_test(bignum, certainty, false);
}
}
diff --git a/luni/src/main/java/java/math/Multiplication.java b/luni/src/main/java/java/math/Multiplication.java
index 093b1b72a..2a4285b56 100644
--- a/luni/src/main/java/java/math/Multiplication.java
+++ b/luni/src/main/java/java/math/Multiplication.java
@@ -25,13 +25,13 @@ class Multiplication {
/** Just to denote that this class can't be instantiated. */
private Multiplication() {}
- // BEGIN android-removed
+ // BEGIN Android-removed
// /**
// * Break point in digits (number of {@code int} elements)
// * between Karatsuba and Pencil and Paper multiply.
// */
// static final int whenUseKaratsuba = 63; // an heuristic value
- // END android-removed
+ // END Android-removed
/**
* An array with powers of ten that fit in the type {@code int}.
diff --git a/luni/src/main/java/java/math/NativeBN.java b/luni/src/main/java/java/math/NativeBN.java
index 64b446810..d269f2e27 100644
--- a/luni/src/main/java/java/math/NativeBN.java
+++ b/luni/src/main/java/java/math/NativeBN.java
@@ -120,12 +120,15 @@ final class NativeBN {
public static native void BN_generate_prime_ex(long ret, int bits, boolean safe,
- long add, long rem, long cb);
+ long add, long rem);
// int BN_generate_prime_ex(BIGNUM *ret, int bits, int safe,
// const BIGNUM *add, const BIGNUM *rem, BN_GENCB *cb);
- public static native boolean BN_is_prime_ex(long p, int nchecks, long cb);
- // int BN_is_prime_ex(const BIGNUM *p, int nchecks, BN_CTX *ctx, BN_GENCB *cb);
+ public static native boolean BN_primality_test(long candidate, int checks,
+ boolean do_trial_division);
+ // int BN_primality_test(int *is_probably_prime, const BIGNUM *candidate, int checks,
+ // BN_CTX *ctx, int do_trial_division, BN_GENCB *cb);
+ // Returns *is_probably_prime on success and throws an exception on error.
public static native long getNativeFinalizer();
// &BN_free
diff --git a/luni/src/main/java/java/net/DefaultFileNameMap.java b/luni/src/main/java/java/net/DefaultFileNameMap.java
index 2f254d991..6222d7576 100644
--- a/luni/src/main/java/java/net/DefaultFileNameMap.java
+++ b/luni/src/main/java/java/net/DefaultFileNameMap.java
@@ -37,6 +37,6 @@ public String getContentTypeFor(String filename) {
if (firstCharInExtension > filename.lastIndexOf('/')) {
ext = filename.substring(firstCharInExtension, lastCharInExtension);
}
- return MimeUtils.guessMimeTypeFromExtension(ext.toLowerCase(Locale.US));
+ return MimeUtils.guessMimeTypeFromExtension(ext);
}
}
diff --git a/luni/src/main/java/java/security/security.properties b/luni/src/main/java/java/security/security.properties
index 6b9007ba2..b5f4d25d0 100644
--- a/luni/src/main/java/java/security/security.properties
+++ b/luni/src/main/java/java/security/security.properties
@@ -62,3 +62,5 @@ ssl.disablePeerCertificateChainVerification=false
# Disable weak algorithms in CertPathVerifier and CertPathBuilder.
jdk.certpath.disabledAlgorithms=MD2, MD4, RSA keySize < 1024, DSA keySize < 1024, EC keySize < 160
+
+securerandom.strongAlgorithms=SHA1PRNG:AndroidOpenSSL
diff --git a/luni/src/main/java/java/util/concurrent/BrokenBarrierException.java b/luni/src/main/java/java/util/concurrent/BrokenBarrierException.java
deleted file mode 100644
index 9fe707d8e..000000000
--- a/luni/src/main/java/java/util/concurrent/BrokenBarrierException.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent;
-
-/**
- * Exception thrown when a thread tries to wait upon a barrier that is
- * in a broken state, or which enters the broken state while the thread
- * is waiting.
- *
- * @see CyclicBarrier
- *
- * @since 1.5
- * @author Doug Lea
- */
-public class BrokenBarrierException extends Exception {
- private static final long serialVersionUID = 7117394618823254244L;
-
- /**
- * Constructs a {@code BrokenBarrierException} with no specified detail
- * message.
- */
- public BrokenBarrierException() {}
-
- /**
- * Constructs a {@code BrokenBarrierException} with the specified
- * detail message.
- *
- * @param message the detail message
- */
- public BrokenBarrierException(String message) {
- super(message);
- }
-}
diff --git a/luni/src/main/java/java/util/concurrent/Callable.java b/luni/src/main/java/java/util/concurrent/Callable.java
deleted file mode 100644
index a22ec500f..000000000
--- a/luni/src/main/java/java/util/concurrent/Callable.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent;
-
-/**
- * A task that returns a result and may throw an exception.
- * Implementors define a single method with no arguments called
- * {@code call}.
- *
- *
The {@code Callable} interface is similar to {@link
- * java.lang.Runnable}, in that both are designed for classes whose
- * instances are potentially executed by another thread. A
- * {@code Runnable}, however, does not return a result and cannot
- * throw a checked exception.
- *
- *
The {@link Executors} class contains utility methods to
- * convert from other common forms to {@code Callable} classes.
- *
- * @see Executor
- * @since 1.5
- * @author Doug Lea
- * @param the result type of method {@code call}
- */
-@FunctionalInterface
-public interface Callable {
- /**
- * Computes a result, or throws an exception if unable to do so.
- *
- * @return computed result
- * @throws Exception if unable to compute a result
- */
- V call() throws Exception;
-}
diff --git a/luni/src/main/java/java/util/concurrent/CancellationException.java b/luni/src/main/java/java/util/concurrent/CancellationException.java
deleted file mode 100644
index 25ab2715a..000000000
--- a/luni/src/main/java/java/util/concurrent/CancellationException.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent;
-
-/**
- * Exception indicating that the result of a value-producing task,
- * such as a {@link FutureTask}, cannot be retrieved because the task
- * was cancelled.
- *
- * @since 1.5
- * @author Doug Lea
- */
-public class CancellationException extends IllegalStateException {
- private static final long serialVersionUID = -9202173006928992231L;
-
- /**
- * Constructs a {@code CancellationException} with no detail message.
- */
- public CancellationException() {}
-
- /**
- * Constructs a {@code CancellationException} with the specified detail
- * message.
- *
- * @param message the detail message
- */
- public CancellationException(String message) {
- super(message);
- }
-}
diff --git a/luni/src/main/java/java/util/concurrent/CompletionException.java b/luni/src/main/java/java/util/concurrent/CompletionException.java
deleted file mode 100644
index 9b905d2d3..000000000
--- a/luni/src/main/java/java/util/concurrent/CompletionException.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent;
-
-/**
- * Exception thrown when an error or other exception is encountered
- * in the course of completing a result or task.
- *
- * @since 1.8
- * @author Doug Lea
- */
-public class CompletionException extends RuntimeException {
- private static final long serialVersionUID = 7830266012832686185L;
-
- /**
- * Constructs a {@code CompletionException} with no detail message.
- * The cause is not initialized, and may subsequently be
- * initialized by a call to {@link #initCause(Throwable) initCause}.
- */
- protected CompletionException() { }
-
- /**
- * Constructs a {@code CompletionException} with the specified detail
- * message. The cause is not initialized, and may subsequently be
- * initialized by a call to {@link #initCause(Throwable) initCause}.
- *
- * @param message the detail message
- */
- protected CompletionException(String message) {
- super(message);
- }
-
- /**
- * Constructs a {@code CompletionException} with the specified detail
- * message and cause.
- *
- * @param message the detail message
- * @param cause the cause (which is saved for later retrieval by the
- * {@link #getCause()} method)
- */
- public CompletionException(String message, Throwable cause) {
- super(message, cause);
- }
-
- /**
- * Constructs a {@code CompletionException} with the specified cause.
- * The detail message is set to {@code (cause == null ? null :
- * cause.toString())} (which typically contains the class and
- * detail message of {@code cause}).
- *
- * @param cause the cause (which is saved for later retrieval by the
- * {@link #getCause()} method)
- */
- public CompletionException(Throwable cause) {
- super(cause);
- }
-}
diff --git a/luni/src/main/java/java/util/concurrent/CompletionService.java b/luni/src/main/java/java/util/concurrent/CompletionService.java
deleted file mode 100644
index 06075962e..000000000
--- a/luni/src/main/java/java/util/concurrent/CompletionService.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent;
-
-/**
- * A service that decouples the production of new asynchronous tasks
- * from the consumption of the results of completed tasks. Producers
- * {@code submit} tasks for execution. Consumers {@code take}
- * completed tasks and process their results in the order they
- * complete. A {@code CompletionService} can for example be used to
- * manage asynchronous I/O, in which tasks that perform reads are
- * submitted in one part of a program or system, and then acted upon
- * in a different part of the program when the reads complete,
- * possibly in a different order than they were requested.
- *
- * Typically, a {@code CompletionService} relies on a separate
- * {@link Executor} to actually execute the tasks, in which case the
- * {@code CompletionService} only manages an internal completion
- * queue. The {@link ExecutorCompletionService} class provides an
- * implementation of this approach.
- *
- *
Memory consistency effects: Actions in a thread prior to
- * submitting a task to a {@code CompletionService}
- * happen-before
- * actions taken by that task, which in turn happen-before
- * actions following a successful return from the corresponding {@code take()}.
- */
-public interface CompletionService {
- /**
- * Submits a value-returning task for execution and returns a Future
- * representing the pending results of the task. Upon completion,
- * this task may be taken or polled.
- *
- * @param task the task to submit
- * @return a Future representing pending completion of the task
- * @throws RejectedExecutionException if the task cannot be
- * scheduled for execution
- * @throws NullPointerException if the task is null
- */
- Future submit(Callable task);
-
- /**
- * Submits a Runnable task for execution and returns a Future
- * representing that task. Upon completion, this task may be
- * taken or polled.
- *
- * @param task the task to submit
- * @param result the result to return upon successful completion
- * @return a Future representing pending completion of the task,
- * and whose {@code get()} method will return the given
- * result value upon completion
- * @throws RejectedExecutionException if the task cannot be
- * scheduled for execution
- * @throws NullPointerException if the task is null
- */
- Future submit(Runnable task, V result);
-
- /**
- * Retrieves and removes the Future representing the next
- * completed task, waiting if none are yet present.
- *
- * @return the Future representing the next completed task
- * @throws InterruptedException if interrupted while waiting
- */
- Future take() throws InterruptedException;
-
- /**
- * Retrieves and removes the Future representing the next
- * completed task, or {@code null} if none are present.
- *
- * @return the Future representing the next completed task, or
- * {@code null} if none are present
- */
- Future poll();
-
- /**
- * Retrieves and removes the Future representing the next
- * completed task, waiting if necessary up to the specified wait
- * time if none are yet present.
- *
- * @param timeout how long to wait before giving up, in units of
- * {@code unit}
- * @param unit a {@code TimeUnit} determining how to interpret the
- * {@code timeout} parameter
- * @return the Future representing the next completed task or
- * {@code null} if the specified waiting time elapses
- * before one is present
- * @throws InterruptedException if interrupted while waiting
- */
- Future poll(long timeout, TimeUnit unit) throws InterruptedException;
-}
diff --git a/luni/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java b/luni/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java
deleted file mode 100644
index 96225b135..000000000
--- a/luni/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java
+++ /dev/null
@@ -1,851 +0,0 @@
-/*
- * Copyright (C) 2010 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 java.util.concurrent;
-
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.util.AbstractList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.ConcurrentModificationException;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.NoSuchElementException;
-import java.util.RandomAccess;
-import java.util.function.Consumer;
-import java.util.function.UnaryOperator;
-
-import libcore.util.EmptyArray;
-import libcore.util.Objects;
-
-/**
- * A thread-safe random-access list.
- *
- * Read operations (including {@link #get}) do not block and may overlap with
- * update operations. Reads reflect the results of the most recently completed
- * operations. Aggregate operations like {@link #addAll} and {@link #clear} are
- * atomic; they never expose an intermediate state.
- *
- *
Iterators of this list never throw {@link
- * ConcurrentModificationException}. When an iterator is created, it keeps a
- * copy of the list's contents. It is always safe to iterate this list, but
- * iterations may not reflect the latest state of the list.
- *
- *
Iterators returned by this list and its sub lists cannot modify the
- * underlying list. In particular, {@link Iterator#remove}, {@link
- * ListIterator#add} and {@link ListIterator#set} all throw {@link
- * UnsupportedOperationException}.
- *
- *
This class offers extended API beyond the {@link List} interface. It
- * includes additional overloads for indexed search ({@link #indexOf} and {@link
- * #lastIndexOf}) and methods for conditional adds ({@link #addIfAbsent} and
- * {@link #addAllAbsent}).
- */
-public class CopyOnWriteArrayList implements List, RandomAccess, Cloneable, Serializable {
-
- private static final long serialVersionUID = 8673264195747942595L;
-
- /**
- * Holds the latest snapshot of the list's data. This field is volatile so
- * that data can be read without synchronization. As a consequence, all
- * writes to this field must be atomic; it is an error to modify the
- * contents of an array after it has been assigned to this field.
- *
- * Synchronization is required by all update operations. This defends
- * against one update clobbering the result of another operation. For
- * example, 100 threads simultaneously calling add() will grow the list's
- * size by 100 when they have completed. No update operations are lost!
- *
- * Maintainers should be careful to read this field only once in
- * non-blocking read methods. Write methods must be synchronized to avoid
- * clobbering concurrent writes.
- */
- private transient volatile Object[] elements;
-
- /**
- * Creates a new empty instance.
- */
- public CopyOnWriteArrayList() {
- elements = EmptyArray.OBJECT;
- }
-
- /**
- * Creates a new instance containing the elements of {@code collection}.
- */
- @SuppressWarnings("unchecked")
- public CopyOnWriteArrayList(Collection extends E> collection) {
- this((E[]) collection.toArray());
- }
-
- /**
- * Creates a new instance containing the elements of {@code array}.
- */
- public CopyOnWriteArrayList(E[] array) {
- this.elements = Arrays.copyOf(array, array.length, Object[].class);
- }
-
- @Override public Object clone() {
- try {
- CopyOnWriteArrayList result = (CopyOnWriteArrayList) super.clone();
- result.elements = result.elements.clone();
- return result;
- } catch (CloneNotSupportedException e) {
- throw new AssertionError(e);
- }
- }
-
- public int size() {
- return elements.length;
- }
-
- @SuppressWarnings("unchecked")
- public E get(int index) {
- return (E) elements[index];
- }
-
- public boolean contains(Object o) {
- return indexOf(o) != -1;
- }
-
- public boolean containsAll(Collection> collection) {
- Object[] snapshot = elements;
- return containsAll(collection, snapshot, 0, snapshot.length);
- }
-
- static boolean containsAll(Collection> collection, Object[] snapshot, int from, int to) {
- for (Object o : collection) {
- if (indexOf(o, snapshot, from, to) == -1) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Searches this list for {@code object} and returns the index of the first
- * occurrence that is at or after {@code from}.
- *
- * @return the index or -1 if the object was not found.
- */
- public int indexOf(E object, int from) {
- Object[] snapshot = elements;
- return indexOf(object, snapshot, from, snapshot.length);
- }
-
- public int indexOf(Object object) {
- Object[] snapshot = elements;
- return indexOf(object, snapshot, 0, snapshot.length);
- }
-
- /**
- * Searches this list for {@code object} and returns the index of the last
- * occurrence that is before {@code to}.
- *
- * @return the index or -1 if the object was not found.
- */
- public int lastIndexOf(E object, int to) {
- Object[] snapshot = elements;
- return lastIndexOf(object, snapshot, 0, to);
- }
-
- public int lastIndexOf(Object object) {
- Object[] snapshot = elements;
- return lastIndexOf(object, snapshot, 0, snapshot.length);
- }
-
- public boolean isEmpty() {
- return elements.length == 0;
- }
-
- /**
- * Returns an {@link Iterator} that iterates over the elements of this list
- * as they were at the time of this method call. Changes to the list made
- * after this method call will not be reflected by the iterator, nor will
- * they trigger a {@link ConcurrentModificationException}.
- *
- * The returned iterator does not support {@link Iterator#remove()}.
- */
- public Iterator iterator() {
- Object[] snapshot = elements;
- return new CowIterator(snapshot, 0, snapshot.length);
- }
-
- /**
- * Returns a {@link ListIterator} that iterates over the elements of this
- * list as they were at the time of this method call. Changes to the list
- * made after this method call will not be reflected by the iterator, nor
- * will they trigger a {@link ConcurrentModificationException}.
- *
- * The returned iterator does not support {@link ListIterator#add},
- * {@link ListIterator#set} or {@link Iterator#remove()},
- */
- public ListIterator listIterator(int index) {
- Object[] snapshot = elements;
- if (index < 0 || index > snapshot.length) {
- throw new IndexOutOfBoundsException("index=" + index + ", length=" + snapshot.length);
- }
- CowIterator result = new CowIterator(snapshot, 0, snapshot.length);
- result.index = index;
- return result;
- }
-
- /**
- * Equivalent to {@code listIterator(0)}.
- */
- public ListIterator listIterator() {
- Object[] snapshot = elements;
- return new CowIterator(snapshot, 0, snapshot.length);
- }
-
- public List subList(int from, int to) {
- Object[] snapshot = elements;
- if (from < 0 || from > to || to > snapshot.length) {
- throw new IndexOutOfBoundsException("from=" + from + ", to=" + to +
- ", list size=" + snapshot.length);
- }
- return new CowSubList(snapshot, from, to);
- }
-
- public Object[] toArray() {
- return elements.clone();
- }
-
- @SuppressWarnings({"unchecked","SuspiciousSystemArraycopy"})
- public T[] toArray(T[] contents) {
- Object[] snapshot = elements;
- if (snapshot.length > contents.length) {
- return (T[]) Arrays.copyOf(snapshot, snapshot.length, contents.getClass());
- }
- System.arraycopy(snapshot, 0, contents, 0, snapshot.length);
- if (snapshot.length < contents.length) {
- contents[snapshot.length] = null;
- }
- return contents;
- }
-
- @Override public boolean equals(Object other) {
- if (other instanceof CopyOnWriteArrayList) {
- return this == other
- || Arrays.equals(elements, ((CopyOnWriteArrayList>) other).elements);
- } else if (other instanceof List) {
- Object[] snapshot = elements;
- Iterator> i = ((List>) other).iterator();
- for (Object o : snapshot) {
- if (!i.hasNext() || !Objects.equal(o, i.next())) {
- return false;
- }
- }
- return !i.hasNext();
- } else {
- return false;
- }
- }
-
- @Override public int hashCode() {
- return Arrays.hashCode(elements);
- }
-
- @Override public String toString() {
- return Arrays.toString(elements);
- }
-
- public synchronized boolean add(E e) {
- Object[] newElements = new Object[elements.length + 1];
- System.arraycopy(elements, 0, newElements, 0, elements.length);
- newElements[elements.length] = e;
- elements = newElements;
- return true;
- }
-
- public synchronized void add(int index, E e) {
- Object[] newElements = new Object[elements.length + 1];
- System.arraycopy(elements, 0, newElements, 0, index);
- newElements[index] = e;
- System.arraycopy(elements, index, newElements, index + 1, elements.length - index);
- elements = newElements;
- }
-
- public synchronized boolean addAll(Collection extends E> collection) {
- return addAll(elements.length, collection);
- }
-
- public synchronized boolean addAll(int index, Collection extends E> collection) {
- Object[] toAdd = collection.toArray();
- Object[] newElements = new Object[elements.length + toAdd.length];
- System.arraycopy(elements, 0, newElements, 0, index);
- System.arraycopy(toAdd, 0, newElements, index, toAdd.length);
- System.arraycopy(elements, index,
- newElements, index + toAdd.length, elements.length - index);
- elements = newElements;
- return toAdd.length > 0;
- }
-
- /**
- * Adds the elements of {@code collection} that are not already present in
- * this list. If {@code collection} includes a repeated value, at most one
- * occurrence of that value will be added to this list. Elements are added
- * at the end of this list.
- *
- * Callers of this method may prefer {@link CopyOnWriteArraySet}, whose
- * API is more appropriate for set operations.
- */
- public synchronized int addAllAbsent(Collection extends E> collection) {
- Object[] toAdd = collection.toArray();
- Object[] newElements = new Object[elements.length + toAdd.length];
- System.arraycopy(elements, 0, newElements, 0, elements.length);
- int addedCount = 0;
- for (Object o : toAdd) {
- if (indexOf(o, newElements, 0, elements.length + addedCount) == -1) {
- newElements[elements.length + addedCount++] = o;
- }
- }
- if (addedCount < toAdd.length) {
- newElements = Arrays.copyOfRange(
- newElements, 0, elements.length + addedCount); // trim to size
- }
- elements = newElements;
- return addedCount;
- }
-
- /**
- * Adds {@code object} to the end of this list if it is not already present.
- *
- *
Callers of this method may prefer {@link CopyOnWriteArraySet}, whose
- * API is more appropriate for set operations.
- */
- public synchronized boolean addIfAbsent(E object) {
- if (contains(object)) {
- return false;
- }
- add(object);
- return true;
- }
-
- @Override public synchronized void clear() {
- elements = EmptyArray.OBJECT;
- }
-
- public synchronized E remove(int index) {
- @SuppressWarnings("unchecked")
- E removed = (E) elements[index];
- removeRange(index, index + 1);
- return removed;
- }
-
- public synchronized boolean remove(Object o) {
- int index = indexOf(o);
- if (index == -1) {
- return false;
- }
- remove(index);
- return true;
- }
-
- public synchronized boolean removeAll(Collection> collection) {
- return removeOrRetain(collection, false, 0, elements.length) != 0;
- }
-
- public synchronized boolean retainAll(Collection> collection) {
- return removeOrRetain(collection, true, 0, elements.length) != 0;
- }
-
- @Override
- public synchronized void replaceAll(UnaryOperator operator) {
- replaceInRange(0, elements.length,operator);
- }
-
- private void replaceInRange(int from, int to, UnaryOperator operator) {
- java.util.Objects.requireNonNull(operator);
- Object[] newElements = new Object[elements.length];
- System.arraycopy(elements, 0, newElements, 0, newElements.length);
- for (int i = from; i < to; i++) {
- @SuppressWarnings("unchecked") E e = (E) elements[i];
- newElements[i] = operator.apply(e);
- }
- elements = newElements;
- }
-
- @Override
- public synchronized void sort(Comparator super E> c) {
- sortInRange(0, elements.length, c);
- }
-
- private synchronized void sortInRange(int from, int to, Comparator super E> c) {
- java.util.Objects.requireNonNull(c);
- Object[] newElements = new Object[elements.length];
- System.arraycopy(elements, 0, newElements, 0, newElements.length);
- Arrays.sort((E[])newElements, from, to, c);
- elements = newElements;
- }
-
- @Override
- public void forEach(Consumer super E> action) {
- forInRange(0, elements.length, action);
- }
-
- private void forInRange(int from, int to, Consumer super E> action) {
- java.util.Objects.requireNonNull(action);
- Object[] newElements = new Object[elements.length];
- System.arraycopy(elements, 0, newElements, 0, newElements.length);
- for (int i = from; i < to; i++) {
- action.accept((E)newElements[i]);
- }
- }
-
- /**
- * Removes or retains the elements in {@code collection}. Returns the number
- * of elements removed.
- */
- private int removeOrRetain(Collection> collection, boolean retain, int from, int to) {
- for (int i = from; i < to; i++) {
- if (collection.contains(elements[i]) == retain) {
- continue;
- }
-
- /*
- * We've encountered an element that must be removed! Create a new
- * array and copy in the surviving elements one by one.
- */
- Object[] newElements = new Object[elements.length - 1];
- System.arraycopy(elements, 0, newElements, 0, i);
- int newSize = i;
- for (int j = i + 1; j < to; j++) {
- if (collection.contains(elements[j]) == retain) {
- newElements[newSize++] = elements[j];
- }
- }
-
- /*
- * Copy the elements after 'to'. This is only useful for sub lists,
- * where 'to' will be less than elements.length.
- */
- System.arraycopy(elements, to, newElements, newSize, elements.length - to);
- newSize += (elements.length - to);
-
- if (newSize < newElements.length) {
- newElements = Arrays.copyOfRange(newElements, 0, newSize); // trim to size
- }
- int removed = elements.length - newElements.length;
- elements = newElements;
- return removed;
- }
-
- // we made it all the way through the loop without making any changes
- return 0;
- }
-
- public synchronized E set(int index, E e) {
- Object[] newElements = elements.clone();
- @SuppressWarnings("unchecked")
- E result = (E) newElements[index];
- newElements[index] = e;
- elements = newElements;
- return result;
- }
-
- private void removeRange(int from, int to) {
- Object[] newElements = new Object[elements.length - (to - from)];
- System.arraycopy(elements, 0, newElements, 0, from);
- System.arraycopy(elements, to, newElements, from, elements.length - to);
- elements = newElements;
- }
-
- static int lastIndexOf(Object o, Object[] data, int from, int to) {
- if (o == null) {
- for (int i = to - 1; i >= from; i--) {
- if (data[i] == null) {
- return i;
- }
- }
- } else {
- for (int i = to - 1; i >= from; i--) {
- if (o.equals(data[i])) {
- return i;
- }
- }
- }
- return -1;
- }
-
- static int indexOf(Object o, Object[] data, int from, int to) {
- if (o == null) {
- for (int i = from; i < to; i++) {
- if (data[i] == null) {
- return i;
- }
- }
- } else {
- for (int i = from; i < to; i++) {
- if (o.equals(data[i])) {
- return i;
- }
- }
- }
- return -1;
- }
-
- final Object[] getArray() {
- // CopyOnWriteArraySet needs this.
- return elements;
- }
-
- /**
- * The sub list is thread safe and supports non-blocking reads. Doing so is
- * more difficult than in the full list, because each read needs to examine
- * four fields worth of state:
- * - the elements array of the full list
- * - two integers for the bounds of this sub list
- * - the expected elements array (to detect concurrent modification)
- *
- * This is accomplished by aggregating the sub list's three fields into a
- * single snapshot object representing the current slice. This permits reads
- * to be internally consistent without synchronization. This takes advantage
- * of Java's concurrency semantics for final fields.
- */
- class CowSubList extends AbstractList {
-
- /*
- * An immutable snapshot of a sub list's state. By gathering all three
- * of the sub list's fields in an immutable object,
- */
- private volatile Slice slice;
-
- public CowSubList(Object[] expectedElements, int from, int to) {
- this.slice = new Slice(expectedElements, from, to);
- }
-
- @Override public int size() {
- Slice slice = this.slice;
- return slice.to - slice.from;
- }
-
- @Override public boolean isEmpty() {
- Slice slice = this.slice;
- return slice.from == slice.to;
- }
-
- @SuppressWarnings("unchecked")
- @Override public E get(int index) {
- Slice slice = this.slice;
- Object[] snapshot = elements;
- slice.checkElementIndex(index);
- slice.checkConcurrentModification(snapshot);
- return (E) snapshot[index + slice.from];
- }
-
- @Override public Iterator iterator() {
- return listIterator(0);
- }
-
- @Override public ListIterator listIterator() {
- return listIterator(0);
- }
-
- @Override public ListIterator listIterator(int index) {
- Slice slice = this.slice;
- Object[] snapshot = elements;
- slice.checkPositionIndex(index);
- slice.checkConcurrentModification(snapshot);
- CowIterator result = new CowIterator(snapshot, slice.from, slice.to);
- result.index = slice.from + index;
- return result;
- }
-
- @Override public int indexOf(Object object) {
- Slice slice = this.slice;
- Object[] snapshot = elements;
- slice.checkConcurrentModification(snapshot);
- int result = CopyOnWriteArrayList.indexOf(object, snapshot, slice.from, slice.to);
- return (result != -1) ? (result - slice.from) : -1;
- }
-
- @Override public int lastIndexOf(Object object) {
- Slice slice = this.slice;
- Object[] snapshot = elements;
- slice.checkConcurrentModification(snapshot);
- int result = CopyOnWriteArrayList.lastIndexOf(object, snapshot, slice.from, slice.to);
- return (result != -1) ? (result - slice.from) : -1;
- }
-
- @Override public boolean contains(Object object) {
- return indexOf(object) != -1;
- }
-
- @Override public boolean containsAll(Collection> collection) {
- Slice slice = this.slice;
- Object[] snapshot = elements;
- slice.checkConcurrentModification(snapshot);
- return CopyOnWriteArrayList.containsAll(collection, snapshot, slice.from, slice.to);
- }
-
- @Override public List subList(int from, int to) {
- Slice slice = this.slice;
- if (from < 0 || from > to || to > size()) {
- throw new IndexOutOfBoundsException("from=" + from + ", to=" + to +
- ", list size=" + size());
- }
- return new CowSubList(slice.expectedElements, slice.from + from, slice.from + to);
- }
-
- @Override public E remove(int index) {
- synchronized (CopyOnWriteArrayList.this) {
- slice.checkElementIndex(index);
- slice.checkConcurrentModification(elements);
- E removed = CopyOnWriteArrayList.this.remove(slice.from + index);
- slice = new Slice(elements, slice.from, slice.to - 1);
- return removed;
- }
- }
-
- @Override public void clear() {
- synchronized (CopyOnWriteArrayList.this) {
- slice.checkConcurrentModification(elements);
- CopyOnWriteArrayList.this.removeRange(slice.from, slice.to);
- slice = new Slice(elements, slice.from, slice.from);
- }
- }
-
- @Override public void add(int index, E object) {
- synchronized (CopyOnWriteArrayList.this) {
- slice.checkPositionIndex(index);
- slice.checkConcurrentModification(elements);
- CopyOnWriteArrayList.this.add(index + slice.from, object);
- slice = new Slice(elements, slice.from, slice.to + 1);
- }
- }
-
- @Override public boolean add(E object) {
- synchronized (CopyOnWriteArrayList.this) {
- add(slice.to - slice.from, object);
- return true;
- }
- }
-
- @Override public boolean addAll(int index, Collection extends E> collection) {
- synchronized (CopyOnWriteArrayList.this) {
- slice.checkPositionIndex(index);
- slice.checkConcurrentModification(elements);
- int oldSize = elements.length;
- boolean result = CopyOnWriteArrayList.this.addAll(index + slice.from, collection);
- slice = new Slice(elements, slice.from, slice.to + (elements.length - oldSize));
- return result;
- }
- }
-
- @Override public boolean addAll(Collection extends E> collection) {
- synchronized (CopyOnWriteArrayList.this) {
- return addAll(size(), collection);
- }
- }
-
- @Override public E set(int index, E object) {
- synchronized (CopyOnWriteArrayList.this) {
- slice.checkElementIndex(index);
- slice.checkConcurrentModification(elements);
- E result = CopyOnWriteArrayList.this.set(index + slice.from, object);
- slice = new Slice(elements, slice.from, slice.to);
- return result;
- }
- }
-
- @Override public boolean remove(Object object) {
- synchronized (CopyOnWriteArrayList.this) {
- int index = indexOf(object);
- if (index == -1) {
- return false;
- }
- remove(index);
- return true;
- }
- }
-
- @Override public boolean removeAll(Collection> collection) {
- synchronized (CopyOnWriteArrayList.this) {
- slice.checkConcurrentModification(elements);
- int removed = removeOrRetain(collection, false, slice.from, slice.to);
- slice = new Slice(elements, slice.from, slice.to - removed);
- return removed != 0;
- }
- }
-
- @Override public boolean retainAll(Collection> collection) {
- synchronized (CopyOnWriteArrayList.this) {
- slice.checkConcurrentModification(elements);
- int removed = removeOrRetain(collection, true, slice.from, slice.to);
- slice = new Slice(elements, slice.from, slice.to - removed);
- return removed != 0;
- }
- }
-
- @Override
- public void forEach(Consumer super E> action) {
- CopyOnWriteArrayList.this.forInRange(slice.from, slice.to, action);
- }
-
- @Override
- public void replaceAll(UnaryOperator operator) {
- synchronized (CopyOnWriteArrayList.this) {
- slice.checkConcurrentModification(elements);
- CopyOnWriteArrayList.this.replaceInRange(slice.from, slice.to, operator);
- slice = new Slice(elements, slice.from, slice.to);
- }
- }
-
- @Override
- public synchronized void sort(Comparator super E> c) {
- synchronized (CopyOnWriteArrayList.this) {
- slice.checkConcurrentModification(elements);
- CopyOnWriteArrayList.this.sortInRange(slice.from, slice.to, c);
- slice = new Slice(elements, slice.from, slice.to);
- }
- }
- }
-
- static class Slice {
- private final Object[] expectedElements;
- private final int from;
- private final int to;
-
- Slice(Object[] expectedElements, int from, int to) {
- this.expectedElements = expectedElements;
- this.from = from;
- this.to = to;
- }
-
- /**
- * Throws if {@code index} doesn't identify an element in the array.
- */
- void checkElementIndex(int index) {
- if (index < 0 || index >= to - from) {
- throw new IndexOutOfBoundsException("index=" + index + ", size=" + (to - from));
- }
- }
-
- /**
- * Throws if {@code index} doesn't identify an insertion point in the
- * array. Unlike element index, it's okay to add or iterate at size().
- */
- void checkPositionIndex(int index) {
- if (index < 0 || index > to - from) {
- throw new IndexOutOfBoundsException("index=" + index + ", size=" + (to - from));
- }
- }
-
- void checkConcurrentModification(Object[] snapshot) {
- if (expectedElements != snapshot) {
- throw new ConcurrentModificationException();
- }
- }
- }
-
- /**
- * Iterates an immutable snapshot of the list.
- */
- static class CowIterator implements ListIterator {
- private final Object[] snapshot;
- private final int from;
- private final int to;
- private int index = 0;
-
- CowIterator(Object[] snapshot, int from, int to) {
- this.snapshot = snapshot;
- this.from = from;
- this.to = to;
- this.index = from;
- }
-
- public void add(E object) {
- throw new UnsupportedOperationException();
- }
-
- public boolean hasNext() {
- return index < to;
- }
-
- public boolean hasPrevious() {
- return index > from;
- }
-
- @SuppressWarnings("unchecked")
- public E next() {
- if (index < to) {
- return (E) snapshot[index++];
- } else {
- throw new NoSuchElementException();
- }
- }
-
- public int nextIndex() {
- return index;
- }
-
- @SuppressWarnings("unchecked")
- public E previous() {
- if (index > from) {
- return (E) snapshot[--index];
- } else {
- throw new NoSuchElementException();
- }
- }
-
- public int previousIndex() {
- return index - 1;
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- public void set(E object) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void forEachRemaining(Consumer super E> action) {
- java.util.Objects.requireNonNull(action);
- Object[] elements = snapshot;
- for (int i = index; i < to; i++) {
- @SuppressWarnings("unchecked") E e = (E) elements[i];
- action.accept(e);
- }
- index = to;
- }
- }
-
- private void writeObject(ObjectOutputStream out) throws IOException {
- Object[] snapshot = elements;
- out.defaultWriteObject();
- out.writeInt(snapshot.length);
- for (Object o : snapshot) {
- out.writeObject(o);
- }
- }
-
- private synchronized void readObject(ObjectInputStream in)
- throws IOException, ClassNotFoundException {
- in.defaultReadObject();
- Object[] snapshot = new Object[in.readInt()];
- for (int i = 0; i < snapshot.length; i++) {
- snapshot[i] = in.readObject();
- }
- elements = snapshot;
- }
-}
diff --git a/luni/src/main/java/java/util/concurrent/Delayed.java b/luni/src/main/java/java/util/concurrent/Delayed.java
deleted file mode 100644
index 6a9527d73..000000000
--- a/luni/src/main/java/java/util/concurrent/Delayed.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent;
-
-/**
- * A mix-in style interface for marking objects that should be
- * acted upon after a given delay.
- *
- * An implementation of this interface must define a
- * {@code compareTo} method that provides an ordering consistent with
- * its {@code getDelay} method.
- *
- * @since 1.5
- * @author Doug Lea
- */
-public interface Delayed extends Comparable {
-
- /**
- * Returns the remaining delay associated with this object, in the
- * given time unit.
- *
- * @param unit the time unit
- * @return the remaining delay; zero or negative values indicate
- * that the delay has already elapsed
- */
- long getDelay(TimeUnit unit);
-}
diff --git a/luni/src/main/java/java/util/concurrent/ExecutionException.java b/luni/src/main/java/java/util/concurrent/ExecutionException.java
deleted file mode 100644
index dbfbe6506..000000000
--- a/luni/src/main/java/java/util/concurrent/ExecutionException.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent;
-
-/**
- * Exception thrown when attempting to retrieve the result of a task
- * that aborted by throwing an exception. This exception can be
- * inspected using the {@link #getCause()} method.
- *
- * @see Future
- * @since 1.5
- * @author Doug Lea
- */
-public class ExecutionException extends Exception {
- private static final long serialVersionUID = 7830266012832686185L;
-
- /**
- * Constructs an {@code ExecutionException} with no detail message.
- * The cause is not initialized, and may subsequently be
- * initialized by a call to {@link #initCause(Throwable) initCause}.
- */
- protected ExecutionException() { }
-
- /**
- * Constructs an {@code ExecutionException} with the specified detail
- * message. The cause is not initialized, and may subsequently be
- * initialized by a call to {@link #initCause(Throwable) initCause}.
- *
- * @param message the detail message
- */
- protected ExecutionException(String message) {
- super(message);
- }
-
- /**
- * Constructs an {@code ExecutionException} with the specified detail
- * message and cause.
- *
- * @param message the detail message
- * @param cause the cause (which is saved for later retrieval by the
- * {@link #getCause()} method)
- */
- public ExecutionException(String message, Throwable cause) {
- super(message, cause);
- }
-
- /**
- * Constructs an {@code ExecutionException} with the specified cause.
- * The detail message is set to {@code (cause == null ? null :
- * cause.toString())} (which typically contains the class and
- * detail message of {@code cause}).
- *
- * @param cause the cause (which is saved for later retrieval by the
- * {@link #getCause()} method)
- */
- public ExecutionException(Throwable cause) {
- super(cause);
- }
-}
diff --git a/luni/src/main/java/java/util/concurrent/Executor.java b/luni/src/main/java/java/util/concurrent/Executor.java
deleted file mode 100644
index 9dd3efb62..000000000
--- a/luni/src/main/java/java/util/concurrent/Executor.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent;
-
-/**
- * An object that executes submitted {@link Runnable} tasks. This
- * interface provides a way of decoupling task submission from the
- * mechanics of how each task will be run, including details of thread
- * use, scheduling, etc. An {@code Executor} is normally used
- * instead of explicitly creating threads. For example, rather than
- * invoking {@code new Thread(new RunnableTask()).start()} for each
- * of a set of tasks, you might use:
- *
- * {@code
- * Executor executor = anExecutor();
- * executor.execute(new RunnableTask1());
- * executor.execute(new RunnableTask2());
- * ...}
- *
- * However, the {@code Executor} interface does not strictly require
- * that execution be asynchronous. In the simplest case, an executor
- * can run the submitted task immediately in the caller's thread:
- *
- * {@code
- * class DirectExecutor implements Executor {
- * public void execute(Runnable r) {
- * r.run();
- * }
- * }}
- *
- * More typically, tasks are executed in some thread other than the
- * caller's thread. The executor below spawns a new thread for each
- * task.
- *
- * {@code
- * class ThreadPerTaskExecutor implements Executor {
- * public void execute(Runnable r) {
- * new Thread(r).start();
- * }
- * }}
- *
- * Many {@code Executor} implementations impose some sort of
- * limitation on how and when tasks are scheduled. The executor below
- * serializes the submission of tasks to a second executor,
- * illustrating a composite executor.
- *
- * {@code
- * class SerialExecutor implements Executor {
- * final Queue tasks = new ArrayDeque<>();
- * final Executor executor;
- * Runnable active;
- *
- * SerialExecutor(Executor executor) {
- * this.executor = executor;
- * }
- *
- * public synchronized void execute(final Runnable r) {
- * tasks.add(new Runnable() {
- * public void run() {
- * try {
- * r.run();
- * } finally {
- * scheduleNext();
- * }
- * }
- * });
- * if (active == null) {
- * scheduleNext();
- * }
- * }
- *
- * protected synchronized void scheduleNext() {
- * if ((active = tasks.poll()) != null) {
- * executor.execute(active);
- * }
- * }
- * }}
- *
- * The {@code Executor} implementations provided in this package
- * implement {@link ExecutorService}, which is a more extensive
- * interface. The {@link ThreadPoolExecutor} class provides an
- * extensible thread pool implementation. The {@link Executors} class
- * provides convenient factory methods for these Executors.
- *
- * Memory consistency effects: Actions in a thread prior to
- * submitting a {@code Runnable} object to an {@code Executor}
- * happen-before
- * its execution begins, perhaps in another thread.
- *
- * @since 1.5
- * @author Doug Lea
- */
-public interface Executor {
-
- /**
- * Executes the given command at some time in the future. The command
- * may execute in a new thread, in a pooled thread, or in the calling
- * thread, at the discretion of the {@code Executor} implementation.
- *
- * @param command the runnable task
- * @throws RejectedExecutionException if this task cannot be
- * accepted for execution
- * @throws NullPointerException if command is null
- */
- void execute(Runnable command);
-}
diff --git a/luni/src/main/java/java/util/concurrent/Helpers.java b/luni/src/main/java/java/util/concurrent/Helpers.java
deleted file mode 100644
index 9051e2f66..000000000
--- a/luni/src/main/java/java/util/concurrent/Helpers.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Written by Martin Buchholz with assistance from members of JCP
- * JSR-166 Expert Group and released to the public domain, as
- * explained at http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent;
-
-import java.util.Collection;
-
-/** Shared implementation code for java.util.concurrent. */
-class Helpers {
- private Helpers() {} // non-instantiable
-
- /**
- * An implementation of Collection.toString() suitable for classes
- * with locks. Instead of holding a lock for the entire duration of
- * toString(), or acquiring a lock for each call to Iterator.next(),
- * we hold the lock only during the call to toArray() (less
- * disruptive to other threads accessing the collection) and follows
- * the maxim "Never call foreign code while holding a lock".
- */
- static String collectionToString(Collection> c) {
- final Object[] a = c.toArray();
- final int size = a.length;
- if (size == 0)
- return "[]";
- int charLength = 0;
-
- // Replace every array element with its string representation
- for (int i = 0; i < size; i++) {
- Object e = a[i];
- // Extreme compatibility with AbstractCollection.toString()
- String s = (e == c) ? "(this Collection)" : objectToString(e);
- a[i] = s;
- charLength += s.length();
- }
-
- return toString(a, size, charLength);
- }
-
- /**
- * Like Arrays.toString(), but caller guarantees that size > 0,
- * each element with index 0 <= i < size is a non-null String,
- * and charLength is the sum of the lengths of the input Strings.
- */
- static String toString(Object[] a, int size, int charLength) {
- // assert a != null;
- // assert size > 0;
-
- // Copy each string into a perfectly sized char[]
- // Length of [ , , , ] == 2 * size
- final char[] chars = new char[charLength + 2 * size];
- chars[0] = '[';
- int j = 1;
- for (int i = 0; i < size; i++) {
- if (i > 0) {
- chars[j++] = ',';
- chars[j++] = ' ';
- }
- String s = (String) a[i];
- int len = s.length();
- s.getChars(0, len, chars, j);
- j += len;
- }
- chars[j] = ']';
- // assert j == chars.length - 1;
- return new String(chars);
- }
-
- /** Optimized form of: key + "=" + val */
- static String mapEntryToString(Object key, Object val) {
- final String k, v;
- final int klen, vlen;
- final char[] chars =
- new char[(klen = (k = objectToString(key)).length()) +
- (vlen = (v = objectToString(val)).length()) + 1];
- k.getChars(0, klen, chars, 0);
- chars[klen] = '=';
- v.getChars(0, vlen, chars, klen + 1);
- return new String(chars);
- }
-
- private static String objectToString(Object x) {
- // Extreme compatibility with StringBuilder.append(null)
- String s;
- return (x == null || (s = x.toString()) == null) ? "null" : s;
- }
-}
diff --git a/luni/src/main/java/java/util/concurrent/RecursiveTask.java b/luni/src/main/java/java/util/concurrent/RecursiveTask.java
deleted file mode 100644
index 5cba1dac3..000000000
--- a/luni/src/main/java/java/util/concurrent/RecursiveTask.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent;
-
-/**
- * A recursive result-bearing {@link ForkJoinTask}.
- *
- *
For a classic example, here is a task computing Fibonacci numbers:
- *
- *
{@code
- * class Fibonacci extends RecursiveTask {
- * final int n;
- * Fibonacci(int n) { this.n = n; }
- * protected Integer compute() {
- * if (n <= 1)
- * return n;
- * Fibonacci f1 = new Fibonacci(n - 1);
- * f1.fork();
- * Fibonacci f2 = new Fibonacci(n - 2);
- * return f2.compute() + f1.join();
- * }
- * }}
- *
- * However, besides being a dumb way to compute Fibonacci functions
- * (there is a simple fast linear algorithm that you'd use in
- * practice), this is likely to perform poorly because the smallest
- * subtasks are too small to be worthwhile splitting up. Instead, as
- * is the case for nearly all fork/join applications, you'd pick some
- * minimum granularity size (for example 10 here) for which you always
- * sequentially solve rather than subdividing.
- *
- * @since 1.7
- * @author Doug Lea
- */
-public abstract class RecursiveTask extends ForkJoinTask {
- private static final long serialVersionUID = 5232453952276485270L;
-
- /**
- * The result of the computation.
- */
- V result;
-
- /**
- * The main computation performed by this task.
- * @return the result of the computation
- */
- protected abstract V compute();
-
- public final V getRawResult() {
- return result;
- }
-
- protected final void setRawResult(V value) {
- result = value;
- }
-
- /**
- * Implements execution conventions for RecursiveTask.
- */
- protected final boolean exec() {
- result = compute();
- return true;
- }
-
-}
diff --git a/luni/src/main/java/java/util/concurrent/RejectedExecutionException.java b/luni/src/main/java/java/util/concurrent/RejectedExecutionException.java
deleted file mode 100644
index c61365fae..000000000
--- a/luni/src/main/java/java/util/concurrent/RejectedExecutionException.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent;
-
-/**
- * Exception thrown by an {@link Executor} when a task cannot be
- * accepted for execution.
- *
- * @since 1.5
- * @author Doug Lea
- */
-public class RejectedExecutionException extends RuntimeException {
- private static final long serialVersionUID = -375805702767069545L;
-
- /**
- * Constructs a {@code RejectedExecutionException} with no detail message.
- * The cause is not initialized, and may subsequently be
- * initialized by a call to {@link #initCause(Throwable) initCause}.
- */
- public RejectedExecutionException() { }
-
- /**
- * Constructs a {@code RejectedExecutionException} with the
- * specified detail message. The cause is not initialized, and may
- * subsequently be initialized by a call to {@link
- * #initCause(Throwable) initCause}.
- *
- * @param message the detail message
- */
- public RejectedExecutionException(String message) {
- super(message);
- }
-
- /**
- * Constructs a {@code RejectedExecutionException} with the
- * specified detail message and cause.
- *
- * @param message the detail message
- * @param cause the cause (which is saved for later retrieval by the
- * {@link #getCause()} method)
- */
- public RejectedExecutionException(String message, Throwable cause) {
- super(message, cause);
- }
-
- /**
- * Constructs a {@code RejectedExecutionException} with the
- * specified cause. The detail message is set to {@code (cause ==
- * null ? null : cause.toString())} (which typically contains
- * the class and detail message of {@code cause}).
- *
- * @param cause the cause (which is saved for later retrieval by the
- * {@link #getCause()} method)
- */
- public RejectedExecutionException(Throwable cause) {
- super(cause);
- }
-}
diff --git a/luni/src/main/java/java/util/concurrent/RejectedExecutionHandler.java b/luni/src/main/java/java/util/concurrent/RejectedExecutionHandler.java
deleted file mode 100644
index 8c000ea8d..000000000
--- a/luni/src/main/java/java/util/concurrent/RejectedExecutionHandler.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent;
-
-/**
- * A handler for tasks that cannot be executed by a {@link ThreadPoolExecutor}.
- *
- * @since 1.5
- * @author Doug Lea
- */
-public interface RejectedExecutionHandler {
-
- /**
- * Method that may be invoked by a {@link ThreadPoolExecutor} when
- * {@link ThreadPoolExecutor#execute execute} cannot accept a
- * task. This may occur when no more threads or queue slots are
- * available because their bounds would be exceeded, or upon
- * shutdown of the Executor.
- *
- * In the absence of other alternatives, the method may throw
- * an unchecked {@link RejectedExecutionException}, which will be
- * propagated to the caller of {@code execute}.
- *
- * @param r the runnable task requested to be executed
- * @param executor the executor attempting to execute this task
- * @throws RejectedExecutionException if there is no remedy
- */
- void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
-}
diff --git a/luni/src/main/java/java/util/concurrent/RunnableFuture.java b/luni/src/main/java/java/util/concurrent/RunnableFuture.java
deleted file mode 100644
index ccd28e35a..000000000
--- a/luni/src/main/java/java/util/concurrent/RunnableFuture.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent;
-
-/**
- * A {@link Future} that is {@link Runnable}. Successful execution of
- * the {@code run} method causes completion of the {@code Future}
- * and allows access to its results.
- * @see FutureTask
- * @see Executor
- * @since 1.6
- * @author Doug Lea
- * @param The result type returned by this Future's {@code get} method
- */
-public interface RunnableFuture extends Runnable, Future {
- /**
- * Sets this Future to the result of its computation
- * unless it has been cancelled.
- */
- void run();
-}
diff --git a/luni/src/main/java/java/util/concurrent/RunnableScheduledFuture.java b/luni/src/main/java/java/util/concurrent/RunnableScheduledFuture.java
deleted file mode 100644
index 604f180bc..000000000
--- a/luni/src/main/java/java/util/concurrent/RunnableScheduledFuture.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent;
-
-/**
- * A {@link ScheduledFuture} that is {@link Runnable}. Successful
- * execution of the {@code run} method causes completion of the
- * {@code Future} and allows access to its results.
- * @see FutureTask
- * @see Executor
- * @since 1.6
- * @author Doug Lea
- * @param The result type returned by this Future's {@code get} method
- */
-public interface RunnableScheduledFuture extends RunnableFuture, ScheduledFuture {
-
- /**
- * Returns {@code true} if this task is periodic. A periodic task may
- * re-run according to some schedule. A non-periodic task can be
- * run only once.
- *
- * @return {@code true} if this task is periodic
- */
- boolean isPeriodic();
-}
diff --git a/luni/src/main/java/java/util/concurrent/ScheduledFuture.java b/luni/src/main/java/java/util/concurrent/ScheduledFuture.java
deleted file mode 100644
index 3745cb0f6..000000000
--- a/luni/src/main/java/java/util/concurrent/ScheduledFuture.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent;
-
-/**
- * A delayed result-bearing action that can be cancelled.
- * Usually a scheduled future is the result of scheduling
- * a task with a {@link ScheduledExecutorService}.
- *
- * @since 1.5
- * @author Doug Lea
- * @param The result type returned by this Future
- */
-public interface ScheduledFuture extends Delayed, Future {
-}
diff --git a/luni/src/main/java/java/util/concurrent/ThreadFactory.java b/luni/src/main/java/java/util/concurrent/ThreadFactory.java
deleted file mode 100644
index fdedea34b..000000000
--- a/luni/src/main/java/java/util/concurrent/ThreadFactory.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent;
-
-/**
- * An object that creates new threads on demand. Using thread factories
- * removes hardwiring of calls to {@link Thread#Thread(Runnable) new Thread},
- * enabling applications to use special thread subclasses, priorities, etc.
- *
- *
- * The simplest implementation of this interface is just:
- *
{@code
- * class SimpleThreadFactory implements ThreadFactory {
- * public Thread newThread(Runnable r) {
- * return new Thread(r);
- * }
- * }}
- *
- * The {@link Executors#defaultThreadFactory} method provides a more
- * useful simple implementation, that sets the created thread context
- * to known values before returning it.
- * @since 1.5
- * @author Doug Lea
- */
-public interface ThreadFactory {
-
- /**
- * Constructs a new {@code Thread}. Implementations may also initialize
- * priority, name, daemon status, {@code ThreadGroup}, etc.
- *
- * @param r a runnable to be executed by new thread instance
- * @return constructed thread, or {@code null} if the request to
- * create a thread is rejected
- */
- Thread newThread(Runnable r);
-}
diff --git a/luni/src/main/java/java/util/concurrent/TimeoutException.java b/luni/src/main/java/java/util/concurrent/TimeoutException.java
deleted file mode 100644
index 1d7e634a3..000000000
--- a/luni/src/main/java/java/util/concurrent/TimeoutException.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent;
-
-/**
- * Exception thrown when a blocking operation times out. Blocking
- * operations for which a timeout is specified need a means to
- * indicate that the timeout has occurred. For many such operations it
- * is possible to return a value that indicates timeout; when that is
- * not possible or desirable then {@code TimeoutException} should be
- * declared and thrown.
- *
- * @since 1.5
- * @author Doug Lea
- */
-public class TimeoutException extends Exception {
- private static final long serialVersionUID = 1900926677490660714L;
-
- /**
- * Constructs a {@code TimeoutException} with no specified detail
- * message.
- */
- public TimeoutException() {}
-
- /**
- * Constructs a {@code TimeoutException} with the specified detail
- * message.
- *
- * @param message the detail message
- */
- public TimeoutException(String message) {
- super(message);
- }
-}
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java
deleted file mode 100644
index 01e4b072d..000000000
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent.atomic;
-
-/**
- * A {@code boolean} value that may be updated atomically. See the
- * {@link java.util.concurrent.atomic} package specification for
- * description of the properties of atomic variables. An
- * {@code AtomicBoolean} is used in applications such as atomically
- * updated flags, and cannot be used as a replacement for a
- * {@link java.lang.Boolean}.
- *
- * @since 1.5
- * @author Doug Lea
- */
-public class AtomicBoolean implements java.io.Serializable {
- private static final long serialVersionUID = 4654671469794556979L;
-
- private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
- private static final long VALUE;
-
- static {
- try {
- VALUE = U.objectFieldOffset
- (AtomicBoolean.class.getDeclaredField("value"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
-
- private volatile int value;
-
- /**
- * Creates a new {@code AtomicBoolean} with the given initial value.
- *
- * @param initialValue the initial value
- */
- public AtomicBoolean(boolean initialValue) {
- value = initialValue ? 1 : 0;
- }
-
- /**
- * Creates a new {@code AtomicBoolean} with initial value {@code false}.
- */
- public AtomicBoolean() {
- }
-
- /**
- * Returns the current value.
- *
- * @return the current value
- */
- public final boolean get() {
- return value != 0;
- }
-
- /**
- * Atomically sets the value to the given updated value
- * if the current value {@code ==} the expected value.
- *
- * @param expect the expected value
- * @param update the new value
- * @return {@code true} if successful. False return indicates that
- * the actual value was not equal to the expected value.
- */
- public final boolean compareAndSet(boolean expect, boolean update) {
- return U.compareAndSwapInt(this, VALUE,
- (expect ? 1 : 0),
- (update ? 1 : 0));
- }
-
- /**
- * Atomically sets the value to the given updated value
- * if the current value {@code ==} the expected value.
- *
- * May fail
- * spuriously and does not provide ordering guarantees , so is
- * only rarely an appropriate alternative to {@code compareAndSet}.
- *
- * @param expect the expected value
- * @param update the new value
- * @return {@code true} if successful
- */
- public boolean weakCompareAndSet(boolean expect, boolean update) {
- return U.compareAndSwapInt(this, VALUE,
- (expect ? 1 : 0),
- (update ? 1 : 0));
- }
-
- /**
- * Unconditionally sets to the given value.
- *
- * @param newValue the new value
- */
- public final void set(boolean newValue) {
- value = newValue ? 1 : 0;
- }
-
- /**
- * Eventually sets to the given value.
- *
- * @param newValue the new value
- * @since 1.6
- */
- public final void lazySet(boolean newValue) {
- U.putOrderedInt(this, VALUE, (newValue ? 1 : 0));
- }
-
- /**
- * Atomically sets to the given value and returns the previous value.
- *
- * @param newValue the new value
- * @return the previous value
- */
- public final boolean getAndSet(boolean newValue) {
- boolean prev;
- do {
- prev = get();
- } while (!compareAndSet(prev, newValue));
- return prev;
- }
-
- /**
- * Returns the String representation of the current value.
- * @return the String representation of the current value
- */
- public String toString() {
- return Boolean.toString(get());
- }
-
-}
diff --git a/luni/src/main/java/java/util/concurrent/atomic/package-info.java b/luni/src/main/java/java/util/concurrent/atomic/package-info.java
deleted file mode 100644
index b19dd49a0..000000000
--- a/luni/src/main/java/java/util/concurrent/atomic/package-info.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-/**
- * A small toolkit of classes that support lock-free thread-safe
- * programming on single variables. In essence, the classes in this
- * package extend the notion of {@code volatile} values, fields, and
- * array elements to those that also provide an atomic conditional update
- * operation of the form:
- *
- *
{@code boolean compareAndSet(expectedValue, updateValue);}
- *
- * This method (which varies in argument types across different
- * classes) atomically sets a variable to the {@code updateValue} if it
- * currently holds the {@code expectedValue}, reporting {@code true} on
- * success. The classes in this package also contain methods to get and
- * unconditionally set values, as well as a weaker conditional atomic
- * update operation {@code weakCompareAndSet} described below.
- *
- *
The specifications of these methods enable implementations to
- * employ efficient machine-level atomic instructions that are available
- * on contemporary processors. However on some platforms, support may
- * entail some form of internal locking. Thus the methods are not
- * strictly guaranteed to be non-blocking --
- * a thread may block transiently before performing the operation.
- *
- *
Instances of classes
- * {@link java.util.concurrent.atomic.AtomicBoolean},
- * {@link java.util.concurrent.atomic.AtomicInteger},
- * {@link java.util.concurrent.atomic.AtomicLong}, and
- * {@link java.util.concurrent.atomic.AtomicReference}
- * each provide access and updates to a single variable of the
- * corresponding type. Each class also provides appropriate utility
- * methods for that type. For example, classes {@code AtomicLong} and
- * {@code AtomicInteger} provide atomic increment methods. One
- * application is to generate sequence numbers, as in:
- *
- *
{@code
- * class Sequencer {
- * private final AtomicLong sequenceNumber
- * = new AtomicLong(0);
- * public long next() {
- * return sequenceNumber.getAndIncrement();
- * }
- * }}
- *
- * It is straightforward to define new utility functions that, like
- * {@code getAndIncrement}, apply a function to a value atomically.
- * For example, given some transformation
- *
{@code long transform(long input)}
- *
- * write your utility method as follows:
- * {@code
- * long getAndTransform(AtomicLong var) {
- * long prev, next;
- * do {
- * prev = var.get();
- * next = transform(prev);
- * } while (!var.compareAndSet(prev, next));
- * return prev; // return next; for transformAndGet
- * }}
- *
- * The memory effects for accesses and updates of atomics generally
- * follow the rules for volatiles, as stated in
- *
- * Chapter 17 of
- * The Java™ Language Specification :
- *
- *
- *
- * {@code get} has the memory effects of reading a
- * {@code volatile} variable.
- *
- * {@code set} has the memory effects of writing (assigning) a
- * {@code volatile} variable.
- *
- * {@code lazySet} has the memory effects of writing (assigning)
- * a {@code volatile} variable except that it permits reorderings with
- * subsequent (but not previous) memory actions that do not themselves
- * impose reordering constraints with ordinary non-{@code volatile}
- * writes. Among other usage contexts, {@code lazySet} may apply when
- * nulling out, for the sake of garbage collection, a reference that is
- * never accessed again.
- *
- * {@code weakCompareAndSet} atomically reads and conditionally
- * writes a variable but does not
- * create any happens-before orderings, so provides no guarantees
- * with respect to previous or subsequent reads and writes of any
- * variables other than the target of the {@code weakCompareAndSet}.
- *
- * {@code compareAndSet}
- * and all other read-and-update operations such as {@code getAndIncrement}
- * have the memory effects of both reading and
- * writing {@code volatile} variables.
- *
- *
- * In addition to classes representing single values, this package
- * contains Updater classes that can be used to obtain
- * {@code compareAndSet} operations on any selected {@code volatile}
- * field of any selected class.
- *
- * {@link java.util.concurrent.atomic.AtomicReferenceFieldUpdater},
- * {@link java.util.concurrent.atomic.AtomicIntegerFieldUpdater}, and
- * {@link java.util.concurrent.atomic.AtomicLongFieldUpdater} are
- * reflection-based utilities that provide access to the associated
- * field types. These are mainly of use in atomic data structures in
- * which several {@code volatile} fields of the same node (for
- * example, the links of a tree node) are independently subject to
- * atomic updates. These classes enable greater flexibility in how
- * and when to use atomic updates, at the expense of more awkward
- * reflection-based setup, less convenient usage, and weaker
- * guarantees.
- *
- *
The
- * {@link java.util.concurrent.atomic.AtomicIntegerArray},
- * {@link java.util.concurrent.atomic.AtomicLongArray}, and
- * {@link java.util.concurrent.atomic.AtomicReferenceArray} classes
- * further extend atomic operation support to arrays of these types.
- * These classes are also notable in providing {@code volatile} access
- * semantics for their array elements, which is not supported for
- * ordinary arrays.
- *
- *
The atomic classes also support method
- * {@code weakCompareAndSet}, which has limited applicability. On some
- * platforms, the weak version may be more efficient than {@code
- * compareAndSet} in the normal case, but differs in that any given
- * invocation of the {@code weakCompareAndSet} method may return {@code
- * false} spuriously (that is, for no apparent reason). A
- * {@code false} return means only that the operation may be retried if
- * desired, relying on the guarantee that repeated invocation when the
- * variable holds {@code expectedValue} and no other thread is also
- * attempting to set the variable will eventually succeed. (Such
- * spurious failures may for example be due to memory contention effects
- * that are unrelated to whether the expected and current values are
- * equal.) Additionally {@code weakCompareAndSet} does not provide
- * ordering guarantees that are usually needed for synchronization
- * control. However, the method may be useful for updating counters and
- * statistics when such updates are unrelated to the other
- * happens-before orderings of a program. When a thread sees an update
- * to an atomic variable caused by a {@code weakCompareAndSet}, it does
- * not necessarily see updates to any other variables that
- * occurred before the {@code weakCompareAndSet}. This may be
- * acceptable when, for example, updating performance statistics, but
- * rarely otherwise.
- *
- *
The {@link java.util.concurrent.atomic.AtomicMarkableReference}
- * class associates a single boolean with a reference. For example, this
- * bit might be used inside a data structure to mean that the object
- * being referenced has logically been deleted.
- *
- * The {@link java.util.concurrent.atomic.AtomicStampedReference}
- * class associates an integer value with a reference. This may be
- * used for example, to represent version numbers corresponding to
- * series of updates.
- *
- *
Atomic classes are designed primarily as building blocks for
- * implementing non-blocking data structures and related infrastructure
- * classes. The {@code compareAndSet} method is not a general
- * replacement for locking. It applies only when critical updates for an
- * object are confined to a single variable.
- *
- *
Atomic classes are not general purpose replacements for
- * {@code java.lang.Integer} and related classes. They do not
- * define methods such as {@code equals}, {@code hashCode} and
- * {@code compareTo}. (Because atomic variables are expected to be
- * mutated, they are poor choices for hash table keys.) Additionally,
- * classes are provided only for those types that are commonly useful in
- * intended applications. For example, there is no atomic class for
- * representing {@code byte}. In those infrequent cases where you would
- * like to do so, you can use an {@code AtomicInteger} to hold
- * {@code byte} values, and cast appropriately.
- *
- * You can also hold floats using
- * {@link java.lang.Float#floatToRawIntBits} and
- * {@link java.lang.Float#intBitsToFloat} conversions, and doubles using
- * {@link java.lang.Double#doubleToRawLongBits} and
- * {@link java.lang.Double#longBitsToDouble} conversions.
- *
- * @since 1.5
- */
-package java.util.concurrent.atomic;
diff --git a/luni/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java b/luni/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java
deleted file mode 100644
index 66a2f8e57..000000000
--- a/luni/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-package java.util.concurrent.locks;
-
-/**
- * A synchronizer that may be exclusively owned by a thread. This
- * class provides a basis for creating locks and related synchronizers
- * that may entail a notion of ownership. The
- * {@code AbstractOwnableSynchronizer} class itself does not manage or
- * use this information. However, subclasses and tools may use
- * appropriately maintained values to help control and monitor access
- * and provide diagnostics.
- *
- * @since 1.6
- * @author Doug Lea
- */
-public abstract class AbstractOwnableSynchronizer
- implements java.io.Serializable {
-
- /** Use serial ID even though all fields transient. */
- private static final long serialVersionUID = 3737899427754241961L;
-
- /**
- * Empty constructor for use by subclasses.
- */
- protected AbstractOwnableSynchronizer() { }
-
- /**
- * The current owner of exclusive mode synchronization.
- */
- private transient Thread exclusiveOwnerThread;
-
- /**
- * Sets the thread that currently owns exclusive access.
- * A {@code null} argument indicates that no thread owns access.
- * This method does not otherwise impose any synchronization or
- * {@code volatile} field accesses.
- * @param thread the owner thread
- */
- protected final void setExclusiveOwnerThread(Thread thread) {
- exclusiveOwnerThread = thread;
- }
-
- /**
- * Returns the thread last set by {@code setExclusiveOwnerThread},
- * or {@code null} if never set. This method does not otherwise
- * impose any synchronization or {@code volatile} field accesses.
- * @return the owner thread
- */
- protected final Thread getExclusiveOwnerThread() {
- return exclusiveOwnerThread;
- }
-}
diff --git a/luni/src/main/java/java/util/concurrent/locks/package-info.java b/luni/src/main/java/java/util/concurrent/locks/package-info.java
deleted file mode 100644
index 433f86908..000000000
--- a/luni/src/main/java/java/util/concurrent/locks/package-info.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-/**
- * Interfaces and classes providing a framework for locking and waiting
- * for conditions that is distinct from built-in synchronization and
- * monitors. The framework permits much greater flexibility in the use of
- * locks and conditions, at the expense of more awkward syntax.
- *
- *
The {@link java.util.concurrent.locks.Lock} interface supports
- * locking disciplines that differ in semantics (reentrant, fair, etc),
- * and that can be used in non-block-structured contexts including
- * hand-over-hand and lock reordering algorithms. The main implementation
- * is {@link java.util.concurrent.locks.ReentrantLock}.
- *
- *
The {@link java.util.concurrent.locks.ReadWriteLock} interface
- * similarly defines locks that may be shared among readers but are
- * exclusive to writers. Only a single implementation, {@link
- * java.util.concurrent.locks.ReentrantReadWriteLock}, is provided, since
- * it covers most standard usage contexts. But programmers may create
- * their own implementations to cover nonstandard requirements.
- *
- *
The {@link java.util.concurrent.locks.Condition} interface
- * describes condition variables that may be associated with Locks.
- * These are similar in usage to the implicit monitors accessed using
- * {@code Object.wait}, but offer extended capabilities.
- * In particular, multiple {@code Condition} objects may be associated
- * with a single {@code Lock}. To avoid compatibility issues, the
- * names of {@code Condition} methods are different from the
- * corresponding {@code Object} versions.
- *
- *
The {@link java.util.concurrent.locks.AbstractQueuedSynchronizer}
- * class serves as a useful superclass for defining locks and other
- * synchronizers that rely on queuing blocked threads. The {@link
- * java.util.concurrent.locks.AbstractQueuedLongSynchronizer} class
- * provides the same functionality but extends support to 64 bits of
- * synchronization state. Both extend class {@link
- * java.util.concurrent.locks.AbstractOwnableSynchronizer}, a simple
- * class that helps record the thread currently holding exclusive
- * synchronization. The {@link java.util.concurrent.locks.LockSupport}
- * class provides lower-level blocking and unblocking support that is
- * useful for those developers implementing their own customized lock
- * classes.
- *
- * @since 1.5
- */
-package java.util.concurrent.locks;
diff --git a/luni/src/main/java/java/util/concurrent/package-info.java b/luni/src/main/java/java/util/concurrent/package-info.java
deleted file mode 100644
index 5dc12284b..000000000
--- a/luni/src/main/java/java/util/concurrent/package-info.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-/**
- * Utility classes commonly useful in concurrent programming. This
- * package includes a few small standardized extensible frameworks, as
- * well as some classes that provide useful functionality and are
- * otherwise tedious or difficult to implement. Here are brief
- * descriptions of the main components. See also the
- * {@link java.util.concurrent.locks} and
- * {@link java.util.concurrent.atomic} packages.
- *
- *
Executors
- *
- * Interfaces.
- *
- * {@link java.util.concurrent.Executor} is a simple standardized
- * interface for defining custom thread-like subsystems, including
- * thread pools, asynchronous I/O, and lightweight task frameworks.
- * Depending on which concrete Executor class is being used, tasks may
- * execute in a newly created thread, an existing task-execution thread,
- * or the thread calling {@link java.util.concurrent.Executor#execute
- * execute}, and may execute sequentially or concurrently.
- *
- * {@link java.util.concurrent.ExecutorService} provides a more
- * complete asynchronous task execution framework. An
- * ExecutorService manages queuing and scheduling of tasks,
- * and allows controlled shutdown.
- *
- * The {@link java.util.concurrent.ScheduledExecutorService}
- * subinterface and associated interfaces add support for
- * delayed and periodic task execution. ExecutorServices
- * provide methods arranging asynchronous execution of any
- * function expressed as {@link java.util.concurrent.Callable},
- * the result-bearing analog of {@link java.lang.Runnable}.
- *
- * A {@link java.util.concurrent.Future} returns the results of
- * a function, allows determination of whether execution has
- * completed, and provides a means to cancel execution.
- *
- * A {@link java.util.concurrent.RunnableFuture} is a {@code Future}
- * that possesses a {@code run} method that upon execution,
- * sets its results.
- *
- *
- *
- * Implementations.
- *
- * Classes {@link java.util.concurrent.ThreadPoolExecutor} and
- * {@link java.util.concurrent.ScheduledThreadPoolExecutor}
- * provide tunable, flexible thread pools.
- *
- * The {@link java.util.concurrent.Executors} class provides
- * factory methods for the most common kinds and configurations
- * of Executors, as well as a few utility methods for using
- * them. Other utilities based on {@code Executors} include the
- * concrete class {@link java.util.concurrent.FutureTask}
- * providing a common extensible implementation of Futures, and
- * {@link java.util.concurrent.ExecutorCompletionService}, that
- * assists in coordinating the processing of groups of
- * asynchronous tasks.
- *
- *
Class {@link java.util.concurrent.ForkJoinPool} provides an
- * Executor primarily designed for processing instances of {@link
- * java.util.concurrent.ForkJoinTask} and its subclasses. These
- * classes employ a work-stealing scheduler that attains high
- * throughput for tasks conforming to restrictions that often hold in
- * computation-intensive parallel processing.
- *
- *
Queues
- *
- * The {@link java.util.concurrent.ConcurrentLinkedQueue} class
- * supplies an efficient scalable thread-safe non-blocking FIFO queue.
- * The {@link java.util.concurrent.ConcurrentLinkedDeque} class is
- * similar, but additionally supports the {@link java.util.Deque}
- * interface.
- *
- * Five implementations in {@code java.util.concurrent} support
- * the extended {@link java.util.concurrent.BlockingQueue}
- * interface, that defines blocking versions of put and take:
- * {@link java.util.concurrent.LinkedBlockingQueue},
- * {@link java.util.concurrent.ArrayBlockingQueue},
- * {@link java.util.concurrent.SynchronousQueue},
- * {@link java.util.concurrent.PriorityBlockingQueue}, and
- * {@link java.util.concurrent.DelayQueue}.
- * The different classes cover the most common usage contexts
- * for producer-consumer, messaging, parallel tasking, and
- * related concurrent designs.
- *
- *
Extended interface {@link java.util.concurrent.TransferQueue},
- * and implementation {@link java.util.concurrent.LinkedTransferQueue}
- * introduce a synchronous {@code transfer} method (along with related
- * features) in which a producer may optionally block awaiting its
- * consumer.
- *
- *
The {@link java.util.concurrent.BlockingDeque} interface
- * extends {@code BlockingQueue} to support both FIFO and LIFO
- * (stack-based) operations.
- * Class {@link java.util.concurrent.LinkedBlockingDeque}
- * provides an implementation.
- *
- *
Timing
- *
- * The {@link java.util.concurrent.TimeUnit} class provides
- * multiple granularities (including nanoseconds) for
- * specifying and controlling time-out based operations. Most
- * classes in the package contain operations based on time-outs
- * in addition to indefinite waits. In all cases that
- * time-outs are used, the time-out specifies the minimum time
- * that the method should wait before indicating that it
- * timed-out. Implementations make a "best effort"
- * to detect time-outs as soon as possible after they occur.
- * However, an indefinite amount of time may elapse between a
- * time-out being detected and a thread actually executing
- * again after that time-out. All methods that accept timeout
- * parameters treat values less than or equal to zero to mean
- * not to wait at all. To wait "forever", you can use a value
- * of {@code Long.MAX_VALUE}.
- *
- * Synchronizers
- *
- * Five classes aid common special-purpose synchronization idioms.
- *
- *
- * {@link java.util.concurrent.Semaphore} is a classic concurrency tool.
- *
- * {@link java.util.concurrent.CountDownLatch} is a very simple yet
- * very common utility for blocking until a given number of signals,
- * events, or conditions hold.
- *
- * A {@link java.util.concurrent.CyclicBarrier} is a resettable
- * multiway synchronization point useful in some styles of parallel
- * programming.
- *
- * A {@link java.util.concurrent.Phaser} provides
- * a more flexible form of barrier that may be used to control phased
- * computation among multiple threads.
- *
- * An {@link java.util.concurrent.Exchanger} allows two threads to
- * exchange objects at a rendezvous point, and is useful in several
- * pipeline designs.
- *
- *
- *
- * Concurrent Collections
- *
- * Besides Queues, this package supplies Collection implementations
- * designed for use in multithreaded contexts:
- * {@link java.util.concurrent.ConcurrentHashMap},
- * {@link java.util.concurrent.ConcurrentSkipListMap},
- * {@link java.util.concurrent.ConcurrentSkipListSet},
- * {@link java.util.concurrent.CopyOnWriteArrayList}, and
- * {@link java.util.concurrent.CopyOnWriteArraySet}.
- * When many threads are expected to access a given collection, a
- * {@code ConcurrentHashMap} is normally preferable to a synchronized
- * {@code HashMap}, and a {@code ConcurrentSkipListMap} is normally
- * preferable to a synchronized {@code TreeMap}.
- * A {@code CopyOnWriteArrayList} is preferable to a synchronized
- * {@code ArrayList} when the expected number of reads and traversals
- * greatly outnumber the number of updates to a list.
- *
- * The "Concurrent" prefix used with some classes in this package
- * is a shorthand indicating several differences from similar
- * "synchronized" classes. For example {@code java.util.Hashtable} and
- * {@code Collections.synchronizedMap(new HashMap())} are
- * synchronized. But {@link
- * java.util.concurrent.ConcurrentHashMap} is "concurrent". A
- * concurrent collection is thread-safe, but not governed by a
- * single exclusion lock. In the particular case of
- * ConcurrentHashMap, it safely permits any number of
- * concurrent reads as well as a tunable number of concurrent
- * writes. "Synchronized" classes can be useful when you need
- * to prevent all access to a collection via a single lock, at
- * the expense of poorer scalability. In other cases in which
- * multiple threads are expected to access a common collection,
- * "concurrent" versions are normally preferable. And
- * unsynchronized collections are preferable when either
- * collections are unshared, or are accessible only when
- * holding other locks.
- *
- *
Most concurrent Collection implementations
- * (including most Queues) also differ from the usual {@code java.util}
- * conventions in that their {@linkplain java.util.Iterator Iterators}
- * and {@linkplain java.util.Spliterator Spliterators} provide
- * weakly consistent rather than fast-fail traversal:
- *
- * they may proceed concurrently with other operations
- * they will never throw {@link java.util.ConcurrentModificationException
- * ConcurrentModificationException}
- * they are guaranteed to traverse elements as they existed upon
- * construction exactly once, and may (but are not guaranteed to)
- * reflect any modifications subsequent to construction.
- *
- *
- * Memory Consistency Properties
- *
- *
- * Chapter 17 of
- * The Java™ Language Specification defines the
- * happens-before relation on memory operations such as reads and
- * writes of shared variables. The results of a write by one thread are
- * guaranteed to be visible to a read by another thread only if the write
- * operation happens-before the read operation. The
- * {@code synchronized} and {@code volatile} constructs, as well as the
- * {@code Thread.start()} and {@code Thread.join()} methods, can form
- * happens-before relationships. In particular:
- *
- *
- * Each action in a thread happens-before every action in that
- * thread that comes later in the program's order.
- *
- * An unlock ({@code synchronized} block or method exit) of a
- * monitor happens-before every subsequent lock ({@code synchronized}
- * block or method entry) of that same monitor. And because
- * the happens-before relation is transitive, all actions
- * of a thread prior to unlocking happen-before all actions
- * subsequent to any thread locking that monitor.
- *
- * A write to a {@code volatile} field happens-before every
- * subsequent read of that same field. Writes and reads of
- * {@code volatile} fields have similar memory consistency effects
- * as entering and exiting monitors, but do not entail
- * mutual exclusion locking.
- *
- * A call to {@code start} on a thread happens-before any
- * action in the started thread.
- *
- * All actions in a thread happen-before any other thread
- * successfully returns from a {@code join} on that thread.
- *
- *
- *
- *
- * The methods of all classes in {@code java.util.concurrent} and its
- * subpackages extend these guarantees to higher-level
- * synchronization. In particular:
- *
- *
- *
- * Actions in a thread prior to placing an object into any concurrent
- * collection happen-before actions subsequent to the access or
- * removal of that element from the collection in another thread.
- *
- * Actions in a thread prior to the submission of a {@code Runnable}
- * to an {@code Executor} happen-before its execution begins.
- * Similarly for {@code Callables} submitted to an {@code ExecutorService}.
- *
- * Actions taken by the asynchronous computation represented by a
- * {@code Future} happen-before actions subsequent to the
- * retrieval of the result via {@code Future.get()} in another thread.
- *
- * Actions prior to "releasing" synchronizer methods such as
- * {@code Lock.unlock}, {@code Semaphore.release}, and
- * {@code CountDownLatch.countDown} happen-before actions
- * subsequent to a successful "acquiring" method such as
- * {@code Lock.lock}, {@code Semaphore.acquire},
- * {@code Condition.await}, and {@code CountDownLatch.await} on the
- * same synchronizer object in another thread.
- *
- * For each pair of threads that successfully exchange objects via
- * an {@code Exchanger}, actions prior to the {@code exchange()}
- * in each thread happen-before those subsequent to the
- * corresponding {@code exchange()} in another thread.
- *
- * Actions prior to calling {@code CyclicBarrier.await} and
- * {@code Phaser.awaitAdvance} (as well as its variants)
- * happen-before actions performed by the barrier action, and
- * actions performed by the barrier action happen-before actions
- * subsequent to a successful return from the corresponding {@code await}
- * in other threads.
- *
- *
- *
- * @since 1.5
- */
-package java.util.concurrent;
diff --git a/luni/src/main/java/javax/xml/datatype/FactoryFinder.java b/luni/src/main/java/javax/xml/datatype/FactoryFinder.java
index 1fbca2faa..c31bee3ab 100644
--- a/luni/src/main/java/javax/xml/datatype/FactoryFinder.java
+++ b/luni/src/main/java/javax/xml/datatype/FactoryFinder.java
@@ -61,8 +61,8 @@ private static class CacheHolder {
File f = new File(configFile);
if (f.exists()) {
if (debug) debugPrintln("Read properties file " + f);
- try {
- cacheProps.load(new FileInputStream(f));
+ try (FileInputStream inputStream = new FileInputStream(f)) {
+ cacheProps.load(inputStream);
} catch (Exception ex) {
if (debug) {
ex.printStackTrace();
diff --git a/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java b/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java
index 0060612df..50a644fba 100644
--- a/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java
+++ b/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java
@@ -62,8 +62,8 @@ private static class CacheHolder {
File f = new File(configFile);
if (f.exists()) {
if (debug) debugPrintln("Read properties file " + f);
- try {
- cacheProps.load(new FileInputStream(f));
+ try (FileInputStream inputStream = new FileInputStream(f)) {
+ cacheProps.load(inputStream);
} catch (Exception ex) {
if (debug) {
ex.printStackTrace();
diff --git a/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java b/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java
index 5a7663c75..7a4f6b33c 100644
--- a/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java
+++ b/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java
@@ -69,8 +69,8 @@ private static class CacheHolder {
File f = new File(configFile);
if (f.exists()) {
if (debug) debugPrintln("Read properties file " + f);
- try {
- cacheProps.load(new FileInputStream(f));
+ try (FileInputStream inputStream = new FileInputStream(f)) {
+ cacheProps.load(inputStream);
} catch (Exception ex) {
if (debug) {
ex.printStackTrace();
diff --git a/luni/src/main/java/libcore/icu/LocaleData.java b/luni/src/main/java/libcore/icu/LocaleData.java
index cf52b9c7a..7d1809862 100644
--- a/luni/src/main/java/libcore/icu/LocaleData.java
+++ b/luni/src/main/java/libcore/icu/LocaleData.java
@@ -17,7 +17,6 @@
package libcore.icu;
import java.text.DateFormat;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import libcore.util.Objects;
@@ -83,10 +82,6 @@ public final class LocaleData {
public String narrowAm; // "a".
public String narrowPm; // "p".
- // shortDateFormat, but guaranteed to have 4-digit years.
- // Used by android.text.format.DateFormat.getDateFormatStringForSetting.
- public String shortDateFormat4;
-
// Used by DateFormat to implement 12- and 24-hour SHORT and MEDIUM.
// The first two are also used directly by frameworks code.
public String timeFormat_hm;
@@ -229,7 +224,6 @@ private static LocaleData initLocaleData(Locale locale) {
// accidentally eat too much.
localeData.integerPattern = localeData.numberPattern.replaceAll("\\.[#,]*", "");
}
- localeData.shortDateFormat4 = localeData.shortDateFormat.replaceAll("\\byy\\b", "y");
return localeData;
}
}
diff --git a/luni/src/main/java/libcore/icu/TimeZoneNames.java b/luni/src/main/java/libcore/icu/TimeZoneNames.java
index daa915edf..917d9ce76 100644
--- a/luni/src/main/java/libcore/icu/TimeZoneNames.java
+++ b/luni/src/main/java/libcore/icu/TimeZoneNames.java
@@ -68,7 +68,7 @@ public ZoneStringsCache() {
}
long nativeStart = System.nanoTime();
- fillZoneStrings(locale.toString(), result);
+ fillZoneStrings(locale.toLanguageTag(), result);
long nativeEnd = System.nanoTime();
internStrings(result);
diff --git a/luni/src/main/java/libcore/io/Base64.java b/luni/src/main/java/libcore/io/Base64.java
deleted file mode 100644
index 236c1669c..000000000
--- a/luni/src/main/java/libcore/io/Base64.java
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package libcore.io;
-
-import java.io.ByteArrayOutputStream;
-import java.nio.charset.StandardCharsets;
-
-/**
- * Perform encoding and decoding of Base64 byte arrays as described in
- * http://www.ietf.org/rfc/rfc2045.txt
- */
-public final class Base64 {
- private static final byte[] BASE_64_ALPHABET = initializeBase64Alphabet();
-
- private static byte[] initializeBase64Alphabet() {
- return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
- .getBytes(StandardCharsets.US_ASCII);
- }
-
- // Bit masks for the 4 output 6-bit values from 3 input bytes.
- private static final int FIRST_OUTPUT_BYTE_MASK = 0x3f << 18;
- private static final int SECOND_OUTPUT_BYTE_MASK = 0x3f << 12;
- private static final int THIRD_OUTPUT_BYTE_MASK = 0x3f << 6;
- private static final int FOURTH_OUTPUT_BYTE_MASK = 0x3f;
-
- private Base64() {}
-
- public static String encode(byte[] in) {
- int len = in.length;
- int outputLen = computeEncodingOutputLen(len);
- byte[] output = new byte[outputLen];
-
- int outputIndex = 0;
- for (int i = 0; i < len; i += 3) {
- // Only a "triplet" if there are there are at least three remaining bytes
- // in the input...
- // Mask with 0xff to avoid signed extension.
- int byteTripletAsInt = in[i] & 0xff;
- if (i + 1 < len) {
- // Add second byte to the triplet.
- byteTripletAsInt <<= 8;
- byteTripletAsInt |= in[i + 1] & 0xff;
- if (i + 2 < len) {
- byteTripletAsInt <<= 8;
- byteTripletAsInt |= in[i + 2] & 0xff;
- } else {
- // Insert 2 zero bits as to make output 18 bits long.
- byteTripletAsInt <<= 2;
- }
- } else {
- // Insert 4 zero bits as to make output 12 bits long.
- byteTripletAsInt <<= 4;
- }
-
- if (i + 2 < len) {
- // The int may have up to 24 non-zero bits.
- output[outputIndex++] = BASE_64_ALPHABET[
- (byteTripletAsInt & FIRST_OUTPUT_BYTE_MASK) >>> 18];
- }
- if (i + 1 < len) {
- // The int may have up to 18 non-zero bits.
- output[outputIndex++] = BASE_64_ALPHABET[
- (byteTripletAsInt & SECOND_OUTPUT_BYTE_MASK) >>> 12];
- }
- output[outputIndex++] = BASE_64_ALPHABET[
- (byteTripletAsInt & THIRD_OUTPUT_BYTE_MASK) >>> 6];
- output[outputIndex++] = BASE_64_ALPHABET[
- byteTripletAsInt & FOURTH_OUTPUT_BYTE_MASK];
- }
-
- int inLengthMod3 = len % 3;
- // Add padding as per the spec.
- if (inLengthMod3 > 0) {
- output[outputIndex++] = '=';
- if (inLengthMod3 == 1) {
- output[outputIndex++] = '=';
- }
- }
-
- return new String(output, StandardCharsets.US_ASCII);
- }
-
- private static int computeEncodingOutputLen(int inLength) {
- int inLengthMod3 = inLength % 3;
- int outputLen = (inLength / 3) * 4;
- if (inLengthMod3 == 2) {
- // Need 3 6-bit characters as to express the last 16 bits, plus 1 padding.
- outputLen += 4;
- } else if (inLengthMod3 == 1) {
- // Need 2 6-bit characters as to express the last 8 bits, plus 2 padding.
- outputLen += 4;
- }
- return outputLen;
- }
-
- public static byte[] decode(byte[] in) {
- return decode(in, in.length);
- }
-
- /** Decodes the input from position 0 (inclusive) to len (exclusive). */
- public static byte[] decode(byte[] in, int len) {
- final int inLength = Math.min(in.length, len);
- // Overestimating 3 bytes per each 4 blocks of input (plus a possibly incomplete one).
- ByteArrayOutputStream output = new ByteArrayOutputStream((inLength / 4) * 3 + 3);
- // Position in the input. Use an array so we can pass it to {@code getNextByte}.
- int[] pos = new int[1];
-
- try {
- while (pos[0] < inLength) {
- int byteTripletAsInt = 0;
-
- // j is the index in a 4-tuple of 6-bit characters where are trying to read from the
- // input.
- for (int j = 0; j < 4; j++) {
- byte c = getNextByte(in, pos, inLength);
- if (c == END_OF_INPUT || c == PAD_AS_BYTE) {
- // Padding or end of file...
- switch (j) {
- case 0:
- case 1:
- return (c == END_OF_INPUT) ? output.toByteArray() : null;
- case 2:
- // The input is over with two 6-bit characters: a single byte padded
- // with 4 extra 0's.
-
- if (c == END_OF_INPUT) {
- // Do not consider the block, since padding is not present.
- return checkNoTrailingAndReturn(output, in, pos[0], inLength);
- }
- // We are at a pad character, consume and look for the second one.
- pos[0]++;
- c = getNextByte(in, pos, inLength);
- if (c == END_OF_INPUT) {
- // Do not consider the block, since padding is not present.
- return checkNoTrailingAndReturn(output, in, pos[0], inLength);
- }
- if (c == PAD_AS_BYTE) {
- byteTripletAsInt >>= 4;
- output.write(byteTripletAsInt);
- return checkNoTrailingAndReturn(output, in, pos[0], inLength);
- }
- // Something other than pad and non-alphabet characters, illegal.
- return null;
-
-
- case 3:
- // The input is over with three 6-bit characters: two bytes padded
- // with 2 extra 0's.
- if (c == PAD_AS_BYTE) {
- // Consider the block only if padding is present.
- byteTripletAsInt >>= 2;
- output.write(byteTripletAsInt >> 8);
- output.write(byteTripletAsInt & 0xff);
- }
- return checkNoTrailingAndReturn(output, in, pos[0], inLength);
- }
- } else {
- byteTripletAsInt <<= 6;
- byteTripletAsInt += (c & 0xff);
- pos[0]++;
- }
- }
- // We have four 6-bit characters: output the corresponding 3 bytes
- output.write(byteTripletAsInt >> 16);
- output.write((byteTripletAsInt >> 8) & 0xff);
- output.write(byteTripletAsInt & 0xff);
- }
- return checkNoTrailingAndReturn(output, in, pos[0], inLength);
- } catch (InvalidBase64ByteException e) {
- return null;
- }
- }
-
- /**
- * On decoding, an illegal character always return null.
- *
- * Using this exception to avoid "if" checks every time.
- */
-
- private static class InvalidBase64ByteException extends Exception { }
-
- /**
- * Obtain the numeric value corresponding to the next relevant byte in the input.
- *
- * Calculates the numeric value (6-bit, 0 <= x <= 63) of the next Base64 encoded byte in
- * {@code in} at or after {@code pos[0]} and before {@code inLength}. Returns
- * {@link #WHITESPACE_AS_BYTE}, {@link #PAD_AS_BYTE}, {@link #END_OF_INPUT} or the 6-bit value.
- * {@code pos[0]} is updated as a side effect of this method.
- */
- private static byte getNextByte(byte[] in, int[] pos, int inLength)
- throws InvalidBase64ByteException {
- // Ignore all whitespace.
- while (pos[0] < inLength) {
- byte c = base64AlphabetToNumericalValue(in[pos[0]]);
- if (c != WHITESPACE_AS_BYTE) {
- return c;
- }
- pos[0]++;
- }
- return END_OF_INPUT;
- }
-
- /**
- * Check that there are no invalid trailing characters (ie, other then whitespace and padding)
- *
- * Returns {@code output} as a byte array in case of success, {@code null} in case of invalid
- * characters.
- */
- private static byte[] checkNoTrailingAndReturn(
- ByteArrayOutputStream output, byte[] in, int i, int inLength)
- throws InvalidBase64ByteException{
- while (i < inLength) {
- byte c = base64AlphabetToNumericalValue(in[i]);
- if (c != WHITESPACE_AS_BYTE && c != PAD_AS_BYTE) {
- return null;
- }
- i++;
- }
- return output.toByteArray();
- }
-
- private static final byte PAD_AS_BYTE = -1;
- private static final byte WHITESPACE_AS_BYTE = -2;
- private static final byte END_OF_INPUT = -3;
- private static byte base64AlphabetToNumericalValue(byte c) throws InvalidBase64ByteException {
- if ('A' <= c && c <= 'Z') {
- return (byte) (c - 'A');
- }
- if ('a' <= c && c <= 'z') {
- return (byte) (c - 'a' + 26);
- }
- if ('0' <= c && c <= '9') {
- return (byte) (c - '0' + 52);
- }
- if (c == '+') {
- return (byte) 62;
- }
- if (c == '/') {
- return (byte) 63;
- }
- if (c == '=') {
- return PAD_AS_BYTE;
- }
- if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
- return WHITESPACE_AS_BYTE;
- }
- throw new InvalidBase64ByteException();
- }
-}
diff --git a/luni/src/main/java/libcore/io/BlockGuardOs.java b/luni/src/main/java/libcore/io/BlockGuardOs.java
index 2523c7189..111c5842f 100644
--- a/luni/src/main/java/libcore/io/BlockGuardOs.java
+++ b/luni/src/main/java/libcore/io/BlockGuardOs.java
@@ -17,6 +17,7 @@
package libcore.io;
import android.system.ErrnoException;
+import android.system.OsConstants;
import android.system.StructLinger;
import android.system.StructPollfd;
import android.system.StructStat;
@@ -32,7 +33,6 @@
import java.net.SocketException;
import java.nio.ByteBuffer;
import static android.system.OsConstants.*;
-import static dalvik.system.BlockGuard.DISALLOW_NETWORK;
/**
* Informs BlockGuard of any activity it should be aware of.
@@ -61,7 +61,11 @@ private void untagSocket(FileDescriptor fd) throws ErrnoException {
@Override public FileDescriptor accept(FileDescriptor fd, SocketAddress peerAddress) throws ErrnoException, SocketException {
BlockGuard.getThreadPolicy().onNetwork();
- return tagSocket(os.accept(fd, peerAddress));
+ final FileDescriptor acceptFd = os.accept(fd, peerAddress);
+ if (isInetSocket(acceptFd)) {
+ tagSocket(acceptFd);
+ }
+ return acceptFd;
}
@Override public boolean access(String path, int mode) throws ErrnoException {
@@ -91,7 +95,9 @@ private void untagSocket(FileDescriptor fd) throws ErrnoException {
// connections in methods like onDestroy which will run on the UI thread.
BlockGuard.getThreadPolicy().onNetwork();
}
- untagSocket(fd);
+ if (isInetSocket(fd)) {
+ untagSocket(fd);
+ }
}
} catch (ErrnoException ignored) {
// We're called via Socket.close (which doesn't ask for us to be called), so we
@@ -102,6 +108,14 @@ private void untagSocket(FileDescriptor fd) throws ErrnoException {
os.close(fd);
}
+ private static boolean isInetSocket(FileDescriptor fd) throws ErrnoException{
+ return isInetDomain(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_DOMAIN));
+ }
+
+ private static boolean isInetDomain(int domain) {
+ return (domain == AF_INET) || (domain == AF_INET6);
+ }
+
private static boolean isLingerSocket(FileDescriptor fd) throws ErrnoException {
StructLinger linger = Libcore.os.getsockoptLinger(fd, SOL_SOCKET, SO_LINGER);
return linger.isOn() && linger.l_linger > 0;
@@ -112,6 +126,12 @@ private static boolean isLingerSocket(FileDescriptor fd) throws ErrnoException {
os.connect(fd, address, port);
}
+ @Override public void connect(FileDescriptor fd, SocketAddress address) throws ErrnoException,
+ SocketException {
+ BlockGuard.getThreadPolicy().onNetwork();
+ os.connect(fd, address);
+ }
+
@Override public void fchmod(FileDescriptor fd, int mode) throws ErrnoException {
BlockGuard.getThreadPolicy().onWriteToDisk();
os.fchmod(fd, mode);
@@ -181,7 +201,7 @@ private static boolean isLingerSocket(FileDescriptor fd) throws ErrnoException {
@Override public FileDescriptor open(String path, int flags, int mode) throws ErrnoException {
BlockGuard.getThreadPolicy().onReadFromDisk();
- if ((mode & O_ACCMODE) != O_RDONLY) {
+ if ((flags & O_ACCMODE) != O_RDONLY) {
BlockGuard.getThreadPolicy().onWriteToDisk();
}
return os.open(path, flags, mode);
@@ -285,13 +305,19 @@ private static boolean isLingerSocket(FileDescriptor fd) throws ErrnoException {
}
@Override public FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException {
- return tagSocket(os.socket(domain, type, protocol));
+ final FileDescriptor fd = os.socket(domain, type, protocol);
+ if (isInetDomain(domain)) {
+ tagSocket(fd);
+ }
+ return fd;
}
@Override public void socketpair(int domain, int type, int protocol, FileDescriptor fd1, FileDescriptor fd2) throws ErrnoException {
os.socketpair(domain, type, protocol, fd1, fd2);
- tagSocket(fd1);
- tagSocket(fd2);
+ if (isInetDomain(domain)) {
+ tagSocket(fd1);
+ tagSocket(fd2);
+ }
}
@Override public StructStat stat(String path) throws ErrnoException {
@@ -323,4 +349,49 @@ private static boolean isLingerSocket(FileDescriptor fd) throws ErrnoException {
BlockGuard.getThreadPolicy().onWriteToDisk();
return os.writev(fd, buffers, offsets, byteCounts);
}
+
+ @Override public void execv(String filename, String[] argv) throws ErrnoException {
+ BlockGuard.getThreadPolicy().onReadFromDisk();
+ os.execv(filename, argv);
+ }
+
+ @Override public void execve(String filename, String[] argv, String[] envp)
+ throws ErrnoException {
+ BlockGuard.getThreadPolicy().onReadFromDisk();
+ os.execve(filename, argv, envp);
+ }
+
+ @Override public byte[] getxattr(String path, String name) throws ErrnoException {
+ BlockGuard.getThreadPolicy().onReadFromDisk();
+ return os.getxattr(path, name);
+ }
+
+ @Override public void msync(long address, long byteCount, int flags) throws ErrnoException {
+ if ((flags & OsConstants.MS_SYNC) != 0) {
+ BlockGuard.getThreadPolicy().onWriteToDisk();
+ }
+ os.msync(address, byteCount, flags);
+ }
+
+ @Override public void removexattr(String path, String name) throws ErrnoException {
+ BlockGuard.getThreadPolicy().onWriteToDisk();
+ os.removexattr(path, name);
+ }
+
+ @Override public void setxattr(String path, String name, byte[] value, int flags)
+ throws ErrnoException {
+ BlockGuard.getThreadPolicy().onWriteToDisk();
+ os.setxattr(path, name, value, flags);
+ }
+
+ @Override public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount,
+ int flags, SocketAddress address) throws ErrnoException, SocketException {
+ BlockGuard.getThreadPolicy().onNetwork();
+ return os.sendto(fd, bytes, byteOffset, byteCount, flags, address);
+ }
+
+ @Override public void unlink(String pathname) throws ErrnoException {
+ BlockGuard.getThreadPolicy().onWriteToDisk();
+ os.unlink(pathname);
+ }
}
diff --git a/luni/src/main/java/libcore/io/BufferIterator.java b/luni/src/main/java/libcore/io/BufferIterator.java
index 7f3ad472b..0d167e340 100644
--- a/luni/src/main/java/libcore/io/BufferIterator.java
+++ b/luni/src/main/java/libcore/io/BufferIterator.java
@@ -20,11 +20,12 @@
* Iterates over big- or little-endian bytes. See {@link MemoryMappedFile#bigEndianIterator} and
* {@link MemoryMappedFile#littleEndianIterator}.
*
- * @hide don't make this public without adding bounds checking.
+ * @hide
*/
public abstract class BufferIterator {
/**
- * Seeks to the absolute position {@code offset}, measured in bytes from the start.
+ * Seeks to the absolute position {@code offset}, measured in bytes from the start of the
+ * buffer.
*/
public abstract void seek(int offset);
@@ -33,30 +34,45 @@ public abstract class BufferIterator {
*/
public abstract void skip(int byteCount);
+ /**
+ * Returns the current position of the iterator within the buffer.
+ */
+ public abstract int pos();
+
/**
* Copies {@code byteCount} bytes from the current position into {@code dst}, starting at
* {@code dstOffset}, and advances the current position {@code byteCount} bytes.
+ *
+ * @throws IndexOutOfBoundsException if the read / write would be outside of the buffer / array
*/
public abstract void readByteArray(byte[] dst, int dstOffset, int byteCount);
/**
* Returns the byte at the current position, and advances the current position one byte.
+ *
+ * @throws IndexOutOfBoundsException if the read would be outside of the buffer
*/
public abstract byte readByte();
/**
* Returns the 32-bit int at the current position, and advances the current position four bytes.
+ *
+ * @throws IndexOutOfBoundsException if the read would be outside of the buffer
*/
public abstract int readInt();
/**
* Copies {@code intCount} 32-bit ints from the current position into {@code dst}, starting at
* {@code dstOffset}, and advances the current position {@code 4 * intCount} bytes.
+ *
+ * @throws IndexOutOfBoundsException if the read / write would be outside of the buffer / array
*/
public abstract void readIntArray(int[] dst, int dstOffset, int intCount);
/**
* Returns the 16-bit short at the current position, and advances the current position two bytes.
+ *
+ * @throws IndexOutOfBoundsException if the read would be outside of the buffer
*/
public abstract short readShort();
}
diff --git a/luni/src/main/java/libcore/io/ClassPathURLStreamHandler.java b/luni/src/main/java/libcore/io/ClassPathURLStreamHandler.java
index 9f8a84402..117c1f8aa 100644
--- a/luni/src/main/java/libcore/io/ClassPathURLStreamHandler.java
+++ b/luni/src/main/java/libcore/io/ClassPathURLStreamHandler.java
@@ -103,7 +103,22 @@ static ZipEntry findEntryWithDirectoryFallback(JarFile jarFile, String entryName
}
private class ClassPathURLConnection extends JarURLConnection {
- // The JarFile instance is shared across URLConnections and must not be closed.
+ // The JarFile instance can be shared across URLConnections and should not be closed when it is:
+ //
+ // Sharing occurs if getUseCaches() is true when connect() is called (which can take place
+ // implicitly). useCachedJarFile records the state of sharing at connect() time.
+ // useCachedJarFile == true is the common case. If developers call getJarFile().close() when
+ // sharing is enabled then it will affect other users (current and future) of the shared
+ // JarFile.
+ //
+ // Developers could call ClassLoader.findResource().openConnection() to get a URLConnection and
+ // then call setUseCaches(false) before connect() to prevent sharing. The developer must then
+ // call getJarFile().close() or close() on the inputStream from getInputStream() will do it
+ // automatically. This is likely to be an extremely rare case.
+ //
+ // Most developers are not expecting to deal with the lifecycle of the underlying JarFile object
+ // at all. The presence of the getJarFile() method and setUseCaches() forces us to consider /
+ // handle it.
private JarFile connectionJarFile;
private ZipEntry jarEntry;
@@ -141,7 +156,7 @@ public JarFile getJarFile() throws IOException {
connect();
// We do cache in the surrounding class if useCachedJarFile is true to
- // preserve garbage collection semantics to avoid leak warnings.
+ // preserve garbage collection semantics and to avoid leak warnings.
if (useCachedJarFile) {
connectionJarFile = jarFile;
} else {
@@ -163,8 +178,9 @@ public InputStream getInputStream() throws IOException {
@Override
public void close() throws IOException {
super.close();
- // If the jar file is not cached closing the input stream will close the URLConnection and
- // any JarFile returned from getJarFile().
+ // If the jar file is not cached then closing the input stream will close the
+ // URLConnection and any JarFile returned from getJarFile(). If the jar file is cached
+ // we must not close it because it will affect other URLConnections.
if (connectionJarFile != null && !useCachedJarFile) {
connectionJarFile.close();
closed = true;
diff --git a/luni/src/main/java/libcore/io/DropBox.java b/luni/src/main/java/libcore/io/DropBox.java
index cf881060a..4180a2aee 100644
--- a/luni/src/main/java/libcore/io/DropBox.java
+++ b/luni/src/main/java/libcore/io/DropBox.java
@@ -16,6 +16,8 @@
package libcore.io;
+import java.util.Base64;
+
public final class DropBox {
/**
@@ -54,7 +56,7 @@ public static interface Reporter {
private static final class DefaultReporter implements Reporter {
public void addData(String tag, byte[] data, int flags) {
- System.out.println(tag + ": " + Base64.encode(data));
+ System.out.println(tag + ": " + Base64.getEncoder().encodeToString(data));
}
public void addText(String tag, String data) {
diff --git a/luni/src/main/java/libcore/io/ForwardingOs.java b/luni/src/main/java/libcore/io/ForwardingOs.java
index fbf89398c..55d4d8243 100644
--- a/luni/src/main/java/libcore/io/ForwardingOs.java
+++ b/luni/src/main/java/libcore/io/ForwardingOs.java
@@ -19,9 +19,12 @@
import android.system.ErrnoException;
import android.system.GaiException;
import android.system.StructAddrinfo;
+import android.system.StructCapUserData;
+import android.system.StructCapUserHeader;
import android.system.StructFlock;
import android.system.StructGroupReq;
import android.system.StructGroupSourceReq;
+import android.system.StructIfaddrs;
import android.system.StructLinger;
import android.system.StructPasswd;
import android.system.StructPollfd;
@@ -55,6 +58,14 @@ public ForwardingOs(Os os) {
public InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException { return os.android_getaddrinfo(node, hints, netId); }
public void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException { os.bind(fd, address, port); }
public void bind(FileDescriptor fd, SocketAddress address) throws ErrnoException, SocketException { os.bind(fd, address); }
+ @Override
+ public StructCapUserData[] capget(StructCapUserHeader hdr) throws ErrnoException {
+ return os.capget(hdr);
+ }
+ @Override
+ public void capset(StructCapUserHeader hdr, StructCapUserData[] data) throws ErrnoException {
+ os.capset(hdr, data);
+ }
public void chmod(String path, int mode) throws ErrnoException { os.chmod(path, mode); }
public void chown(String path, int uid, int gid) throws ErrnoException { os.chown(path, uid, gid); }
public void close(FileDescriptor fd) throws ErrnoException { os.close(fd); }
@@ -96,16 +107,21 @@ public ForwardingOs(Os os) {
public StructUcred getsockoptUcred(FileDescriptor fd, int level, int option) throws ErrnoException { return os.getsockoptUcred(fd, level, option); }
public int gettid() { return os.gettid(); }
public int getuid() { return os.getuid(); }
- public int getxattr(String path, String name, byte[] outValue) throws ErrnoException { return os.getxattr(path, name, outValue); }
+ public byte[] getxattr(String path, String name) throws ErrnoException { return os.getxattr(path, name); }
+ public StructIfaddrs[] getifaddrs() throws ErrnoException { return os.getifaddrs(); }
public String if_indextoname(int index) { return os.if_indextoname(index); }
+ public int if_nametoindex(String name) { return os.if_nametoindex(name); }
public InetAddress inet_pton(int family, String address) { return os.inet_pton(family, address); }
+ public int ioctlFlags(FileDescriptor fd, String interfaceName) throws ErrnoException { return os.ioctlFlags(fd, interfaceName); };
public InetAddress ioctlInetAddress(FileDescriptor fd, int cmd, String interfaceName) throws ErrnoException { return os.ioctlInetAddress(fd, cmd, interfaceName); }
public int ioctlInt(FileDescriptor fd, int cmd, MutableInt arg) throws ErrnoException { return os.ioctlInt(fd, cmd, arg); }
+ public int ioctlMTU(FileDescriptor fd, String interfaceName) throws ErrnoException { return os.ioctlMTU(fd, interfaceName); };
public boolean isatty(FileDescriptor fd) { return os.isatty(fd); }
public void kill(int pid, int signal) throws ErrnoException { os.kill(pid, signal); }
public void lchown(String path, int uid, int gid) throws ErrnoException { os.lchown(path, uid, gid); }
public void link(String oldPath, String newPath) throws ErrnoException { os.link(oldPath, newPath); }
public void listen(FileDescriptor fd, int backlog) throws ErrnoException { os.listen(fd, backlog); }
+ public String[] listxattr(String path) throws ErrnoException { return os.listxattr(path); }
public long lseek(FileDescriptor fd, long offset, int whence) throws ErrnoException { return os.lseek(fd, offset, whence); }
public StructStat lstat(String path) throws ErrnoException { return os.lstat(path); }
public void mincore(long address, long byteCount, byte[] vector) throws ErrnoException { os.mincore(address, byteCount, vector); }
diff --git a/luni/src/main/java/libcore/io/IoBridge.java b/luni/src/main/java/libcore/io/IoBridge.java
index acf9b3973..0c34d5e1b 100644
--- a/luni/src/main/java/libcore/io/IoBridge.java
+++ b/luni/src/main/java/libcore/io/IoBridge.java
@@ -98,7 +98,12 @@ public static void bind(FileDescriptor fd, InetAddress address, int port) throws
try {
Libcore.os.bind(fd, address, port);
} catch (ErrnoException errnoException) {
- throw new BindException(errnoException.getMessage(), errnoException);
+ if (errnoException.errno == EADDRINUSE || errnoException.errno == EADDRNOTAVAIL ||
+ errnoException.errno == EPERM || errnoException.errno == EACCES) {
+ throw new BindException(errnoException.getMessage(), errnoException);
+ } else {
+ throw new SocketException(errnoException.getMessage(), errnoException);
+ }
}
}
@@ -123,7 +128,8 @@ public static void connect(FileDescriptor fd, InetAddress inetAddress, int port,
try {
connectErrno(fd, inetAddress, port, timeoutMs);
} catch (ErrnoException errnoException) {
- throw new ConnectException(connectDetail(inetAddress, port, timeoutMs, errnoException), errnoException);
+ throw new ConnectException(connectDetail(fd, inetAddress, port, timeoutMs,
+ errnoException), errnoException);
} catch (SocketException ex) {
throw ex; // We don't want to doubly wrap these.
} catch (SocketTimeoutException ex) {
@@ -169,21 +175,44 @@ private static void connectErrno(FileDescriptor fd, InetAddress inetAddress, int
remainingTimeoutMs =
(int) TimeUnit.NANOSECONDS.toMillis(finishTimeNanos - System.nanoTime());
if (remainingTimeoutMs <= 0) {
- throw new SocketTimeoutException(connectDetail(inetAddress, port, timeoutMs, null));
+ throw new SocketTimeoutException(connectDetail(fd, inetAddress, port, timeoutMs,
+ null));
}
} while (!IoBridge.isConnected(fd, inetAddress, port, timeoutMs, remainingTimeoutMs));
IoUtils.setBlocking(fd, true); // 4. set the socket back to blocking.
}
- private static String connectDetail(InetAddress inetAddress, int port, int timeoutMs, ErrnoException cause) {
- String detail = "failed to connect to " + inetAddress + " (port " + port + ")";
+ private static String connectDetail(FileDescriptor fd, InetAddress inetAddress, int port,
+ int timeoutMs, Exception cause) {
+ // Figure out source address from fd.
+ InetSocketAddress localAddress = null;
+ try {
+ localAddress = getLocalInetSocketAddress(fd);
+ } catch (SocketException ignored) { }
+
+ StringBuilder sb = new StringBuilder("failed to connect")
+ .append(" to ")
+ .append(inetAddress)
+ .append(" (port ")
+ .append(port)
+ .append(")");
+ if (localAddress != null) {
+ sb.append(" from ")
+ .append(localAddress.getAddress())
+ .append(" (port ")
+ .append(localAddress.getPort())
+ .append(")");
+ }
if (timeoutMs > 0) {
- detail += " after " + timeoutMs + "ms";
+ sb.append(" after ")
+ .append(timeoutMs)
+ .append("ms");
}
if (cause != null) {
- detail += ": " + cause.getMessage();
+ sb.append(": ")
+ .append(cause.getMessage());
}
- return detail;
+ return sb.toString();
}
/**
@@ -230,7 +259,7 @@ public static boolean isConnected(FileDescriptor fd, InetAddress inetAddress, in
}
cause = errnoException;
}
- String detail = connectDetail(inetAddress, port, timeoutMs, cause);
+ String detail = connectDetail(fd, inetAddress, port, timeoutMs, cause);
if (cause.errno == ETIMEDOUT) {
throw new SocketTimeoutException(detail, cause);
}
@@ -245,6 +274,7 @@ public static boolean isConnected(FileDescriptor fd, InetAddress inetAddress, in
public static final int JAVA_MCAST_BLOCK_SOURCE = 23;
public static final int JAVA_MCAST_UNBLOCK_SOURCE = 24;
public static final int JAVA_IP_MULTICAST_TTL = 17;
+ public static final int JAVA_IP_TTL = 25;
/**
* java.net has its own socket options similar to the underlying Unix ones. We paper over the
@@ -261,19 +291,22 @@ public static Object getSocketOption(FileDescriptor fd, int option) throws Socke
private static Object getSocketOptionErrno(FileDescriptor fd, int option) throws ErrnoException, SocketException {
switch (option) {
case SocketOptions.IP_MULTICAST_IF:
- // This is IPv4-only.
- return Libcore.os.getsockoptInAddr(fd, IPPROTO_IP, IP_MULTICAST_IF);
case SocketOptions.IP_MULTICAST_IF2:
- // This is IPv6-only.
return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF);
case SocketOptions.IP_MULTICAST_LOOP:
// Since setting this from java.net always sets IPv4 and IPv6 to the same value,
// it doesn't matter which we return.
- return booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP));
+ // NOTE: getsockopt's return value means "isEnabled", while OpenJDK code java.net
+ // requires a value that means "isDisabled" so we NEGATE the system call value here.
+ return !booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP));
case IoBridge.JAVA_IP_MULTICAST_TTL:
// Since setting this from java.net always sets IPv4 and IPv6 to the same value,
// it doesn't matter which we return.
return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
+ case IoBridge.JAVA_IP_TTL:
+ // Since setting this from java.net always sets IPv4 and IPv6 to the same value,
+ // it doesn't matter which we return.
+ return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS);
case SocketOptions.IP_TOS:
// Since setting this from java.net always sets IPv4 and IPv6 to the same value,
// it doesn't matter which we return.
@@ -300,6 +333,8 @@ private static Object getSocketOptionErrno(FileDescriptor fd, int option) throws
return (int) Libcore.os.getsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO).toMillis();
case SocketOptions.TCP_NODELAY:
return booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_TCP, TCP_NODELAY));
+ case SocketOptions.SO_BINDADDR:
+ return ((InetSocketAddress) Libcore.os.getsockname(fd)).getAddress();
default:
throw new SocketException("Unknown socket option: " + option);
}
@@ -328,7 +363,15 @@ public static void setSocketOption(FileDescriptor fd, int option, Object value)
private static void setSocketOptionErrno(FileDescriptor fd, int option, Object value) throws ErrnoException, SocketException {
switch (option) {
case SocketOptions.IP_MULTICAST_IF:
- throw new UnsupportedOperationException("Use IP_MULTICAST_IF2 on Android");
+ NetworkInterface nif = NetworkInterface.getByInetAddress((InetAddress) value);
+ if (nif == null) {
+ throw new SocketException(
+ "bad argument for IP_MULTICAST_IF : address not bound to any interface");
+ }
+ // Although IPv6 was cleaned up to use int, IPv4 uses an ip_mreqn containing an int.
+ Libcore.os.setsockoptIpMreqn(fd, IPPROTO_IP, IP_MULTICAST_IF, nif.getIndex());
+ Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, nif.getIndex());
+ return;
case SocketOptions.IP_MULTICAST_IF2:
// Although IPv6 was cleaned up to use int, IPv4 uses an ip_mreqn containing an int.
Libcore.os.setsockoptIpMreqn(fd, IPPROTO_IP, IP_MULTICAST_IF, (Integer) value);
@@ -336,8 +379,11 @@ private static void setSocketOptionErrno(FileDescriptor fd, int option, Object v
return;
case SocketOptions.IP_MULTICAST_LOOP:
// Although IPv6 was cleaned up to use int, IPv4 multicast loopback uses a byte.
- Libcore.os.setsockoptByte(fd, IPPROTO_IP, IP_MULTICAST_LOOP, booleanToInt((Boolean) value));
- Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, booleanToInt((Boolean) value));
+ // NOTE: setsockopt's arguement value means "isEnabled", while OpenJDK code java.net
+ // uses a value that means "isDisabled" so we NEGATE the system call value here.
+ int enable = booleanToInt(!((Boolean) value));
+ Libcore.os.setsockoptByte(fd, IPPROTO_IP, IP_MULTICAST_LOOP, enable);
+ Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, enable);
return;
case IoBridge.JAVA_IP_MULTICAST_TTL:
// Although IPv6 was cleaned up to use int, and IPv4 non-multicast TTL uses int,
@@ -345,6 +391,10 @@ private static void setSocketOptionErrno(FileDescriptor fd, int option, Object v
Libcore.os.setsockoptByte(fd, IPPROTO_IP, IP_MULTICAST_TTL, (Integer) value);
Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (Integer) value);
return;
+ case IoBridge.JAVA_IP_TTL:
+ Libcore.os.setsockoptInt(fd, IPPROTO_IP, IP_TTL, (Integer) value);
+ Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (Integer) value);
+ return;
case SocketOptions.IP_TOS:
Libcore.os.setsockoptInt(fd, IPPROTO_IP, IP_TOS, (Integer) value);
Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_TCLASS, (Integer) value);
@@ -530,10 +580,11 @@ public static int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAd
return result;
}
- private static int maybeThrowAfterSendto(boolean isDatagram, ErrnoException errnoException) throws SocketException {
+ private static int maybeThrowAfterSendto(boolean isDatagram, ErrnoException errnoException)
+ throws IOException {
if (isDatagram) {
- if (errnoException.errno == ECONNRESET || errnoException.errno == ECONNREFUSED) {
- return 0;
+ if (errnoException.errno == ECONNREFUSED) {
+ throw new PortUnreachableException("ICMP Port Unreachable");
}
} else {
if (errnoException.errno == EAGAIN) {
@@ -542,15 +593,15 @@ private static int maybeThrowAfterSendto(boolean isDatagram, ErrnoException errn
return 0;
}
}
- throw errnoException.rethrowAsSocketException();
+ throw errnoException.rethrowAsIOException();
}
public static int recvfrom(boolean isRead, FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, DatagramPacket packet, boolean isConnected) throws IOException {
int result;
try {
- InetSocketAddress srcAddress = (packet != null && !isConnected) ? new InetSocketAddress() : null;
+ InetSocketAddress srcAddress = packet != null ? new InetSocketAddress() : null;
result = Libcore.os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress);
- result = postRecvfrom(isRead, packet, isConnected, srcAddress, result);
+ result = postRecvfrom(isRead, packet, srcAddress, result);
} catch (ErrnoException errnoException) {
result = maybeThrowAfterRecvfrom(isRead, isConnected, errnoException);
}
@@ -560,24 +611,26 @@ public static int recvfrom(boolean isRead, FileDescriptor fd, byte[] bytes, int
public static int recvfrom(boolean isRead, FileDescriptor fd, ByteBuffer buffer, int flags, DatagramPacket packet, boolean isConnected) throws IOException {
int result;
try {
- InetSocketAddress srcAddress = (packet != null && !isConnected) ? new InetSocketAddress() : null;
+ InetSocketAddress srcAddress = packet != null ? new InetSocketAddress() : null;
result = Libcore.os.recvfrom(fd, buffer, flags, srcAddress);
- result = postRecvfrom(isRead, packet, isConnected, srcAddress, result);
+ result = postRecvfrom(isRead, packet, srcAddress, result);
} catch (ErrnoException errnoException) {
result = maybeThrowAfterRecvfrom(isRead, isConnected, errnoException);
}
return result;
}
- private static int postRecvfrom(boolean isRead, DatagramPacket packet, boolean isConnected, InetSocketAddress srcAddress, int byteCount) {
+ private static int postRecvfrom(boolean isRead, DatagramPacket packet, InetSocketAddress srcAddress, int byteCount) {
if (isRead && byteCount == 0) {
return -1;
}
if (packet != null) {
packet.setReceivedLength(byteCount);
- if (!isConnected) {
+ packet.setPort(srcAddress.getPort());
+
+ // packet.address should only be changed when it is different from srcAddress.
+ if (!srcAddress.getAddress().equals(packet.getAddress())) {
packet.setAddress(srcAddress.getAddress());
- packet.setPort(srcAddress.getPort());
}
}
return byteCount;
@@ -592,7 +645,7 @@ private static int maybeThrowAfterRecvfrom(boolean isRead, boolean isConnected,
}
} else {
if (isConnected && errnoException.errno == ECONNREFUSED) {
- throw new PortUnreachableException("", errnoException);
+ throw new PortUnreachableException("ICMP Port Unreachable", errnoException);
} else if (errnoException.errno == EAGAIN) {
throw new SocketTimeoutException(errnoException);
} else {
@@ -601,21 +654,10 @@ private static int maybeThrowAfterRecvfrom(boolean isRead, boolean isConnected,
}
}
- public static FileDescriptor socket(boolean stream) throws SocketException {
+ public static FileDescriptor socket(int domain, int type, int protocol) throws SocketException {
FileDescriptor fd;
try {
- fd = Libcore.os.socket(AF_INET6, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
-
- // The RFC (http://www.ietf.org/rfc/rfc3493.txt) says that IPV6_MULTICAST_HOPS defaults
- // to 1. The Linux kernel (at least up to 2.6.38) accidentally defaults to 64 (which
- // would be correct for the *unicast* hop limit).
- // See http://www.spinics.net/lists/netdev/msg129022.html, though no patch appears to
- // have been applied as a result of that discussion. If that bug is ever fixed, we can
- // remove this code. Until then, we manually set the hop limit on IPv6 datagram sockets.
- // (IPv4 is already correct.)
- if (!stream) {
- Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 1);
- }
+ fd = Libcore.os.socket(domain, type, protocol);
return fd;
} catch (ErrnoException errnoException) {
@@ -623,21 +665,32 @@ public static FileDescriptor socket(boolean stream) throws SocketException {
}
}
- public static InetAddress getSocketLocalAddress(FileDescriptor fd) throws SocketException {
+ /**
+ * Wait for some event on a file descriptor, blocks until the event happened or timeout period
+ * passed. See poll(2) and @link{android.system.Os.Poll}.
+ *
+ * @throws SocketException if poll(2) fails.
+ * @throws SocketTimeoutException if the event has not happened before timeout period has passed.
+ */
+ public static void poll(FileDescriptor fd, int events, int timeout)
+ throws SocketException, SocketTimeoutException {
+ StructPollfd[] pollFds = new StructPollfd[]{ new StructPollfd() };
+ pollFds[0].fd = fd;
+ pollFds[0].events = (short) events;
+
try {
- SocketAddress sa = Libcore.os.getsockname(fd);
- InetSocketAddress isa = (InetSocketAddress) sa;
- return isa.getAddress();
- } catch (ErrnoException errnoException) {
- throw errnoException.rethrowAsSocketException();
+ int ret = android.system.Os.poll(pollFds, timeout);
+ if (ret == 0) {
+ throw new SocketTimeoutException("Poll timed out");
+ }
+ } catch (ErrnoException e) {
+ e.rethrowAsSocketException();
}
}
- public static int getSocketLocalPort(FileDescriptor fd) throws SocketException {
+ public static InetSocketAddress getLocalInetSocketAddress(FileDescriptor fd) throws SocketException {
try {
- SocketAddress sa = Libcore.os.getsockname(fd);
- InetSocketAddress isa = (InetSocketAddress) sa;
- return isa.getPort();
+ return (InetSocketAddress) Libcore.os.getsockname(fd);
} catch (ErrnoException errnoException) {
throw errnoException.rethrowAsSocketException();
}
diff --git a/luni/src/main/java/libcore/io/IoTracker.java b/luni/src/main/java/libcore/io/IoTracker.java
new file mode 100644
index 000000000..4623b6a78
--- /dev/null
+++ b/luni/src/main/java/libcore/io/IoTracker.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package libcore.io;
+
+import dalvik.system.BlockGuard;
+
+/**
+ * Used to detect unbuffered I/O.
+ * @hide
+ */
+public final class IoTracker {
+ private int opCount;
+ private int totalByteCount;
+ private boolean isOpen = true;
+ private Mode mode = Mode.READ;
+
+ public void trackIo(int byteCount) {
+ ++opCount;
+ totalByteCount += byteCount;
+ if (isOpen && opCount > 10 && totalByteCount < 10*512) {
+ BlockGuard.getThreadPolicy().onUnbufferedIO();
+ isOpen = false;
+ }
+ }
+
+ public void trackIo(int byteCount, Mode mode) {
+ if (this.mode != mode) {
+ reset();
+ this.mode = mode;
+ }
+ trackIo(byteCount);
+ }
+
+ /**
+ * Resets the state of the IoTracker, except {@link #isOpen} as it is not required to notify
+ * again and again about the same stream.
+ * This is primarily used by RandomAccessFile to consider a case when {@link
+ * java.io.RandomAccessFile#seek seek} is called.
+ */
+ public void reset() {
+ opCount = 0;
+ totalByteCount = 0;
+ }
+
+ public enum Mode {
+ READ,
+ WRITE
+ }
+}
diff --git a/luni/src/main/java/libcore/io/Libcore.java b/luni/src/main/java/libcore/io/Libcore.java
index 5f57f91bb..cbc5a55fc 100644
--- a/luni/src/main/java/libcore/io/Libcore.java
+++ b/luni/src/main/java/libcore/io/Libcore.java
@@ -19,5 +19,15 @@
public final class Libcore {
private Libcore() { }
- public static Os os = new BlockGuardOs(new Posix());
+ /**
+ * Direct access to syscalls. Code should strongly prefer using {@link #os}
+ * unless it has a strong reason to bypass the helpful checks/guards that it
+ * provides.
+ */
+ public static Os rawOs = new Linux();
+
+ /**
+ * Access to syscalls with helpful checks/guards.
+ */
+ public static Os os = new BlockGuardOs(rawOs);
}
diff --git a/luni/src/main/java/libcore/io/Linux.java b/luni/src/main/java/libcore/io/Linux.java
new file mode 100644
index 000000000..09adb09c3
--- /dev/null
+++ b/luni/src/main/java/libcore/io/Linux.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.io;
+
+import android.system.ErrnoException;
+import android.system.GaiException;
+import android.system.StructAddrinfo;
+import android.system.StructCapUserData;
+import android.system.StructCapUserHeader;
+import android.system.StructFlock;
+import android.system.StructGroupReq;
+import android.system.StructGroupSourceReq;
+import android.system.StructIfaddrs;
+import android.system.StructLinger;
+import android.system.StructPasswd;
+import android.system.StructPollfd;
+import android.system.StructStat;
+import android.system.StructStatVfs;
+import android.system.StructTimeval;
+import android.system.StructUcred;
+import android.system.StructUtsname;
+import android.util.MutableInt;
+import android.util.MutableLong;
+import java.io.FileDescriptor;
+import java.io.InterruptedIOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.nio.NioUtils;
+
+public final class Linux implements Os {
+ Linux() { }
+
+ public native FileDescriptor accept(FileDescriptor fd, SocketAddress peerAddress) throws ErrnoException, SocketException;
+ public native boolean access(String path, int mode) throws ErrnoException;
+ public native InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException;
+ public native void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
+ public native void bind(FileDescriptor fd, SocketAddress address) throws ErrnoException, SocketException;
+ @Override
+ public native StructCapUserData[] capget(StructCapUserHeader hdr) throws ErrnoException;
+ @Override
+ public native void capset(StructCapUserHeader hdr, StructCapUserData[] data)
+ throws ErrnoException;
+ public native void chmod(String path, int mode) throws ErrnoException;
+ public native void chown(String path, int uid, int gid) throws ErrnoException;
+ public native void close(FileDescriptor fd) throws ErrnoException;
+ public native void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
+ public native void connect(FileDescriptor fd, SocketAddress address) throws ErrnoException, SocketException;
+ public native FileDescriptor dup(FileDescriptor oldFd) throws ErrnoException;
+ public native FileDescriptor dup2(FileDescriptor oldFd, int newFd) throws ErrnoException;
+ public native String[] environ();
+ public native void execv(String filename, String[] argv) throws ErrnoException;
+ public native void execve(String filename, String[] argv, String[] envp) throws ErrnoException;
+ public native void fchmod(FileDescriptor fd, int mode) throws ErrnoException;
+ public native void fchown(FileDescriptor fd, int uid, int gid) throws ErrnoException;
+ public native int fcntlFlock(FileDescriptor fd, int cmd, StructFlock arg) throws ErrnoException, InterruptedIOException;
+ public native int fcntlInt(FileDescriptor fd, int cmd, int arg) throws ErrnoException;
+ public native int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException;
+ public native void fdatasync(FileDescriptor fd) throws ErrnoException;
+ public native StructStat fstat(FileDescriptor fd) throws ErrnoException;
+ public native StructStatVfs fstatvfs(FileDescriptor fd) throws ErrnoException;
+ public native void fsync(FileDescriptor fd) throws ErrnoException;
+ public native void ftruncate(FileDescriptor fd, long length) throws ErrnoException;
+ public native String gai_strerror(int error);
+ public native int getegid();
+ public native int geteuid();
+ public native int getgid();
+ public native String getenv(String name);
+ public native String getnameinfo(InetAddress address, int flags) throws GaiException;
+ public native SocketAddress getpeername(FileDescriptor fd) throws ErrnoException;
+ public native int getpgid(int pid);
+ public native int getpid();
+ public native int getppid();
+ public native StructPasswd getpwnam(String name) throws ErrnoException;
+ public native StructPasswd getpwuid(int uid) throws ErrnoException;
+ public native SocketAddress getsockname(FileDescriptor fd) throws ErrnoException;
+ public native int getsockoptByte(FileDescriptor fd, int level, int option) throws ErrnoException;
+ public native InetAddress getsockoptInAddr(FileDescriptor fd, int level, int option) throws ErrnoException;
+ public native int getsockoptInt(FileDescriptor fd, int level, int option) throws ErrnoException;
+ public native StructLinger getsockoptLinger(FileDescriptor fd, int level, int option) throws ErrnoException;
+ public native StructTimeval getsockoptTimeval(FileDescriptor fd, int level, int option) throws ErrnoException;
+ public native StructUcred getsockoptUcred(FileDescriptor fd, int level, int option) throws ErrnoException;
+ public native int gettid();
+ public native int getuid();
+ public native byte[] getxattr(String path, String name) throws ErrnoException;
+ public native StructIfaddrs[] getifaddrs() throws ErrnoException;
+ public native String if_indextoname(int index);
+ public native int if_nametoindex(String name);
+ public native InetAddress inet_pton(int family, String address);
+ public native int ioctlFlags(FileDescriptor fd, String interfaceName) throws ErrnoException;
+ public native InetAddress ioctlInetAddress(FileDescriptor fd, int cmd, String interfaceName) throws ErrnoException;
+ public native int ioctlInt(FileDescriptor fd, int cmd, MutableInt arg) throws ErrnoException;
+ public native int ioctlMTU(FileDescriptor fd, String interfaceName) throws ErrnoException;
+ public native boolean isatty(FileDescriptor fd);
+ public native void kill(int pid, int signal) throws ErrnoException;
+ public native void lchown(String path, int uid, int gid) throws ErrnoException;
+ public native void link(String oldPath, String newPath) throws ErrnoException;
+ public native void listen(FileDescriptor fd, int backlog) throws ErrnoException;
+ public native String[] listxattr(String path) throws ErrnoException;
+ public native long lseek(FileDescriptor fd, long offset, int whence) throws ErrnoException;
+ public native StructStat lstat(String path) throws ErrnoException;
+ public native void mincore(long address, long byteCount, byte[] vector) throws ErrnoException;
+ public native void mkdir(String path, int mode) throws ErrnoException;
+ public native void mkfifo(String path, int mode) throws ErrnoException;
+ public native void mlock(long address, long byteCount) throws ErrnoException;
+ public native long mmap(long address, long byteCount, int prot, int flags, FileDescriptor fd, long offset) throws ErrnoException;
+ public native void msync(long address, long byteCount, int flags) throws ErrnoException;
+ public native void munlock(long address, long byteCount) throws ErrnoException;
+ public native void munmap(long address, long byteCount) throws ErrnoException;
+ public native FileDescriptor open(String path, int flags, int mode) throws ErrnoException;
+ public native FileDescriptor[] pipe2(int flags) throws ErrnoException;
+ public native int poll(StructPollfd[] fds, int timeoutMs) throws ErrnoException;
+ public native void posix_fallocate(FileDescriptor fd, long offset, long length) throws ErrnoException;
+ public native int prctl(int option, long arg2, long arg3, long arg4, long arg5) throws ErrnoException;
+ public int pread(FileDescriptor fd, ByteBuffer buffer, long offset) throws ErrnoException, InterruptedIOException {
+ final int bytesRead;
+ final int position = buffer.position();
+
+ if (buffer.isDirect()) {
+ bytesRead = preadBytes(fd, buffer, position, buffer.remaining(), offset);
+ } else {
+ bytesRead = preadBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + position, buffer.remaining(), offset);
+ }
+
+ maybeUpdateBufferPosition(buffer, position, bytesRead);
+ return bytesRead;
+ }
+ public int pread(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, long offset) throws ErrnoException, InterruptedIOException {
+ // This indirection isn't strictly necessary, but ensures that our public interface is type safe.
+ return preadBytes(fd, bytes, byteOffset, byteCount, offset);
+ }
+ private native int preadBytes(FileDescriptor fd, Object buffer, int bufferOffset, int byteCount, long offset) throws ErrnoException, InterruptedIOException;
+ public int pwrite(FileDescriptor fd, ByteBuffer buffer, long offset) throws ErrnoException, InterruptedIOException {
+ final int bytesWritten;
+ final int position = buffer.position();
+
+ if (buffer.isDirect()) {
+ bytesWritten = pwriteBytes(fd, buffer, position, buffer.remaining(), offset);
+ } else {
+ bytesWritten = pwriteBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + position, buffer.remaining(), offset);
+ }
+
+ maybeUpdateBufferPosition(buffer, position, bytesWritten);
+ return bytesWritten;
+ }
+ public int pwrite(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, long offset) throws ErrnoException, InterruptedIOException {
+ // This indirection isn't strictly necessary, but ensures that our public interface is type safe.
+ return pwriteBytes(fd, bytes, byteOffset, byteCount, offset);
+ }
+ private native int pwriteBytes(FileDescriptor fd, Object buffer, int bufferOffset, int byteCount, long offset) throws ErrnoException, InterruptedIOException;
+ public int read(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException, InterruptedIOException {
+ final int bytesRead;
+ final int position = buffer.position();
+
+ if (buffer.isDirect()) {
+ bytesRead = readBytes(fd, buffer, position, buffer.remaining());
+ } else {
+ bytesRead = readBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + position, buffer.remaining());
+ }
+
+ maybeUpdateBufferPosition(buffer, position, bytesRead);
+ return bytesRead;
+ }
+ public int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException, InterruptedIOException {
+ // This indirection isn't strictly necessary, but ensures that our public interface is type safe.
+ return readBytes(fd, bytes, byteOffset, byteCount);
+ }
+ private native int readBytes(FileDescriptor fd, Object buffer, int offset, int byteCount) throws ErrnoException, InterruptedIOException;
+ public native String readlink(String path) throws ErrnoException;
+ public native String realpath(String path) throws ErrnoException;
+ public native int readv(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException, InterruptedIOException;
+ public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException {
+ final int bytesReceived;
+ final int position = buffer.position();
+
+ if (buffer.isDirect()) {
+ bytesReceived = recvfromBytes(fd, buffer, position, buffer.remaining(), flags, srcAddress);
+ } else {
+ bytesReceived = recvfromBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + position, buffer.remaining(), flags, srcAddress);
+ }
+
+ maybeUpdateBufferPosition(buffer, position, bytesReceived);
+ return bytesReceived;
+ }
+ public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException {
+ // This indirection isn't strictly necessary, but ensures that our public interface is type safe.
+ return recvfromBytes(fd, bytes, byteOffset, byteCount, flags, srcAddress);
+ }
+ private native int recvfromBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException;
+ public native void remove(String path) throws ErrnoException;
+ public native void removexattr(String path, String name) throws ErrnoException;
+ public native void rename(String oldPath, String newPath) throws ErrnoException;
+ public native long sendfile(FileDescriptor outFd, FileDescriptor inFd, MutableLong inOffset, long byteCount) throws ErrnoException;
+ public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException {
+ final int bytesSent;
+ final int position = buffer.position();
+
+ if (buffer.isDirect()) {
+ bytesSent = sendtoBytes(fd, buffer, position, buffer.remaining(), flags, inetAddress, port);
+ } else {
+ bytesSent = sendtoBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + position, buffer.remaining(), flags, inetAddress, port);
+ }
+
+ maybeUpdateBufferPosition(buffer, position, bytesSent);
+ return bytesSent;
+ }
+ public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException {
+ // This indirection isn't strictly necessary, but ensures that our public interface is type safe.
+ return sendtoBytes(fd, bytes, byteOffset, byteCount, flags, inetAddress, port);
+ }
+ public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, SocketAddress address) throws ErrnoException, SocketException {
+ return sendtoBytes(fd, bytes, byteOffset, byteCount, flags, address);
+ }
+ private native int sendtoBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException;
+ private native int sendtoBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, SocketAddress address) throws ErrnoException, SocketException;
+ public native void setegid(int egid) throws ErrnoException;
+ public native void setenv(String name, String value, boolean overwrite) throws ErrnoException;
+ public native void seteuid(int euid) throws ErrnoException;
+ public native void setgid(int gid) throws ErrnoException;
+ public native void setpgid(int pid, int pgid) throws ErrnoException;
+ public native void setregid(int rgid, int egid) throws ErrnoException;
+ public native void setreuid(int ruid, int euid) throws ErrnoException;
+ public native int setsid() throws ErrnoException;
+ public native void setsockoptByte(FileDescriptor fd, int level, int option, int value) throws ErrnoException;
+ public native void setsockoptIfreq(FileDescriptor fd, int level, int option, String value) throws ErrnoException;
+ public native void setsockoptInt(FileDescriptor fd, int level, int option, int value) throws ErrnoException;
+ public native void setsockoptIpMreqn(FileDescriptor fd, int level, int option, int value) throws ErrnoException;
+ public native void setsockoptGroupReq(FileDescriptor fd, int level, int option, StructGroupReq value) throws ErrnoException;
+ public native void setsockoptGroupSourceReq(FileDescriptor fd, int level, int option, StructGroupSourceReq value) throws ErrnoException;
+ public native void setsockoptLinger(FileDescriptor fd, int level, int option, StructLinger value) throws ErrnoException;
+ public native void setsockoptTimeval(FileDescriptor fd, int level, int option, StructTimeval value) throws ErrnoException;
+ public native void setuid(int uid) throws ErrnoException;
+ public native void setxattr(String path, String name, byte[] value, int flags) throws ErrnoException;
+ public native void shutdown(FileDescriptor fd, int how) throws ErrnoException;
+ public native FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException;
+ public native void socketpair(int domain, int type, int protocol, FileDescriptor fd1, FileDescriptor fd2) throws ErrnoException;
+ public native StructStat stat(String path) throws ErrnoException;
+ public native StructStatVfs statvfs(String path) throws ErrnoException;
+ public native String strerror(int errno);
+ public native String strsignal(int signal);
+ public native void symlink(String oldPath, String newPath) throws ErrnoException;
+ public native long sysconf(int name);
+ public native void tcdrain(FileDescriptor fd) throws ErrnoException;
+ public native void tcsendbreak(FileDescriptor fd, int duration) throws ErrnoException;
+ public int umask(int mask) {
+ if ((mask & 0777) != mask) {
+ throw new IllegalArgumentException("Invalid umask: " + mask);
+ }
+ return umaskImpl(mask);
+ }
+ private native int umaskImpl(int mask);
+ public native StructUtsname uname();
+ public native void unlink(String pathname) throws ErrnoException;
+ public native void unsetenv(String name) throws ErrnoException;
+ public native int waitpid(int pid, MutableInt status, int options) throws ErrnoException;
+ public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException, InterruptedIOException {
+ final int bytesWritten;
+ final int position = buffer.position();
+ if (buffer.isDirect()) {
+ bytesWritten = writeBytes(fd, buffer, position, buffer.remaining());
+ } else {
+ bytesWritten = writeBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + position, buffer.remaining());
+ }
+
+ maybeUpdateBufferPosition(buffer, position, bytesWritten);
+ return bytesWritten;
+ }
+ public int write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException, InterruptedIOException {
+ // This indirection isn't strictly necessary, but ensures that our public interface is type safe.
+ return writeBytes(fd, bytes, byteOffset, byteCount);
+ }
+ private native int writeBytes(FileDescriptor fd, Object buffer, int offset, int byteCount) throws ErrnoException, InterruptedIOException;
+ public native int writev(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException, InterruptedIOException;
+
+ private static void maybeUpdateBufferPosition(ByteBuffer buffer, int originalPosition, int bytesReadOrWritten) {
+ if (bytesReadOrWritten > 0) {
+ buffer.position(bytesReadOrWritten + originalPosition);
+ }
+ }
+}
diff --git a/luni/src/main/java/libcore/io/Memory.java b/luni/src/main/java/libcore/io/Memory.java
index e1484575e..ba7398d77 100644
--- a/luni/src/main/java/libcore/io/Memory.java
+++ b/luni/src/main/java/libcore/io/Memory.java
@@ -17,6 +17,7 @@
package libcore.io;
+import dalvik.annotation.optimization.FastNative;
import java.io.FileDescriptor;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -150,6 +151,7 @@ public static void pokeShort(byte[] dst, int offset, short value, ByteOrder orde
*/
public static native void memmove(Object dstObject, int dstOffset, Object srcObject, int srcOffset, long byteCount);
+ @FastNative
public static native byte peekByte(long address);
public static int peekInt(long address, boolean swap) {
@@ -159,6 +161,7 @@ public static int peekInt(long address, boolean swap) {
}
return result;
}
+ @FastNative
private static native int peekIntNative(long address);
public static long peekLong(long address, boolean swap) {
@@ -168,6 +171,7 @@ public static long peekLong(long address, boolean swap) {
}
return result;
}
+ @FastNative
private static native long peekLongNative(long address);
public static short peekShort(long address, boolean swap) {
@@ -177,6 +181,7 @@ public static short peekShort(long address, boolean swap) {
}
return result;
}
+ @FastNative
private static native short peekShortNative(long address);
public static native void peekByteArray(long address, byte[] dst, int dstOffset, int byteCount);
@@ -187,6 +192,7 @@ public static short peekShort(long address, boolean swap) {
public static native void peekLongArray(long address, long[] dst, int dstOffset, int longCount, boolean swap);
public static native void peekShortArray(long address, short[] dst, int dstOffset, int shortCount, boolean swap);
+ @FastNative
public static native void pokeByte(long address, byte value);
public static void pokeInt(long address, int value, boolean swap) {
@@ -195,6 +201,7 @@ public static void pokeInt(long address, int value, boolean swap) {
}
pokeIntNative(address, value);
}
+ @FastNative
private static native void pokeIntNative(long address, int value);
public static void pokeLong(long address, long value, boolean swap) {
@@ -203,6 +210,7 @@ public static void pokeLong(long address, long value, boolean swap) {
}
pokeLongNative(address, value);
}
+ @FastNative
private static native void pokeLongNative(long address, long value);
public static void pokeShort(long address, short value, boolean swap) {
@@ -211,6 +219,7 @@ public static void pokeShort(long address, short value, boolean swap) {
}
pokeShortNative(address, value);
}
+ @FastNative
private static native void pokeShortNative(long address, short value);
public static native void pokeByteArray(long address, byte[] src, int offset, int count);
diff --git a/luni/src/main/java/libcore/io/MemoryMappedFile.java b/luni/src/main/java/libcore/io/MemoryMappedFile.java
index b4cd8fc50..4c736833a 100644
--- a/luni/src/main/java/libcore/io/MemoryMappedFile.java
+++ b/luni/src/main/java/libcore/io/MemoryMappedFile.java
@@ -28,20 +28,23 @@
import static android.system.OsConstants.*;
/**
- * A memory-mapped file. Use {@link #mmap} to map a file, {@link #close} to unmap a file,
+ * A memory-mapped file. Use {@link #mmapRO} to map a file, {@link #close} to unmap a file,
* and either {@link #bigEndianIterator} or {@link #littleEndianIterator} to get a seekable
- * {@link BufferIterator} over the mapped data.
+ * {@link BufferIterator} over the mapped data. This class is not thread safe.
*/
public final class MemoryMappedFile implements AutoCloseable {
- private long address;
- private final long size;
+ private boolean closed;
+ private final long address;
+ private final int size;
- /**
- * Use this if you've called {@code mmap} yourself.
- */
+ /** Public for layoutlib only. */
public MemoryMappedFile(long address, long size) {
this.address = address;
- this.size = size;
+ // For simplicity when bounds checking, only sizes up to Integer.MAX_VALUE are supported.
+ if (size < 0 || size > Integer.MAX_VALUE) {
+ throw new IllegalArgumentException("Unsupported file size=" + size);
+ }
+ this.size = (int) size;
}
/**
@@ -49,10 +52,13 @@ public MemoryMappedFile(long address, long size) {
*/
public static MemoryMappedFile mmapRO(String path) throws ErrnoException {
FileDescriptor fd = Libcore.os.open(path, O_RDONLY, 0);
- long size = Libcore.os.fstat(fd).st_size;
- long address = Libcore.os.mmap(0L, size, PROT_READ, MAP_SHARED, fd, 0);
- Libcore.os.close(fd);
- return new MemoryMappedFile(address, size);
+ try {
+ long size = Libcore.os.fstat(fd).st_size;
+ long address = Libcore.os.mmap(0L, size, PROT_READ, MAP_SHARED, fd, 0);
+ return new MemoryMappedFile(address, size);
+ } finally {
+ Libcore.os.close(fd);
+ }
}
/**
@@ -63,31 +69,45 @@ public static MemoryMappedFile mmapRO(String path) throws ErrnoException {
* Calling this method invalidates any iterators over this {@code MemoryMappedFile}. It is an
* error to use such an iterator after calling {@code close}.
*/
- public synchronized void close() throws ErrnoException {
- if (address != 0) {
+ public void close() throws ErrnoException {
+ if (!closed) {
+ closed = true;
Libcore.os.munmap(address, size);
- address = 0;
}
}
+ public boolean isClosed() {
+ return closed;
+ }
+
/**
* Returns a new iterator that treats the mapped data as big-endian.
*/
public BufferIterator bigEndianIterator() {
- return new NioBufferIterator(address, (int) size, ByteOrder.nativeOrder() != ByteOrder.BIG_ENDIAN);
+ return new NioBufferIterator(
+ this, address, size, ByteOrder.nativeOrder() != ByteOrder.BIG_ENDIAN);
}
/**
* Returns a new iterator that treats the mapped data as little-endian.
*/
public BufferIterator littleEndianIterator() {
- return new NioBufferIterator(address, (int) size, ByteOrder.nativeOrder() != ByteOrder.LITTLE_ENDIAN);
+ return new NioBufferIterator(
+ this, this.address, this.size, ByteOrder.nativeOrder() != ByteOrder.LITTLE_ENDIAN);
+ }
+
+ /** Throws {@link IllegalStateException} if the file is closed. */
+ void checkNotClosed() {
+ if (closed) {
+ throw new IllegalStateException("MemoryMappedFile is closed");
+ }
}
/**
* Returns the size in bytes of the memory-mapped region.
*/
- public long size() {
+ public int size() {
+ checkNotClosed();
return size;
}
}
diff --git a/luni/src/main/java/libcore/io/NioBufferIterator.java b/luni/src/main/java/libcore/io/NioBufferIterator.java
index 3dd05a5a5..0f3f920cb 100644
--- a/luni/src/main/java/libcore/io/NioBufferIterator.java
+++ b/luni/src/main/java/libcore/io/NioBufferIterator.java
@@ -16,24 +16,37 @@
package libcore.io;
-import libcore.io.Memory;
-
/**
* Iterates over big- or little-endian bytes on the native heap.
* See {@link MemoryMappedFile#bigEndianIterator} and {@link MemoryMappedFile#littleEndianIterator}.
*
- * @hide don't make this public without adding bounds checking.
+ * @hide
*/
public final class NioBufferIterator extends BufferIterator {
+
+ private final MemoryMappedFile file;
private final long address;
- private final int size;
+ private final int length;
private final boolean swap;
private int position;
- NioBufferIterator(long address, int size, boolean swap) {
+ NioBufferIterator(MemoryMappedFile file, long address, int length, boolean swap) {
+ file.checkNotClosed();
+
+ this.file = file;
this.address = address;
- this.size = size;
+
+ if (length < 0) {
+ throw new IllegalArgumentException("length < 0");
+ }
+ final long MAX_VALID_ADDRESS = -1;
+ if (Long.compareUnsigned(address, MAX_VALID_ADDRESS - length) > 0) {
+ throw new IllegalArgumentException(
+ "length " + length + " would overflow 64-bit address space");
+ }
+ this.length = length;
+
this.swap = swap;
}
@@ -45,31 +58,78 @@ public void skip(int byteCount) {
position += byteCount;
}
+ @Override
+ public int pos() {
+ return position;
+ }
+
public void readByteArray(byte[] dst, int dstOffset, int byteCount) {
+ checkDstBounds(dstOffset, dst.length, byteCount);
+ file.checkNotClosed();
+ checkReadBounds(position, length, byteCount);
Memory.peekByteArray(address + position, dst, dstOffset, byteCount);
position += byteCount;
}
public byte readByte() {
+ file.checkNotClosed();
+ checkReadBounds(position, length, 1);
byte result = Memory.peekByte(address + position);
++position;
return result;
}
public int readInt() {
+ file.checkNotClosed();
+ checkReadBounds(position, length, SizeOf.INT);
int result = Memory.peekInt(address + position, swap);
position += SizeOf.INT;
return result;
}
public void readIntArray(int[] dst, int dstOffset, int intCount) {
+ checkDstBounds(dstOffset, dst.length, intCount);
+ file.checkNotClosed();
+ final int byteCount = SizeOf.INT * intCount;
+ checkReadBounds(position, length, byteCount);
Memory.peekIntArray(address + position, dst, dstOffset, intCount, swap);
- position += SizeOf.INT * intCount;
+ position += byteCount;
}
public short readShort() {
+ file.checkNotClosed();
+ checkReadBounds(position, length, SizeOf.SHORT);
short result = Memory.peekShort(address + position, swap);
position += SizeOf.SHORT;
return result;
}
+
+ private static void checkReadBounds(int position, int length, int byteCount) {
+ if (position < 0 || byteCount < 0) {
+ throw new IndexOutOfBoundsException(
+ "Invalid read args: position=" + position + ", byteCount=" + byteCount);
+ }
+ // Use of int here relies on length being an int <= Integer.MAX_VALUE.
+ final int finalReadPos = position + byteCount;
+ if (finalReadPos < 0 || finalReadPos > length) {
+ throw new IndexOutOfBoundsException(
+ "Read outside range: position=" + position + ", byteCount=" + byteCount
+ + ", length=" + length);
+ }
+ }
+
+ private static void checkDstBounds(int dstOffset, int dstLength, int count) {
+ if (dstOffset < 0 || count < 0) {
+ throw new IndexOutOfBoundsException(
+ "Invalid dst args: offset=" + dstLength + ", count=" + count);
+ }
+ // Use of int here relies on dstLength being an int <= Integer.MAX_VALUE, which it has to
+ // be because it's an array length.
+ final int targetPos = dstOffset + count;
+ if (targetPos < 0 || targetPos > dstLength) {
+ throw new IndexOutOfBoundsException(
+ "Write outside range: dst.length=" + dstLength + ", offset="
+ + dstOffset + ", count=" + count);
+ }
+ }
}
diff --git a/luni/src/main/java/libcore/io/Os.java b/luni/src/main/java/libcore/io/Os.java
index 006a29eb7..20a84bd2a 100644
--- a/luni/src/main/java/libcore/io/Os.java
+++ b/luni/src/main/java/libcore/io/Os.java
@@ -19,9 +19,12 @@
import android.system.ErrnoException;
import android.system.GaiException;
import android.system.StructAddrinfo;
+import android.system.StructCapUserData;
+import android.system.StructCapUserHeader;
import android.system.StructFlock;
import android.system.StructGroupReq;
import android.system.StructGroupSourceReq;
+import android.system.StructIfaddrs;
import android.system.StructLinger;
import android.system.StructPasswd;
import android.system.StructPollfd;
@@ -46,6 +49,8 @@ public interface Os {
public InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException;
public void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
public void bind(FileDescriptor fd, SocketAddress address) throws ErrnoException, SocketException;
+ public StructCapUserData[] capget(StructCapUserHeader hdr) throws ErrnoException;
+ public void capset(StructCapUserHeader hdr, StructCapUserData[] data) throws ErrnoException;
public void chmod(String path, int mode) throws ErrnoException;
public void chown(String path, int uid, int gid) throws ErrnoException;
public void close(FileDescriptor fd) throws ErrnoException;
@@ -88,16 +93,21 @@ public interface Os {
public StructUcred getsockoptUcred(FileDescriptor fd, int level, int option) throws ErrnoException;
public int gettid();
public int getuid();
- public int getxattr(String path, String name, byte[] outValue) throws ErrnoException;
+ public byte[] getxattr(String path, String name) throws ErrnoException;
+ public StructIfaddrs[] getifaddrs() throws ErrnoException;
public String if_indextoname(int index);
+ public int if_nametoindex(String name);
public InetAddress inet_pton(int family, String address);
+ public int ioctlFlags(FileDescriptor fd, String interfaceName) throws ErrnoException;
public InetAddress ioctlInetAddress(FileDescriptor fd, int cmd, String interfaceName) throws ErrnoException;
public int ioctlInt(FileDescriptor fd, int cmd, MutableInt arg) throws ErrnoException;
+ public int ioctlMTU(FileDescriptor fd, String interfaceName) throws ErrnoException;
public boolean isatty(FileDescriptor fd);
public void kill(int pid, int signal) throws ErrnoException;
public void lchown(String path, int uid, int gid) throws ErrnoException;
public void link(String oldPath, String newPath) throws ErrnoException;
public void listen(FileDescriptor fd, int backlog) throws ErrnoException;
+ public String[] listxattr(String path) throws ErrnoException;
public long lseek(FileDescriptor fd, long offset, int whence) throws ErrnoException;
public StructStat lstat(String path) throws ErrnoException;
public void mincore(long address, long byteCount, byte[] vector) throws ErrnoException;
diff --git a/luni/src/main/java/libcore/io/Posix.java b/luni/src/main/java/libcore/io/Posix.java
deleted file mode 100644
index a341641a5..000000000
--- a/luni/src/main/java/libcore/io/Posix.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package libcore.io;
-
-import android.system.ErrnoException;
-import android.system.GaiException;
-import android.system.StructAddrinfo;
-import android.system.StructFlock;
-import android.system.StructGroupReq;
-import android.system.StructGroupSourceReq;
-import android.system.StructLinger;
-import android.system.StructPasswd;
-import android.system.StructPollfd;
-import android.system.StructStat;
-import android.system.StructStatVfs;
-import android.system.StructTimeval;
-import android.system.StructUcred;
-import android.system.StructUtsname;
-import android.util.MutableInt;
-import android.util.MutableLong;
-import java.io.FileDescriptor;
-import java.io.InterruptedIOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.net.SocketException;
-import java.nio.ByteBuffer;
-import java.nio.NioUtils;
-
-public final class Posix implements Os {
- Posix() { }
-
- public native FileDescriptor accept(FileDescriptor fd, SocketAddress peerAddress) throws ErrnoException, SocketException;
- public native boolean access(String path, int mode) throws ErrnoException;
- public native InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException;
- public native void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
- public native void bind(FileDescriptor fd, SocketAddress address) throws ErrnoException, SocketException;
- public native void chmod(String path, int mode) throws ErrnoException;
- public native void chown(String path, int uid, int gid) throws ErrnoException;
- public native void close(FileDescriptor fd) throws ErrnoException;
- public native void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
- public native void connect(FileDescriptor fd, SocketAddress address) throws ErrnoException, SocketException;
- public native FileDescriptor dup(FileDescriptor oldFd) throws ErrnoException;
- public native FileDescriptor dup2(FileDescriptor oldFd, int newFd) throws ErrnoException;
- public native String[] environ();
- public native void execv(String filename, String[] argv) throws ErrnoException;
- public native void execve(String filename, String[] argv, String[] envp) throws ErrnoException;
- public native void fchmod(FileDescriptor fd, int mode) throws ErrnoException;
- public native void fchown(FileDescriptor fd, int uid, int gid) throws ErrnoException;
- public native int fcntlFlock(FileDescriptor fd, int cmd, StructFlock arg) throws ErrnoException, InterruptedIOException;
- public native int fcntlInt(FileDescriptor fd, int cmd, int arg) throws ErrnoException;
- public native int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException;
- public native void fdatasync(FileDescriptor fd) throws ErrnoException;
- public native StructStat fstat(FileDescriptor fd) throws ErrnoException;
- public native StructStatVfs fstatvfs(FileDescriptor fd) throws ErrnoException;
- public native void fsync(FileDescriptor fd) throws ErrnoException;
- public native void ftruncate(FileDescriptor fd, long length) throws ErrnoException;
- public native String gai_strerror(int error);
- public native int getegid();
- public native int geteuid();
- public native int getgid();
- public native String getenv(String name);
- public native String getnameinfo(InetAddress address, int flags) throws GaiException;
- public native SocketAddress getpeername(FileDescriptor fd) throws ErrnoException;
- public native int getpgid(int pid);
- public native int getpid();
- public native int getppid();
- public native StructPasswd getpwnam(String name) throws ErrnoException;
- public native StructPasswd getpwuid(int uid) throws ErrnoException;
- public native SocketAddress getsockname(FileDescriptor fd) throws ErrnoException;
- public native int getsockoptByte(FileDescriptor fd, int level, int option) throws ErrnoException;
- public native InetAddress getsockoptInAddr(FileDescriptor fd, int level, int option) throws ErrnoException;
- public native int getsockoptInt(FileDescriptor fd, int level, int option) throws ErrnoException;
- public native StructLinger getsockoptLinger(FileDescriptor fd, int level, int option) throws ErrnoException;
- public native StructTimeval getsockoptTimeval(FileDescriptor fd, int level, int option) throws ErrnoException;
- public native StructUcred getsockoptUcred(FileDescriptor fd, int level, int option) throws ErrnoException;
- public native int gettid();
- public native int getuid();
- public native int getxattr(String path, String name, byte[] outValue) throws ErrnoException;
- public native String if_indextoname(int index);
- public native InetAddress inet_pton(int family, String address);
- public native InetAddress ioctlInetAddress(FileDescriptor fd, int cmd, String interfaceName) throws ErrnoException;
- public native int ioctlInt(FileDescriptor fd, int cmd, MutableInt arg) throws ErrnoException;
- public native boolean isatty(FileDescriptor fd);
- public native void kill(int pid, int signal) throws ErrnoException;
- public native void lchown(String path, int uid, int gid) throws ErrnoException;
- public native void link(String oldPath, String newPath) throws ErrnoException;
- public native void listen(FileDescriptor fd, int backlog) throws ErrnoException;
- public native long lseek(FileDescriptor fd, long offset, int whence) throws ErrnoException;
- public native StructStat lstat(String path) throws ErrnoException;
- public native void mincore(long address, long byteCount, byte[] vector) throws ErrnoException;
- public native void mkdir(String path, int mode) throws ErrnoException;
- public native void mkfifo(String path, int mode) throws ErrnoException;
- public native void mlock(long address, long byteCount) throws ErrnoException;
- public native long mmap(long address, long byteCount, int prot, int flags, FileDescriptor fd, long offset) throws ErrnoException;
- public native void msync(long address, long byteCount, int flags) throws ErrnoException;
- public native void munlock(long address, long byteCount) throws ErrnoException;
- public native void munmap(long address, long byteCount) throws ErrnoException;
- public native FileDescriptor open(String path, int flags, int mode) throws ErrnoException;
- public native FileDescriptor[] pipe2(int flags) throws ErrnoException;
- public native int poll(StructPollfd[] fds, int timeoutMs) throws ErrnoException;
- public native void posix_fallocate(FileDescriptor fd, long offset, long length) throws ErrnoException;
- public native int prctl(int option, long arg2, long arg3, long arg4, long arg5) throws ErrnoException;
- public int pread(FileDescriptor fd, ByteBuffer buffer, long offset) throws ErrnoException, InterruptedIOException {
- final int bytesRead;
- final int position = buffer.position();
-
- if (buffer.isDirect()) {
- bytesRead = preadBytes(fd, buffer, position, buffer.remaining(), offset);
- } else {
- bytesRead = preadBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + position, buffer.remaining(), offset);
- }
-
- maybeUpdateBufferPosition(buffer, position, bytesRead);
- return bytesRead;
- }
- public int pread(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, long offset) throws ErrnoException, InterruptedIOException {
- // This indirection isn't strictly necessary, but ensures that our public interface is type safe.
- return preadBytes(fd, bytes, byteOffset, byteCount, offset);
- }
- private native int preadBytes(FileDescriptor fd, Object buffer, int bufferOffset, int byteCount, long offset) throws ErrnoException, InterruptedIOException;
- public int pwrite(FileDescriptor fd, ByteBuffer buffer, long offset) throws ErrnoException, InterruptedIOException {
- final int bytesWritten;
- final int position = buffer.position();
-
- if (buffer.isDirect()) {
- bytesWritten = pwriteBytes(fd, buffer, position, buffer.remaining(), offset);
- } else {
- bytesWritten = pwriteBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + position, buffer.remaining(), offset);
- }
-
- maybeUpdateBufferPosition(buffer, position, bytesWritten);
- return bytesWritten;
- }
- public int pwrite(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, long offset) throws ErrnoException, InterruptedIOException {
- // This indirection isn't strictly necessary, but ensures that our public interface is type safe.
- return pwriteBytes(fd, bytes, byteOffset, byteCount, offset);
- }
- private native int pwriteBytes(FileDescriptor fd, Object buffer, int bufferOffset, int byteCount, long offset) throws ErrnoException, InterruptedIOException;
- public int read(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException, InterruptedIOException {
- final int bytesRead;
- final int position = buffer.position();
-
- if (buffer.isDirect()) {
- bytesRead = readBytes(fd, buffer, position, buffer.remaining());
- } else {
- bytesRead = readBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + position, buffer.remaining());
- }
-
- maybeUpdateBufferPosition(buffer, position, bytesRead);
- return bytesRead;
- }
- public int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException, InterruptedIOException {
- // This indirection isn't strictly necessary, but ensures that our public interface is type safe.
- return readBytes(fd, bytes, byteOffset, byteCount);
- }
- private native int readBytes(FileDescriptor fd, Object buffer, int offset, int byteCount) throws ErrnoException, InterruptedIOException;
- public native String readlink(String path) throws ErrnoException;
- public native String realpath(String path) throws ErrnoException;
- public native int readv(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException, InterruptedIOException;
- public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException {
- final int bytesReceived;
- final int position = buffer.position();
-
- if (buffer.isDirect()) {
- bytesReceived = recvfromBytes(fd, buffer, position, buffer.remaining(), flags, srcAddress);
- } else {
- bytesReceived = recvfromBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + position, buffer.remaining(), flags, srcAddress);
- }
-
- maybeUpdateBufferPosition(buffer, position, bytesReceived);
- return bytesReceived;
- }
- public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException {
- // This indirection isn't strictly necessary, but ensures that our public interface is type safe.
- return recvfromBytes(fd, bytes, byteOffset, byteCount, flags, srcAddress);
- }
- private native int recvfromBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException;
- public native void remove(String path) throws ErrnoException;
- public native void removexattr(String path, String name) throws ErrnoException;
- public native void rename(String oldPath, String newPath) throws ErrnoException;
- public native long sendfile(FileDescriptor outFd, FileDescriptor inFd, MutableLong inOffset, long byteCount) throws ErrnoException;
- public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException {
- final int bytesSent;
- final int position = buffer.position();
-
- if (buffer.isDirect()) {
- bytesSent = sendtoBytes(fd, buffer, position, buffer.remaining(), flags, inetAddress, port);
- } else {
- bytesSent = sendtoBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + position, buffer.remaining(), flags, inetAddress, port);
- }
-
- maybeUpdateBufferPosition(buffer, position, bytesSent);
- return bytesSent;
- }
- public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException {
- // This indirection isn't strictly necessary, but ensures that our public interface is type safe.
- return sendtoBytes(fd, bytes, byteOffset, byteCount, flags, inetAddress, port);
- }
- public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, SocketAddress address) throws ErrnoException, SocketException {
- return sendtoBytes(fd, bytes, byteOffset, byteCount, flags, address);
- }
- private native int sendtoBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException;
- private native int sendtoBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, SocketAddress address) throws ErrnoException, SocketException;
- public native void setegid(int egid) throws ErrnoException;
- public native void setenv(String name, String value, boolean overwrite) throws ErrnoException;
- public native void seteuid(int euid) throws ErrnoException;
- public native void setgid(int gid) throws ErrnoException;
- public native void setpgid(int pid, int pgid) throws ErrnoException;
- public native void setregid(int rgid, int egid) throws ErrnoException;
- public native void setreuid(int ruid, int euid) throws ErrnoException;
- public native int setsid() throws ErrnoException;
- public native void setsockoptByte(FileDescriptor fd, int level, int option, int value) throws ErrnoException;
- public native void setsockoptIfreq(FileDescriptor fd, int level, int option, String value) throws ErrnoException;
- public native void setsockoptInt(FileDescriptor fd, int level, int option, int value) throws ErrnoException;
- public native void setsockoptIpMreqn(FileDescriptor fd, int level, int option, int value) throws ErrnoException;
- public native void setsockoptGroupReq(FileDescriptor fd, int level, int option, StructGroupReq value) throws ErrnoException;
- public native void setsockoptGroupSourceReq(FileDescriptor fd, int level, int option, StructGroupSourceReq value) throws ErrnoException;
- public native void setsockoptLinger(FileDescriptor fd, int level, int option, StructLinger value) throws ErrnoException;
- public native void setsockoptTimeval(FileDescriptor fd, int level, int option, StructTimeval value) throws ErrnoException;
- public native void setuid(int uid) throws ErrnoException;
- public native void setxattr(String path, String name, byte[] value, int flags) throws ErrnoException;
- public native void shutdown(FileDescriptor fd, int how) throws ErrnoException;
- public native FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException;
- public native void socketpair(int domain, int type, int protocol, FileDescriptor fd1, FileDescriptor fd2) throws ErrnoException;
- public native StructStat stat(String path) throws ErrnoException;
- public native StructStatVfs statvfs(String path) throws ErrnoException;
- public native String strerror(int errno);
- public native String strsignal(int signal);
- public native void symlink(String oldPath, String newPath) throws ErrnoException;
- public native long sysconf(int name);
- public native void tcdrain(FileDescriptor fd) throws ErrnoException;
- public native void tcsendbreak(FileDescriptor fd, int duration) throws ErrnoException;
- public int umask(int mask) {
- if ((mask & 0777) != mask) {
- throw new IllegalArgumentException("Invalid umask: " + mask);
- }
- return umaskImpl(mask);
- }
- private native int umaskImpl(int mask);
- public native StructUtsname uname();
- public native void unlink(String pathname) throws ErrnoException;
- public native void unsetenv(String name) throws ErrnoException;
- public native int waitpid(int pid, MutableInt status, int options) throws ErrnoException;
- public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException, InterruptedIOException {
- final int bytesWritten;
- final int position = buffer.position();
- if (buffer.isDirect()) {
- bytesWritten = writeBytes(fd, buffer, position, buffer.remaining());
- } else {
- bytesWritten = writeBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + position, buffer.remaining());
- }
-
- maybeUpdateBufferPosition(buffer, position, bytesWritten);
- return bytesWritten;
- }
- public int write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException, InterruptedIOException {
- // This indirection isn't strictly necessary, but ensures that our public interface is type safe.
- return writeBytes(fd, bytes, byteOffset, byteCount);
- }
- private native int writeBytes(FileDescriptor fd, Object buffer, int offset, int byteCount) throws ErrnoException, InterruptedIOException;
- public native int writev(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException, InterruptedIOException;
-
- private static void maybeUpdateBufferPosition(ByteBuffer buffer, int originalPosition, int bytesReadOrWritten) {
- if (bytesReadOrWritten > 0) {
- buffer.position(bytesReadOrWritten + originalPosition);
- }
- }
-}
diff --git a/luni/src/main/java/libcore/net/MimeUtils.java b/luni/src/main/java/libcore/net/MimeUtils.java
index 3b59b87dc..b746273d4 100644
--- a/luni/src/main/java/libcore/net/MimeUtils.java
+++ b/luni/src/main/java/libcore/net/MimeUtils.java
@@ -17,6 +17,7 @@
package libcore.net;
import java.util.HashMap;
+import java.util.Locale;
import java.util.Map;
/**
@@ -210,6 +211,12 @@ public final class MimeUtils {
add("application/x-xcf", "xcf");
add("application/x-xfig", "fig");
add("application/xhtml+xml", "xhtml");
+ // Video mime types for 3GPP first so they'll be default for guessMimeTypeFromExtension
+ // See RFC 3839 for 3GPP and RFC 4393 for 3GPP2
+ add("video/3gpp", "3gpp");
+ add("video/3gpp", "3gp");
+ add("video/3gpp2", "3gpp2");
+ add("video/3gpp2", "3g2");
add("audio/3gpp", "3gpp");
add("audio/aac", "aac");
add("audio/aac-adts", "aac");
@@ -353,10 +360,6 @@ public final class MimeUtils {
add("text/x-tex", "cls");
add("text/x-vcalendar", "vcs");
add("text/x-vcard", "vcf");
- add("video/3gpp", "3gpp");
- add("video/3gpp", "3gp");
- add("video/3gpp2", "3gpp2");
- add("video/3gpp2", "3g2");
add("video/avi", "avi");
add("video/dl", "dl");
add("video/dv", "dif");
@@ -407,52 +410,52 @@ private MimeUtils() {
}
/**
- * Returns true if the given MIME type has an entry in the map.
+ * Returns true if the given case insensitive MIME type has an entry in the map.
* @param mimeType A MIME type (i.e. text/plain)
- * @return True iff there is a mimeType entry in the map.
+ * @return True if a extension has been registered for
+ * the given case insensitive MIME type.
*/
public static boolean hasMimeType(String mimeType) {
- if (mimeType == null || mimeType.isEmpty()) {
- return false;
- }
- return mimeTypeToExtensionMap.containsKey(mimeType);
+ return (guessExtensionFromMimeType(mimeType) != null);
}
/**
- * Returns the MIME type for the given extension.
+ * Returns the MIME type for the given case insensitive file extension.
* @param extension A file extension without the leading '.'
- * @return The MIME type for the given extension or null iff there is none.
+ * @return The MIME type has been registered for
+ * the given case insensitive file extension or null if there is none.
*/
public static String guessMimeTypeFromExtension(String extension) {
if (extension == null || extension.isEmpty()) {
return null;
}
+ extension = extension.toLowerCase(Locale.US);
return extensionToMimeTypeMap.get(extension);
}
/**
- * Returns true if the given extension has a registered MIME type.
+ * Returns true if the given case insensitive extension has a registered MIME type.
* @param extension A file extension without the leading '.'
- * @return True iff there is an extension entry in the map.
+ * @return True if a MIME type has been registered for
+ * the given case insensitive file extension.
*/
public static boolean hasExtension(String extension) {
- if (extension == null || extension.isEmpty()) {
- return false;
- }
- return extensionToMimeTypeMap.containsKey(extension);
+ return (guessMimeTypeFromExtension(extension) != null);
}
/**
- * Returns the registered extension for the given MIME type. Note that some
+ * Returns the registered extension for the given case insensitive MIME type. Note that some
* MIME types map to multiple extensions. This call will return the most
* common extension for the given MIME type.
* @param mimeType A MIME type (i.e. text/plain)
- * @return The extension for the given MIME type or null iff there is none.
+ * @return The extension has been registered for
+ * the given case insensitive MIME type or null if there is none.
*/
public static String guessExtensionFromMimeType(String mimeType) {
if (mimeType == null || mimeType.isEmpty()) {
return null;
}
+ mimeType = mimeType.toLowerCase(Locale.US);
return mimeTypeToExtensionMap.get(mimeType);
}
}
diff --git a/luni/src/main/java/libcore/net/NetworkSecurityPolicy.java b/luni/src/main/java/libcore/net/NetworkSecurityPolicy.java
index 56b1b6a87..d9c87a417 100644
--- a/luni/src/main/java/libcore/net/NetworkSecurityPolicy.java
+++ b/luni/src/main/java/libcore/net/NetworkSecurityPolicy.java
@@ -71,6 +71,14 @@ public static void setInstance(NetworkSecurityPolicy policy) {
*/
public abstract boolean isCleartextTrafficPermitted(String hostname);
+ /**
+ * Returns {@code true} if Certificate Transparency information is required to be presented by
+ * the server and verified by the client in TLS connections to {@code hostname}.
+ *
+ * See RFC6962 section 3.3 for more details.
+ */
+ public abstract boolean isCertificateTransparencyVerificationRequired(String hostname);
+
public static final class DefaultNetworkSecurityPolicy extends NetworkSecurityPolicy {
@Override
public boolean isCleartextTrafficPermitted() {
@@ -81,5 +89,10 @@ public boolean isCleartextTrafficPermitted() {
public boolean isCleartextTrafficPermitted(String hostname) {
return isCleartextTrafficPermitted();
}
+
+ @Override
+ public boolean isCertificateTransparencyVerificationRequired(String hostname) {
+ return false;
+ }
}
}
diff --git a/luni/src/main/java/libcore/reflect/AnnotatedElements.java b/luni/src/main/java/libcore/reflect/AnnotatedElements.java
index 2fe2d2b25..2b4fb5ea2 100644
--- a/luni/src/main/java/libcore/reflect/AnnotatedElements.java
+++ b/luni/src/main/java/libcore/reflect/AnnotatedElements.java
@@ -32,45 +32,15 @@
*/
public final class AnnotatedElements {
/**
- * Default implementation for {@link AnnotatedElement#getDeclaredAnnotation}.
- *
- * @return Directly present annotation of type {@code annotationClass} for {@code element},
- * or {@code null} if none was found.
- */
- public static T getDeclaredAnnotation(AnnotatedElement element,
- Class annotationClass) {
- if (annotationClass == null) {
- throw new NullPointerException("annotationClass");
- }
-
- Annotation[] annotations = element.getDeclaredAnnotations();
-
- // Safeguard: getDeclaredAnnotations should never return null.
- if (annotations == null) {
- return null;
- }
-
- // The annotation might be directly present:
- // Return the first (and only) annotation whose class matches annotationClass.
- for (int i = 0; i < annotations.length; ++i) {
- if (annotationClass.isInstance(annotations[i])) {
- return (T)annotations[i]; // Safe because of above guard.
- }
- }
-
- // The annotation was *not* directly present:
- // If the array was empty, or we found no matches, return null.
- return null;
- }
-
- /**
- * Default implementation for {@link AnnotatedElement#getDeclaredAnnotationsByType}.
+ * Default implementation of {@link AnnotatedElement#getDeclaredAnnotationsByType}, and
+ * {@link AnnotatedElement#getAnnotationsByType} for elements that do not support annotation
+ * inheritance.
*
* @return Directly/indirectly present list of annotations of type {@code annotationClass} for
* {@code element}, or an empty array if none were found.
*/
- public static T[] getDeclaredAnnotationsByType(AnnotatedElement element,
- Class annotationClass) {
+ public static T[] getDirectOrIndirectAnnotationsByType(
+ AnnotatedElement element, Class annotationClass) {
if (annotationClass == null) {
throw new NullPointerException("annotationClass");
}
@@ -182,37 +152,7 @@ private static void insertAnnotationValues(Annotation ann
return (repeatableAnnotation == null) ? null : repeatableAnnotation.value();
}
- /**
- * Default implementation of {@link AnnotatedElement#getAnnotationsByType}.
- *
- *
- * This method does not handle inherited annotations and is
- * intended for use for {@code Method}, {@code Field}, {@code Package}.
- * The {@link Class#getAnnotationsByType} is implemented explicitly.
- *
- *
- * @return Associated annotations of type {@code annotationClass} for {@code element}.
- */
- public static T[] getAnnotationsByType(AnnotatedElement element,
- Class annotationClass) {
- if (annotationClass == null) {
- throw new NullPointerException("annotationClass");
- }
-
- // Find any associated annotations [directly or repeatably (indirectly) present on this class].
- T[] annotations = element.getDeclaredAnnotationsByType(annotationClass);
- if (annotations == null) {
- throw new AssertionError("annotations must not be null"); // Internal error.
- }
-
- // If nothing was found, we would look for associated annotations recursively up to the root
- // class. However this can only happen if AnnotatedElement is a Class, which is handled
- // in the Class override of this method.
- return annotations;
- }
-
private AnnotatedElements() {
- throw new AssertionError("Instances of AnnotatedElements not allowed");
}
}
diff --git a/luni/src/main/java/libcore/util/CharsetUtils.java b/luni/src/main/java/libcore/util/CharsetUtils.java
index 5163dbabb..bab6f53b2 100644
--- a/luni/src/main/java/libcore/util/CharsetUtils.java
+++ b/luni/src/main/java/libcore/util/CharsetUtils.java
@@ -16,6 +16,8 @@
package libcore.util;
+import dalvik.annotation.optimization.FastNative;
+
/**
* Various special-case charset conversions (for performance).
*
@@ -26,18 +28,21 @@ public final class CharsetUtils {
* Returns a new byte array containing the bytes corresponding to the characters in the given
* string, encoded in US-ASCII. Unrepresentable characters are replaced by (byte) '?'.
*/
+ @FastNative
public static native byte[] toAsciiBytes(String s, int offset, int length);
/**
* Returns a new byte array containing the bytes corresponding to the characters in the given
* string, encoded in ISO-8859-1. Unrepresentable characters are replaced by (byte) '?'.
*/
+ @FastNative
public static native byte[] toIsoLatin1Bytes(String s, int offset, int length);
/**
* Returns a new byte array containing the bytes corresponding to the characters in the given
* string, encoded in UTF-8. All characters are representable in UTF-8.
*/
+ @FastNative
public static native byte[] toUtf8Bytes(String s, int offset, int length);
/**
@@ -64,6 +69,7 @@ public static byte[] toBigEndianUtf16Bytes(String s, int offset, int length) {
* value[i] = (ch <= 0x7f) ? ch : REPLACEMENT_CHAR;
* }
*/
+ @FastNative
public static native void asciiBytesToChars(byte[] bytes, int offset, int length, char[] chars);
/**
@@ -73,6 +79,7 @@ public static byte[] toBigEndianUtf16Bytes(String s, int offset, int length) {
* value[i] = (char) (data[start++] & 0xff);
* }
*/
+ @FastNative
public static native void isoLatin1BytesToChars(byte[] bytes, int offset, int length, char[] chars);
private CharsetUtils() {
diff --git a/luni/src/main/java/libcore/util/TimeZoneDataFiles.java b/luni/src/main/java/libcore/util/TimeZoneDataFiles.java
new file mode 100644
index 000000000..83613391a
--- /dev/null
+++ b/luni/src/main/java/libcore/util/TimeZoneDataFiles.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.util;
+
+/**
+ * Utility methods associated with finding updateable time zone data files.
+ */
+public final class TimeZoneDataFiles {
+
+ private static final String ANDROID_ROOT_ENV = "ANDROID_ROOT";
+ private static final String ANDROID_DATA_ENV = "ANDROID_DATA";
+
+ private TimeZoneDataFiles() {}
+
+ // VisibleForTesting
+ public static String[] getTimeZoneFilePaths(String fileName) {
+ return new String[] {
+ getDataTimeZoneFile(fileName),
+ getSystemTimeZoneFile(fileName)
+ };
+ }
+
+ private static String getDataTimeZoneFile(String fileName) {
+ return System.getenv(ANDROID_DATA_ENV) + "/misc/zoneinfo/current/" + fileName;
+ }
+
+ // VisibleForTesting
+ public static String getSystemTimeZoneFile(String fileName) {
+ return System.getenv(ANDROID_ROOT_ENV) + "/usr/share/zoneinfo/" + fileName;
+ }
+
+ public static String generateIcuDataPath() {
+ StringBuilder icuDataPathBuilder = new StringBuilder();
+ // ICU should first look in ANDROID_DATA. This is used for (optional) timezone data.
+ String dataIcuDataPath = getEnvironmentPath(ANDROID_DATA_ENV, "/misc/zoneinfo/current/icu");
+ if (dataIcuDataPath != null) {
+ icuDataPathBuilder.append(dataIcuDataPath);
+ }
+
+ // ICU should always look in ANDROID_ROOT.
+ String systemIcuDataPath = getEnvironmentPath(ANDROID_ROOT_ENV, "/usr/icu");
+ if (systemIcuDataPath != null) {
+ if (icuDataPathBuilder.length() > 0) {
+ icuDataPathBuilder.append(":");
+ }
+ icuDataPathBuilder.append(systemIcuDataPath);
+ }
+ return icuDataPathBuilder.toString();
+ }
+
+ /**
+ * Creates a path by combining the value of an environment variable with a relative path.
+ * Returns {@code null} if the environment variable is not set.
+ */
+ private static String getEnvironmentPath(String environmentVariable, String path) {
+ String variable = System.getenv(environmentVariable);
+ if (variable == null) {
+ return null;
+ }
+ return variable + path;
+ }
+}
diff --git a/luni/src/main/java/libcore/util/ZoneInfo.java b/luni/src/main/java/libcore/util/ZoneInfo.java
index f9942218a..bbaf0f9c6 100644
--- a/luni/src/main/java/libcore/util/ZoneInfo.java
+++ b/luni/src/main/java/libcore/util/ZoneInfo.java
@@ -43,7 +43,7 @@
* reading the index and creating a {@link BufferIterator} that provides access to an entry for a
* specific file. This class is responsible for reading the data from that {@link BufferIterator}
* and storing it a representation to support the {@link TimeZone} and {@link GregorianCalendar}
- * implementations. See {@link ZoneInfo#makeTimeZone(String, BufferIterator)}.
+ * implementations. See {@link ZoneInfo#readTimeZone(String, BufferIterator, long)}.
*
* The main difference between {@code tzfile} and the compacted form is that the
* {@code struct ttinfo} only uses a single byte for {@code tt_isdst} and {@code tt_abbrind}.
@@ -115,8 +115,8 @@ public final class ZoneInfo extends TimeZone {
* in the offset from UTC or a change in the DST.
*
*
These times are pre-calculated externally from a set of rules (both historical and
- * future) and stored in a file from which {@link ZoneInfo#makeTimeZone(String, BufferIterator)}
- * reads the data. That is quite different to {@link java.util.SimpleTimeZone}, which has
+ * future) and stored in a file from which {@link ZoneInfo#readTimeZone(String, BufferIterator,
+ * long)} reads the data. That is quite different to {@link java.util.SimpleTimeZone}, which has
* essentially human readable rules (e.g. DST starts at 01:00 on the first Sunday in March and
* ends at 01:00 on the last Sunday in October) that can be used to determine the DST transition
* times across a number of years
@@ -178,19 +178,14 @@ public final class ZoneInfo extends TimeZone {
*/
private final byte[] mIsDsts;
- public static ZoneInfo makeTimeZone(String id, BufferIterator it) {
- return makeTimeZone(id, it, System.currentTimeMillis());
- }
-
- /**
- * Visible for testing.
- */
- public static ZoneInfo makeTimeZone(String id, BufferIterator it, long currentTimeMillis) {
+ public static ZoneInfo readTimeZone(String id, BufferIterator it, long currentTimeMillis)
+ throws IOException {
// Variable names beginning tzh_ correspond to those in "tzfile.h".
// Check tzh_magic.
- if (it.readInt() != 0x545a6966) { // "TZif"
- return null;
+ int tzh_magic = it.readInt();
+ if (tzh_magic != 0x545a6966) { // "TZif"
+ throw new IOException("Timezone id=" + id + " has an invalid header=" + tzh_magic);
}
// Skip the uninteresting part of the header.
@@ -198,9 +193,22 @@ public static ZoneInfo makeTimeZone(String id, BufferIterator it, long currentTi
// Read the sizes of the arrays we're about to read.
int tzh_timecnt = it.readInt();
+ // Arbitrary ceiling to prevent allocating memory for corrupt data.
+ // 2 per year with 2^32 seconds would give ~272 transitions.
+ final int MAX_TRANSITIONS = 2000;
+ if (tzh_timecnt < 0 || tzh_timecnt > MAX_TRANSITIONS) {
+ throw new IOException(
+ "Timezone id=" + id + " has an invalid number of transitions=" + tzh_timecnt);
+ }
+
int tzh_typecnt = it.readInt();
- if (tzh_typecnt > 256) {
- throw new IllegalStateException(id + " has more than 256 different types");
+ final int MAX_TYPES = 256;
+ if (tzh_typecnt < 1) {
+ throw new IOException("ZoneInfo requires at least one type "
+ + "to be provided for each timezone but could not find one for '" + id + "'");
+ } else if (tzh_typecnt > MAX_TYPES) {
+ throw new IOException(
+ "Timezone with id " + id + " has too many types=" + tzh_typecnt);
}
it.skip(4); // Skip tzh_charcnt.
@@ -217,20 +225,32 @@ public static ZoneInfo makeTimeZone(String id, BufferIterator it, long currentTi
long[] transitions64 = new long[tzh_timecnt];
for (int i = 0; i < tzh_timecnt; ++i) {
transitions64[i] = transitions32[i];
+ if (i > 0 && transitions64[i] <= transitions64[i - 1]) {
+ throw new IOException(
+ id + " transition at " + i + " is not sorted correctly, is "
+ + transitions64[i] + ", previous is " + transitions64[i - 1]);
+ }
}
byte[] type = new byte[tzh_timecnt];
it.readByteArray(type, 0, type.length);
+ for (int i = 0; i < type.length; i++) {
+ int typeIndex = type[i] & 0xff;
+ if (typeIndex >= tzh_typecnt) {
+ throw new IOException(
+ id + " type at " + i + " is not < " + tzh_typecnt + ", is " + typeIndex);
+ }
+ }
int[] gmtOffsets = new int[tzh_typecnt];
byte[] isDsts = new byte[tzh_typecnt];
for (int i = 0; i < tzh_typecnt; ++i) {
gmtOffsets[i] = it.readInt();
- byte b = it.readByte();
- if (b != 0 && b != 1) {
- throw new IllegalStateException(id + " dst at " + i + " is not 0 or 1, is " + b);
+ byte isDst = it.readByte();
+ if (isDst != 0 && isDst != 1) {
+ throw new IOException(id + " dst at " + i + " is not 0 or 1, is " + isDst);
}
- isDsts[i] = b;
+ isDsts[i] = isDst;
// We skip the abbreviation index. This would let us provide historically-accurate
// time zone abbreviations (such as "AHST", "YST", and "AKST" for standard time in
// America/Anchorage in 1982, 1983, and 1984 respectively). ICU only knows the current
@@ -247,7 +267,7 @@ public static ZoneInfo makeTimeZone(String id, BufferIterator it, long currentTi
private ZoneInfo(String name, long[] transitions, byte[] types, int[] gmtOffsets, byte[] isDsts,
long currentTimeMillis) {
if (gmtOffsets.length == 0) {
- throw new IllegalStateException("ZoneInfo requires at least one offset "
+ throw new IllegalArgumentException("ZoneInfo requires at least one offset "
+ "to be provided for each timezone but could not find one for '" + name + "'");
}
mTransitions = transitions;
diff --git a/luni/src/main/java/libcore/util/ZoneInfoDB.java b/luni/src/main/java/libcore/util/ZoneInfoDB.java
index 916ba290f..acb9c1230 100644
--- a/luni/src/main/java/libcore/util/ZoneInfoDB.java
+++ b/luni/src/main/java/libcore/util/ZoneInfoDB.java
@@ -17,6 +17,9 @@
package libcore.util;
import android.system.ErrnoException;
+
+import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
@@ -34,11 +37,30 @@
* @hide - used to implement TimeZone
*/
public final class ZoneInfoDB {
+
+ // VisibleForTesting
+ public static final String TZDATA_FILE = "tzdata";
+
private static final TzData DATA =
- new TzData(System.getenv("ANDROID_DATA") + "/misc/zoneinfo/current/tzdata",
- System.getenv("ANDROID_ROOT") + "/usr/share/zoneinfo/tzdata");
+ TzData.loadTzDataWithFallback(TimeZoneDataFiles.getTimeZoneFilePaths(TZDATA_FILE));
public static class TzData {
+
+ // The database reserves 40 bytes for each id.
+ private static final int SIZEOF_TZNAME = 40;
+
+ // The database uses 32-bit (4 byte) integers.
+ private static final int SIZEOF_TZINT = 4;
+
+ // Each index entry takes up this number of bytes.
+ public static final int SIZEOF_INDEX_ENTRY = SIZEOF_TZNAME + 3 * SIZEOF_TZINT;
+
+ /**
+ * {@code true} if {@link #close()} has been called meaning the instance cannot provide any
+ * data.
+ */
+ private boolean closed;
+
/**
* Rather than open, read, and close the big data file each time we look up a time zone,
* we map the big data file during startup, and then just use the MemoryMappedFile.
@@ -71,47 +93,85 @@ public static class TzData {
new BasicLruCache(CACHE_SIZE) {
@Override
protected ZoneInfo create(String id) {
- BufferIterator it = getBufferIterator(id);
- if (it == null) {
- return null;
+ try {
+ return makeTimeZoneUncached(id);
+ } catch (IOException e) {
+ throw new IllegalStateException("Unable to load timezone for ID=" + id, e);
}
-
- return ZoneInfo.makeTimeZone(id, it);
}
};
- public TzData(String... paths) {
+ /**
+ * Loads the data at the specified paths in order, returning the first valid one as a
+ * {@link TzData} object. If there is no valid one found a basic fallback instance is created
+ * containing just GMT.
+ */
+ public static TzData loadTzDataWithFallback(String... paths) {
for (String path : paths) {
- if (loadData(path)) {
- return;
+ TzData tzData = new TzData();
+ if (tzData.loadData(path)) {
+ return tzData;
}
}
// We didn't find any usable tzdata on disk, so let's just hard-code knowledge of "GMT".
// This is actually implemented in TimeZone itself, so if this is the only time zone
// we report, we won't be asked any more questions.
- System.logE("Couldn't find any tzdata!");
- version = "missing";
- zoneTab = "# Emergency fallback data.\n";
- ids = new String[] { "GMT" };
- byteOffsets = rawUtcOffsetsCache = new int[1];
+ System.logE("Couldn't find any " + TZDATA_FILE + " file!");
+ return TzData.createFallback();
+ }
+
+ /**
+ * Loads the data at the specified path and returns the {@link TzData} object if it is valid,
+ * otherwise {@code null}.
+ */
+ public static TzData loadTzData(String path) {
+ TzData tzData = new TzData();
+ if (tzData.loadData(path)) {
+ return tzData;
+ }
+ return null;
+ }
+
+ private static TzData createFallback() {
+ TzData tzData = new TzData();
+ tzData.populateFallback();
+ return tzData;
+ }
+
+ private TzData() {
}
/**
* Visible for testing.
*/
public BufferIterator getBufferIterator(String id) {
+ checkNotClosed();
+
// Work out where in the big data file this time zone is.
int index = Arrays.binarySearch(ids, id);
if (index < 0) {
return null;
}
+ int byteOffset = byteOffsets[index];
BufferIterator it = mappedFile.bigEndianIterator();
- it.skip(byteOffsets[index]);
+ it.skip(byteOffset);
return it;
}
+ private void populateFallback() {
+ version = "missing";
+ zoneTab = "# Emergency fallback data.\n";
+ ids = new String[] { "GMT" };
+ byteOffsets = rawUtcOffsetsCache = new int[1];
+ }
+
+ /**
+ * Loads the data file at the specified path. If the data is valid {@code true} will be
+ * returned and the {@link TzData} instance can be used. If {@code false} is returned then the
+ * TzData instance is left in a closed state and must be discarded.
+ */
private boolean loadData(String path) {
try {
mappedFile = MemoryMappedFile.mmapRO(path);
@@ -122,34 +182,56 @@ private boolean loadData(String path) {
readHeader();
return true;
} catch (Exception ex) {
+ close();
+
// Something's wrong with the file.
// Log the problem and return false so we try the next choice.
- System.logE("tzdata file \"" + path + "\" was present but invalid!", ex);
+ System.logE(TZDATA_FILE + " file \"" + path + "\" was present but invalid!", ex);
return false;
}
}
- private void readHeader() {
+ private void readHeader() throws IOException {
// byte[12] tzdata_version -- "tzdata2012f\0"
// int index_offset
// int data_offset
// int zonetab_offset
BufferIterator it = mappedFile.bigEndianIterator();
- byte[] tzdata_version = new byte[12];
- it.readByteArray(tzdata_version, 0, tzdata_version.length);
- String magic = new String(tzdata_version, 0, 6, StandardCharsets.US_ASCII);
- if (!magic.equals("tzdata") || tzdata_version[11] != 0) {
- throw new RuntimeException("bad tzdata magic: " + Arrays.toString(tzdata_version));
- }
- version = new String(tzdata_version, 6, 5, StandardCharsets.US_ASCII);
+ try {
+ byte[] tzdata_version = new byte[12];
+ it.readByteArray(tzdata_version, 0, tzdata_version.length);
+ String magic = new String(tzdata_version, 0, 6, StandardCharsets.US_ASCII);
+ if (!magic.equals("tzdata") || tzdata_version[11] != 0) {
+ throw new IOException("bad tzdata magic: " + Arrays.toString(tzdata_version));
+ }
+ version = new String(tzdata_version, 6, 5, StandardCharsets.US_ASCII);
+
+ final int fileSize = mappedFile.size();
+ int index_offset = it.readInt();
+ validateOffset(index_offset, fileSize);
+ int data_offset = it.readInt();
+ validateOffset(data_offset, fileSize);
+ int zonetab_offset = it.readInt();
+ validateOffset(zonetab_offset, fileSize);
+
+ if (index_offset >= data_offset || data_offset >= zonetab_offset) {
+ throw new IOException("Invalid offset: index_offset=" + index_offset
+ + ", data_offset=" + data_offset + ", zonetab_offset=" + zonetab_offset
+ + ", fileSize=" + fileSize);
+ }
- int index_offset = it.readInt();
- int data_offset = it.readInt();
- int zonetab_offset = it.readInt();
+ readIndex(it, index_offset, data_offset);
+ readZoneTab(it, zonetab_offset, fileSize - zonetab_offset);
+ } catch (IndexOutOfBoundsException e) {
+ throw new IOException("Invalid read from data file", e);
+ }
+ }
- readIndex(it, index_offset, data_offset);
- readZoneTab(it, zonetab_offset, (int) mappedFile.size() - zonetab_offset);
+ private static void validateOffset(int offset, int size) throws IOException {
+ if (offset < 0 || offset >= size) {
+ throw new IOException("Invalid offset=" + offset + ", size=" + size);
+ }
}
private void readZoneTab(BufferIterator it, int zoneTabOffset, int zoneTabSize) {
@@ -159,62 +241,79 @@ private void readZoneTab(BufferIterator it, int zoneTabOffset, int zoneTabSize)
zoneTab = new String(bytes, 0, bytes.length, StandardCharsets.US_ASCII);
}
- private void readIndex(BufferIterator it, int indexOffset, int dataOffset) {
+ private void readIndex(BufferIterator it, int indexOffset, int dataOffset) throws IOException {
it.seek(indexOffset);
- // The database reserves 40 bytes for each id.
- final int SIZEOF_TZNAME = 40;
- // The database uses 32-bit (4 byte) integers.
- final int SIZEOF_TZINT = 4;
-
byte[] idBytes = new byte[SIZEOF_TZNAME];
int indexSize = (dataOffset - indexOffset);
- int entryCount = indexSize / (SIZEOF_TZNAME + 3*SIZEOF_TZINT);
-
- char[] idChars = new char[entryCount * SIZEOF_TZNAME];
- int[] idEnd = new int[entryCount];
- int idOffset = 0;
+ if (indexSize % SIZEOF_INDEX_ENTRY != 0) {
+ throw new IOException("Index size is not divisible by " + SIZEOF_INDEX_ENTRY
+ + ", indexSize=" + indexSize);
+ }
+ int entryCount = indexSize / SIZEOF_INDEX_ENTRY;
byteOffsets = new int[entryCount];
+ ids = new String[entryCount];
for (int i = 0; i < entryCount; i++) {
+ // Read the fixed length timezone ID.
it.readByteArray(idBytes, 0, idBytes.length);
+ // Read the offset into the file where the data for ID can be found.
byteOffsets[i] = it.readInt();
- byteOffsets[i] += dataOffset; // TODO: change the file format so this is included.
+ byteOffsets[i] += dataOffset;
int length = it.readInt();
if (length < 44) {
- throw new AssertionError("length in index file < sizeof(tzhead)");
+ throw new IOException("length in index file < sizeof(tzhead)");
}
it.skip(4); // Skip the unused 4 bytes that used to be the raw offset.
- // Don't include null chars in the String
- int len = idBytes.length;
- for (int j = 0; j < len; j++) {
- if (idBytes[j] == 0) {
- break;
+ // Calculate the true length of the ID.
+ int len = 0;
+ while (idBytes[len] != 0 && len < idBytes.length) {
+ len++;
+ }
+ if (len == 0) {
+ throw new IOException("Invalid ID at index=" + i);
+ }
+ ids[i] = new String(idBytes, 0, len, StandardCharsets.US_ASCII);
+ if (i > 0) {
+ if (ids[i].compareTo(ids[i - 1]) <= 0) {
+ throw new IOException("Index not sorted or contains multiple entries with the same ID"
+ + ", index=" + i + ", ids[i]=" + ids[i] + ", ids[i - 1]=" + ids[i - 1]);
}
- idChars[idOffset++] = (char) (idBytes[j] & 0xFF);
}
+ }
+ }
- idEnd[i] = idOffset;
+ public void validate() throws IOException {
+ checkNotClosed();
+ // Validate the data in the tzdata file by loading each and every zone.
+ for (String id : getAvailableIDs()) {
+ ZoneInfo zoneInfo = makeTimeZoneUncached(id);
+ if (zoneInfo == null) {
+ throw new IOException("Unable to find data for ID=" + id);
+ }
}
+ }
- // We create one string containing all the ids, and then break that into substrings.
- // This way, all ids share a single char[] on the heap.
- String allIds = new String(idChars, 0, idOffset);
- ids = new String[entryCount];
- for (int i = 0; i < entryCount; i++) {
- ids[i] = allIds.substring(i == 0 ? 0 : idEnd[i - 1], idEnd[i]);
+ ZoneInfo makeTimeZoneUncached(String id) throws IOException {
+ BufferIterator it = getBufferIterator(id);
+ if (it == null) {
+ return null;
}
+
+ return ZoneInfo.readTimeZone(id, it, System.currentTimeMillis());
}
public String[] getAvailableIDs() {
+ checkNotClosed();
return ids.clone();
}
public String[] getAvailableIDs(int rawUtcOffset) {
+ checkNotClosed();
List matches = new ArrayList();
int[] rawUtcOffsets = getRawUtcOffsets();
for (int i = 0; i < rawUtcOffsets.length; ++i) {
@@ -242,28 +341,83 @@ private synchronized int[] getRawUtcOffsets() {
}
public String getVersion() {
+ checkNotClosed();
return version;
}
public String getZoneTab() {
+ checkNotClosed();
return zoneTab;
}
public ZoneInfo makeTimeZone(String id) throws IOException {
+ checkNotClosed();
ZoneInfo zoneInfo = cache.get(id);
// The object from the cache is cloned because TimeZone / ZoneInfo are mutable.
return zoneInfo == null ? null : (ZoneInfo) zoneInfo.clone();
}
public boolean hasTimeZone(String id) throws IOException {
+ checkNotClosed();
return cache.get(id) != null;
}
+ public void close() {
+ if (!closed) {
+ closed = true;
+
+ // Clear state that takes up appreciable heap.
+ ids = null;
+ byteOffsets = null;
+ rawUtcOffsetsCache = null;
+ mappedFile = null;
+ cache.evictAll();
+
+ // Remove the mapped file (if needed).
+ if (mappedFile != null) {
+ try {
+ mappedFile.close();
+ } catch (ErrnoException ignored) {
+ }
+ }
+ }
+ }
+
+ private void checkNotClosed() throws IllegalStateException {
+ if (closed) {
+ throw new IllegalStateException("TzData is closed");
+ }
+ }
+
@Override protected void finalize() throws Throwable {
- if (mappedFile != null) {
- mappedFile.close();
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /**
+ * Returns the String describing the IANA version of the rules contained in the specified TzData
+ * file. This method just reads the header of the file, and so is less expensive than mapping
+ * the whole file into memory (and provides no guarantees about validity).
+ */
+ public static String getRulesVersion(File tzDataFile) throws IOException {
+ try (FileInputStream is = new FileInputStream(tzDataFile)) {
+
+ final int bytesToRead = 12;
+ byte[] tzdataVersion = new byte[bytesToRead];
+ int bytesRead = is.read(tzdataVersion, 0, bytesToRead);
+ if (bytesRead != bytesToRead) {
+ throw new IOException("File too short: only able to read " + bytesRead + " bytes.");
+ }
+
+ String magic = new String(tzdataVersion, 0, 6, StandardCharsets.US_ASCII);
+ if (!magic.equals("tzdata") || tzdataVersion[11] != 0) {
+ throw new IOException("bad tzdata magic: " + Arrays.toString(tzdataVersion));
+ }
+ return new String(tzdataVersion, 6, 5, StandardCharsets.US_ASCII);
}
- super.finalize();
}
}
diff --git a/luni/src/main/java/org/apache/harmony/xml/dom/DOMConfigurationImpl.java b/luni/src/main/java/org/apache/harmony/xml/dom/DOMConfigurationImpl.java
index 672477651..0eda8f04b 100644
--- a/luni/src/main/java/org/apache/harmony/xml/dom/DOMConfigurationImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xml/dom/DOMConfigurationImpl.java
@@ -357,6 +357,10 @@ public Object getParameter(String name) throws DOMException {
}
public DOMStringList getParameterNames() {
+ return internalGetParameterNames();
+ }
+
+ private static DOMStringList internalGetParameterNames() {
final String[] result = PARAMETERS.keySet().toArray(new String[PARAMETERS.size()]);
return new DOMStringList() {
public String item(int index) {
diff --git a/luni/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java b/luni/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
index e1b62fa0c..e4002eaa1 100644
--- a/luni/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
@@ -56,7 +56,6 @@ public final class DocumentImpl extends InnerNodeImpl implements Document {
*/
private String documentUri;
private String inputEncoding;
- private String xmlEncoding;
private String xmlVersion = "1.0";
private boolean xmlStandalone = false;
private boolean strictErrorChecking = true;
@@ -437,7 +436,7 @@ public String getInputEncoding() {
}
public String getXmlEncoding() {
- return xmlEncoding;
+ return null;
}
public boolean getXmlStandalone() {
diff --git a/luni/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java b/luni/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java
index 040a0128d..4f54fb55c 100644
--- a/luni/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java
@@ -129,11 +129,12 @@ public Document parse(InputSource source) throws SAXException, IOException {
parser.require(XmlPullParser.END_DOCUMENT, null, null);
} catch (XmlPullParserException ex) {
- if (ex.getDetail() instanceof IOException) {
- throw (IOException) ex.getDetail();
+ Throwable detail = ex.getDetail();
+ if (detail instanceof IOException) {
+ throw (IOException) detail;
}
- if (ex.getDetail() instanceof RuntimeException) {
- throw (RuntimeException) ex.getDetail();
+ if (detail instanceof RuntimeException) {
+ throw (RuntimeException) detail;
}
LocatorImpl locator = new LocatorImpl();
diff --git a/luni/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java b/luni/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java
index c4ff069b2..39dd367fb 100644
--- a/luni/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java
+++ b/luni/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java
@@ -126,9 +126,12 @@ public static XMLReader createXMLReader ()
in = loader.getResourceAsStream (service);
if (in != null) {
- reader = new BufferedReader (new InputStreamReader (in, StandardCharsets.UTF_8));
- className = reader.readLine ();
- in.close ();
+ try {
+ reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
+ className = reader.readLine();
+ } finally {
+ in.close(); // may throw IOException
+ }
}
} catch (Exception e) {
}
diff --git a/luni/src/main/native/ExecStrings.cpp b/luni/src/main/native/ExecStrings.cpp
index a6a62e21b..9a408fd65 100644
--- a/luni/src/main/native/ExecStrings.cpp
+++ b/luni/src/main/native/ExecStrings.cpp
@@ -20,7 +20,8 @@
#include
-#include "cutils/log.h"
+#include
+
#include "ScopedLocalRef.h"
ExecStrings::ExecStrings(JNIEnv* env, jobjectArray java_string_array)
diff --git a/luni/src/main/native/IcuUtilities.cpp b/luni/src/main/native/IcuUtilities.cpp
index 98648a5f3..6b29e670c 100644
--- a/luni/src/main/native/IcuUtilities.cpp
+++ b/luni/src/main/native/IcuUtilities.cpp
@@ -16,16 +16,17 @@
#define LOG_TAG "IcuUtilities"
+#include
+
#include "IcuUtilities.h"
#include "JniConstants.h"
#include "JniException.h"
#include "ScopedLocalRef.h"
#include "ScopedUtfChars.h"
-#include "cutils/log.h"
#include "unicode/strenum.h"
-#include "unicode/uloc.h"
#include "unicode/ustring.h"
+#include "unicode/uloc.h"
jobjectArray fromStringEnumeration(JNIEnv* env, UErrorCode& status, const char* provider, icu::StringEnumeration* se) {
if (maybeThrowIcuException(env, provider, status)) {
diff --git a/luni/src/main/native/NetFd.h b/luni/src/main/native/NetFd.h
index 235b0577a..0397e4d46 100644
--- a/luni/src/main/native/NetFd.h
+++ b/luni/src/main/native/NetFd.h
@@ -17,6 +17,8 @@
#ifndef NET_FD_H_included
#define NET_FD_H_included
+#include "JNIHelp.h"
+
/**
* Wraps access to the int inside a java.io.FileDescriptor, taking care of throwing exceptions.
*/
diff --git a/luni/src/main/native/NetworkUtilities.cpp b/luni/src/main/native/NetworkUtilities.cpp
index b285a0133..bf438fac1 100644
--- a/luni/src/main/native/NetworkUtilities.cpp
+++ b/luni/src/main/native/NetworkUtilities.cpp
@@ -140,8 +140,12 @@ static bool inetAddressToSockaddr(JNIEnv* env, jobject inetAddress, int port, so
jbyte* dst = reinterpret_cast(&sin6.sin6_addr.s6_addr);
env->GetByteArrayRegion(addressBytes.get(), 0, 16, dst);
// ...and set the scope id...
- static jfieldID scopeFid = env->GetFieldID(JniConstants::inet6AddressClass, "scope_id", "I");
- sin6.sin6_scope_id = env->GetIntField(inetAddress, scopeFid);
+ static jfieldID holder6Fid = env->GetFieldID(JniConstants::inet6AddressClass,
+ "holder6",
+ "Ljava/net/Inet6Address$Inet6AddressHolder;");
+ ScopedLocalRef holder6(env, env->GetObjectField(inetAddress, holder6Fid));
+ static jfieldID scopeFid = env->GetFieldID(JniConstants::inet6AddressHolderClass, "scope_id", "I");
+ sin6.sin6_scope_id = env->GetIntField(holder6.get(), scopeFid);
sa_len = sizeof(sockaddr_in6);
return true;
}
diff --git a/luni/src/main/native/Register.cpp b/luni/src/main/native/Register.cpp
index b099a4e1c..f642211c4 100644
--- a/luni/src/main/native/Register.cpp
+++ b/luni/src/main/native/Register.cpp
@@ -16,12 +16,13 @@
#define LOG_TAG "libcore" // We'll be next to "dalvikvm" in the log; make the distinction clear.
-#include "cutils/log.h"
+#include
+
+#include "log/log.h"
+
#include "JniConstants.h"
#include "ScopedLocalFrame.h"
-#include
-
// DalvikVM calls this on startup, so we can statically register all our native methods.
jint JNI_OnLoad(JavaVM* vm, void*) {
JNIEnv* env;
@@ -35,6 +36,7 @@ jint JNI_OnLoad(JavaVM* vm, void*) {
#define REGISTER(FN) extern void FN(JNIEnv*); FN(env)
REGISTER(register_android_system_OsConstants);
// REGISTER(register_java_lang_StringToReal);
+ REGISTER(register_java_lang_invoke_MethodHandle);
REGISTER(register_java_math_NativeBN);
REGISTER(register_java_util_regex_Matcher);
REGISTER(register_java_util_regex_Pattern);
@@ -42,8 +44,8 @@ jint JNI_OnLoad(JavaVM* vm, void*) {
REGISTER(register_libcore_icu_NativeConverter);
REGISTER(register_libcore_icu_TimeZoneNames);
REGISTER(register_libcore_io_AsynchronousCloseMonitor);
+ REGISTER(register_libcore_io_Linux);
REGISTER(register_libcore_io_Memory);
- REGISTER(register_libcore_io_Posix);
REGISTER(register_libcore_util_NativeAllocationRegistry);
REGISTER(register_org_apache_harmony_dalvik_NativeTestTarget);
REGISTER(register_org_apache_harmony_xml_ExpatParser);
@@ -52,3 +54,20 @@ jint JNI_OnLoad(JavaVM* vm, void*) {
return JNI_VERSION_1_6;
}
+
+// DalvikVM calls this on shutdown, do any global cleanup here.
+// -- Very important if we restart multiple DalvikVMs in the same process to reset the state.
+void JNI_OnUnload(JavaVM* vm, void*) {
+ JNIEnv* env;
+ if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) {
+ ALOGE("JavaVM::GetEnv() failed");
+ abort();
+ }
+ ALOGV("libjavacore JNI_OnUnload");
+
+ ScopedLocalFrame localFrame(env);
+
+#define UNREGISTER(FN) extern void FN(JNIEnv*); FN(env)
+ UNREGISTER(unregister_libcore_icu_ICU);
+#undef UNREGISTER
+}
diff --git a/luni/src/main/native/android_system_OsConstants.cpp b/luni/src/main/native/android_system_OsConstants.cpp
index 1293fe776..3ae4af6cf 100644
--- a/luni/src/main/native/android_system_OsConstants.cpp
+++ b/luni/src/main/native/android_system_OsConstants.cpp
@@ -23,7 +23,9 @@
#include
#include
#include
+#include
#include
+#include
#include
#include
#include