summaryrefslogtreecommitdiffstats
path: root/luni
diff options
context:
space:
mode:
Diffstat (limited to 'luni')
-rw-r--r--luni/src/main/java/java/io/FileInputStream.java46
-rw-r--r--luni/src/main/java/java/util/ArrayList.java818
-rw-r--r--luni/src/main/java/java/util/Formatter.java79
-rw-r--r--luni/src/main/java/java/util/HashMap.java2
-rw-r--r--luni/src/main/java/org/apache/harmony/luni/internal/util/ZoneInfo.java17
-rw-r--r--luni/src/main/java/org/apache/harmony/luni/platform/IFileSystem.java3
-rw-r--r--luni/src/main/java/org/apache/harmony/luni/platform/OSFileSystem.java171
-rw-r--r--luni/src/main/native/java_net_InetAddress.cpp81
-rw-r--r--luni/src/main/native/java_net_NetworkInterface.c38
-rw-r--r--luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp790
-rw-r--r--luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp10
-rw-r--r--luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp283
-rw-r--r--luni/src/test/java/com/google/coretests/CoreTestRunner.java49
-rw-r--r--luni/src/test/java/org/apache/harmony/luni/tests/java/lang/PackageTest.java2
-rw-r--r--luni/src/test/java/tests/api/java/io/FileTest.java3
-rw-r--r--luni/src/test/java/tests/api/java/io/RandomAccessFileTest.java30
-rw-r--r--luni/src/test/java/tests/api/java/util/ArrayListTest.java91
-rw-r--r--luni/src/test/java/tests/api/java/util/FormatterTest.java30
-rw-r--r--luni/src/test/java/tests/api/java/util/TimeZoneTest.java13
19 files changed, 1066 insertions, 1490 deletions
diff --git a/luni/src/main/java/java/io/FileInputStream.java b/luni/src/main/java/java/io/FileInputStream.java
index 1243262..c236888 100644
--- a/luni/src/main/java/java/io/FileInputStream.java
+++ b/luni/src/main/java/java/io/FileInputStream.java
@@ -312,25 +312,24 @@ public class FileInputStream extends InputStream implements Closeable {
}
openCheck();
synchronized (repositioningLock) {
- // stdin requires special handling
- if (fd == FileDescriptor.in) {
- return (int) fileSystem.ttyRead(buffer, offset, count);
- }
+ // BEGIN android-changed
+ // If you only support Linux, there's nothing special about stdin.
return (int) fileSystem.read(fd.descriptor, buffer, offset, count);
+ // END android-changed
}
}
/**
* Skips {@code count} number of bytes in this stream. Subsequent
- * {@code read()}'s will not return these bytes unless {@code reset()} is
- * used. This method may perform multiple reads to read {@code count} bytes.
+ * {@code read()}s will not return these bytes unless {@code reset()} is
+ * used. If the underlying stream is unseekable, an IOException is thrown.
*
* @param count
* the number of bytes to skip.
* @return the number of bytes actually skipped.
* @throws IOException
- * if {@code count < 0}, this stream is closed or another
- * IOException occurs.
+ * if {@code count < 0}, this stream is closed or unseekable,
+ * or another IOException occurs.
*/
@Override
public long skip(long count) throws IOException {
@@ -344,29 +343,18 @@ public class FileInputStream extends InputStream implements Closeable {
throw new IOException(Msg.getString("KA013")); //$NON-NLS-1$
}
- // stdin requires special handling
- if (fd == FileDescriptor.in) {
- // Read and discard count bytes in 8k chunks
- long skipped = 0, numRead;
- int chunk = count < 8192 ? (int) count : 8192;
- byte[] buffer = new byte[chunk];
- for (long i = count / chunk; i >= 0; i--) {
- numRead = fileSystem.ttyRead(buffer, 0, chunk);
- skipped += numRead;
- if (numRead < chunk) {
- return skipped;
- }
- }
- return skipped;
- }
-
+ // BEGIN android-changed
+ // The RI doesn't treat stdin as special. It throws IOException for
+ // all non-seekable streams, so we do too. If you did want to support
+ // non-seekable streams, the best way to do it would be to recognize
+ // when lseek(2) fails with ESPIPE and call super.skip(count).
synchronized (repositioningLock) {
- final long currentPosition = fileSystem.seek(fd.descriptor, 0L,
- IFileSystem.SEEK_CUR);
- final long newPosition = fileSystem.seek(fd.descriptor,
- currentPosition + count, IFileSystem.SEEK_SET);
- return newPosition - currentPosition;
+ // Our seek returns the new offset, but we know it will throw an
+ // exception if it couldn't perform exactly the seek we asked for.
+ fileSystem.seek(fd.descriptor, count, IFileSystem.SEEK_CUR);
+ return count;
}
+ // END android-changed
}
private synchronized void openCheck() throws IOException {
diff --git a/luni/src/main/java/java/util/ArrayList.java b/luni/src/main/java/java/util/ArrayList.java
index b8c7056..7c46e89 100644
--- a/luni/src/main/java/java/util/ArrayList.java
+++ b/luni/src/main/java/java/util/ArrayList.java
@@ -15,12 +15,16 @@
* limitations under the License.
*/
+// BEGIN android-note
+// New implementation: simpler and faster than Harmony implementation.
+// BEGIN android-note
+
package java.util;
import java.io.IOException;
+import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.io.ObjectStreamField;
import java.io.Serializable;
import java.lang.reflect.Array;
@@ -29,37 +33,38 @@ import java.lang.reflect.Array;
* optional operations adding, removing, and replacing are supported. The
* elements can be any objects.
*
+ * @param <E> The element type of this list.
* @since 1.2
*/
-public class ArrayList<E> extends AbstractList<E> implements List<E>,
- Cloneable, Serializable, RandomAccess {
-
- private static final long serialVersionUID = 8683452581122892189L;
-
- // BEGIN android-added
- /** zero-element array */
- private static final Object[] emptyArray = new Object[0];
- // END android-added
-
- private transient int firstIndex;
+public class ArrayList<E> extends AbstractList<E>
+ implements Cloneable, Serializable, RandomAccess {
+ /**
+ * An empty array of objects (to be shared among all empty lists).
+ */
+ private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
- private transient int lastIndex;
+ /**
+ * The minimum amount by which the capacity of an ArrayList will increase.
+ * This tuning parameter controls a time-space tradeoff. This value (12)
+ * gives empirically good results and is arguably consistent with the
+ * RI's specified default initial capacity of 10: instead of 10, we start
+ * with 0 (sans allocation) and jump to 12.
+ */
+ private static final int MIN_CAPACITY_INCREMENT = 12;
- private transient E[] array;
+ /**
+ * The number of elements in this list.
+ */
+ int size;
/**
- * Constructs a new instance of {@code ArrayList} with zero capacity.
+ * The elements in this list, followed by nulls.
*/
- public ArrayList() {
- // BEGIN android-changed
- // default capacity is zero, not ten
- this(0);
- // END android-changed
- }
+ transient Object[] array;
/**
* Constructs a new instance of {@code ArrayList} with the specified
- * capacity.
+ * initial capacity.
*
* @param capacity
* the initial capacity of this {@code ArrayList}.
@@ -68,37 +73,55 @@ public class ArrayList<E> extends AbstractList<E> implements List<E>,
if (capacity < 0) {
throw new IllegalArgumentException();
}
- firstIndex = lastIndex = 0;
- array = newElementArray(capacity);
+ array = (capacity == 0 ? EMPTY_OBJECT_ARRAY : new Object[capacity]);
+ }
+
+ /**
+ * Constructs a new {@code ArrayList} instance with zero initial capacity.
+ */
+ public ArrayList() {
+ array = EMPTY_OBJECT_ARRAY;
}
/**
* Constructs a new instance of {@code ArrayList} containing the elements of
- * the specified collection. The initial size of the {@code ArrayList} will
- * be 10% higher than the size of the specified collection.
+ * the specified collection.
*
* @param collection
* the collection of elements to add.
*/
public ArrayList(Collection<? extends E> collection) {
- firstIndex = 0;
- Object[] objects = collection.toArray();
- int size = objects.length;
- array = newElementArray(size + (size / 10));
- System.arraycopy(objects, 0, array, 0, size);
- lastIndex = size;
- modCount = 1;
+ Object[] a = collection.toArray();
+ if (a.getClass() != Object[].class) {
+ Object[] newArray = new Object[a.length];
+ System.arraycopy(a, 0, newArray, 0, a.length);
+ a = newArray;
+ }
+ array = a;
+ size = a.length;
}
- @SuppressWarnings("unchecked")
- private E[] newElementArray(int size) {
- // BEGIN android-added
- if (size == 0) {
- return (E[])emptyArray;
+ /**
+ * Adds the specified object at the end of this {@code ArrayList}.
+ *
+ * @param object
+ * the object to add.
+ * @return always true
+ */
+ @Override public boolean add(E object) {
+ Object[] a = array;
+ int s = size;
+ if (s == a.length) {
+ Object[] newArray = new Object[s +
+ (s < (MIN_CAPACITY_INCREMENT / 2) ?
+ MIN_CAPACITY_INCREMENT : s >> 1)];
+ System.arraycopy(a, 0, newArray, 0, s);
+ array = a = newArray;
}
- // END android-added
-
- return (E[]) new Object[size];
+ a[s] = object;
+ size = s + 1;
+ modCount++;
+ return true;
}
/**
@@ -107,164 +130,136 @@ public class ArrayList<E> extends AbstractList<E> implements List<E>,
* specified location. If the location is equal to the size of this
* {@code ArrayList}, the object is added at the end.
*
- * @param location
+ * @param index
* the index at which to insert the object.
* @param object
* the object to add.
* @throws IndexOutOfBoundsException
* when {@code location < 0 || > size()}
*/
- @Override
- public void add(int location, E object) {
- int size = lastIndex - firstIndex;
- if (0 < location && location < size) {
- if (firstIndex == 0 && lastIndex == array.length) {
- growForInsert(location, 1);
- } else if ((location < size / 2 && firstIndex > 0)
- || lastIndex == array.length) {
- System.arraycopy(array, firstIndex, array, --firstIndex,
- location);
- } else {
- int index = location + firstIndex;
- System.arraycopy(array, index, array, index + 1, size
- - location);
- lastIndex++;
- }
- array[location + firstIndex] = object;
- } else if (location == 0) {
- if (firstIndex == 0) {
- growAtFront(1);
- }
- array[--firstIndex] = object;
- } else if (location == size) {
- if (lastIndex == array.length) {
- growAtEnd(1);
- }
- array[lastIndex++] = object;
- } else {
- throw new IndexOutOfBoundsException();
+ @Override public void add(int index, E object) {
+ Object[] a = array;
+ int s = size;
+ if (index > s) {
+ throwIndexOutOfBoundsException(index, s);
}
+ if (s < a.length) {
+ System.arraycopy(a, index, a, index + 1, s - index);
+ } else {
+ // assert s == a.length;
+ Object[] newArray = new Object[newCapacity(s)];
+ System.arraycopy(a, 0, newArray, 0, index);
+ System.arraycopy(a, index, newArray, index + 1, s - index);
+ array = a = newArray;
+ }
+ a[index] = object;
+ size = s + 1;
modCount++;
}
/**
- * Adds the specified object at the end of this {@code ArrayList}.
+ * This method controls the growth of ArrayList capacities. It represents
+ * a time-space tradeoff: we don't want to grow lists too frequently
+ * (which wastes time and fragments storage), but we don't want to waste
+ * too much space in unused excess capacity.
*
- * @param object
- * the object to add.
- * @return always true
+ * NOTE: This method is inlined into {@link #add(Object)} for performance.
+ * If you change the method, change it there too!
*/
- @Override
- public boolean add(E object) {
- if (lastIndex == array.length) {
- growAtEnd(1);
- }
- array[lastIndex++] = object;
- modCount++;
- return true;
+ private static int newCapacity(int currentCapacity) {
+ int increment = (currentCapacity < (MIN_CAPACITY_INCREMENT / 2) ?
+ MIN_CAPACITY_INCREMENT : currentCapacity >> 1);
+ return currentCapacity + increment;
}
/**
- * Inserts the objects in the specified collection at the specified location
- * in this List. The objects are added in the order they are returned from
- * the collection's iterator.
+ * Adds the objects in the specified collection to this {@code ArrayList}.
*
- * @param location
- * the index at which to insert.
* @param collection
* the collection of objects.
* @return {@code true} if this {@code ArrayList} is modified, {@code false}
* otherwise.
- * @throws IndexOutOfBoundsException
- * when {@code location < 0 || > size()}
*/
- @Override
- public boolean addAll(int location, Collection<? extends E> collection) {
- int size = lastIndex - firstIndex;
- if (location < 0 || location > size) {
- throw new IndexOutOfBoundsException();
- }
- if (this == collection) {
- collection = (ArrayList)clone();
- }
- Object[] dumparray = collection.toArray();
- int growSize = dumparray.length;
- if (growSize == 0) {
+ @Override public boolean addAll(Collection<? extends E> collection) {
+ Object[] newPart = collection.toArray();
+ int newPartSize = newPart.length;
+ if (newPartSize == 0) {
return false;
}
-
- if (0 < location && location < size) {
- if (array.length - size < growSize) {
- growForInsert(location, growSize);
- } else if ((location < size / 2 && firstIndex > 0)
- || lastIndex > array.length - growSize) {
- int newFirst = firstIndex - growSize;
- if (newFirst < 0) {
- int index = location + firstIndex;
- System.arraycopy(array, index, array, index - newFirst,
- size - location);
- lastIndex -= newFirst;
- newFirst = 0;
- }
- System.arraycopy(array, firstIndex, array, newFirst, location);
- firstIndex = newFirst;
- } else {
- int index = location + firstIndex;
- System.arraycopy(array, index, array, index + growSize, size
- - location);
- lastIndex += growSize;
- }
- } else if (location == 0) {
- growAtFront(growSize);
- firstIndex -= growSize;
- } else if (location == size) {
- if (lastIndex > array.length - growSize) {
- growAtEnd(growSize);
- }
- lastIndex += growSize;
+ Object[] a = array;
+ int s = size;
+ int newSize = s + newPartSize; // If add overflows, arraycopy will fail
+ if (newSize > a.length) {
+ int newCapacity = newCapacity(newSize - 1); // ~33% growth room
+ Object[] newArray = new Object[newCapacity];
+ System.arraycopy(a, 0, newArray, 0, s);
+ array = a = newArray;
}
-
- System.arraycopy(dumparray, 0, this.array, location + firstIndex,
- growSize);
+ System.arraycopy(newPart, 0, a, s, newPartSize);
+ size = newSize;
modCount++;
return true;
}
/**
- * Adds the objects in the specified collection to this {@code ArrayList}.
+ * Inserts the objects in the specified collection at the specified location
+ * in this List. The objects are added in the order they are returned from
+ * the collection's iterator.
*
+ * @param index
+ * the index at which to insert.
* @param collection
* the collection of objects.
* @return {@code true} if this {@code ArrayList} is modified, {@code false}
* otherwise.
+ * @throws IndexOutOfBoundsException
+ * when {@code location < 0 || > size()}
*/
@Override
- public boolean addAll(Collection<? extends E> collection) {
- Object[] dumpArray = collection.toArray();
- if (dumpArray.length == 0) {
+ public boolean addAll(int index, Collection<? extends E> collection) {
+ Object[] newPart = collection.toArray();
+ int newPartSize = newPart.length;
+ if (newPartSize == 0) {
return false;
}
- if (dumpArray.length > array.length - lastIndex) {
- growAtEnd(dumpArray.length);
+ Object[] a = array;
+ int s = size;
+ if (index > s) {
+ throwIndexOutOfBoundsException(index, s);
}
- System.arraycopy(dumpArray, 0, this.array, lastIndex, dumpArray.length);
- lastIndex += dumpArray.length;
+ int newSize = s + newPartSize; // If add overflows, arraycopy will fail
+ if (newSize <= a.length) {
+ System.arraycopy(a, index, a, index + newPartSize, s - index);
+ } else {
+ int newCapacity = newCapacity(newSize - 1); // ~33% growth room
+ Object[] newArray = new Object[newCapacity];
+ System.arraycopy(a, 0, newArray, 0, index);
+ System.arraycopy(a, index, newArray, index + newPartSize, s-index);
+ array = a = newArray;
+ }
+ System.arraycopy(newPart, 0, a, index, newPartSize);
+ size = newSize;
modCount++;
return true;
}
+ /** This method was extracted to encourage VM to inline callers. */
+ private static void throwIndexOutOfBoundsException(int index, int size) {
+ throw new IndexOutOfBoundsException("Invalid index " + index
+ + ", size is " + size);
+ }
+
/**
* Removes all elements from this {@code ArrayList}, leaving it empty.
*
* @see #isEmpty
* @see #size
*/
- @Override
- public void clear() {
- if (firstIndex != lastIndex) {
- Arrays.fill(array, firstIndex, lastIndex, null);
- firstIndex = lastIndex = 0;
+ @Override public void clear() {
+ if (size != 0) {
+ Arrays.fill(array, 0, size, null);
+ size = 0;
modCount++;
}
}
@@ -276,45 +271,17 @@ public class ArrayList<E> extends AbstractList<E> implements List<E>,
* @return a shallow copy of this {@code ArrayList}
* @see java.lang.Cloneable
*/
- @Override
- @SuppressWarnings("unchecked")
- public Object clone() {
+ @Override public Object clone() {
try {
- ArrayList<E> newList = (ArrayList<E>) super.clone();
- newList.array = array.clone();
- return newList;
+ ArrayList<?> result = (ArrayList<?>) super.clone();
+ result.array = array.clone();
+ return result;
} catch (CloneNotSupportedException e) {
- return null;
+ throw new AssertionError();
}
}
/**
- * Searches this {@code ArrayList} for the specified object.
- *
- * @param object
- * the object to search for.
- * @return {@code true} if {@code object} is an element of this
- * {@code ArrayList}, {@code false} otherwise
- */
- @Override
- public boolean contains(Object object) {
- if (object != null) {
- for (int i = firstIndex; i < lastIndex; i++) {
- if (object.equals(array[i])) {
- return true;
- }
- }
- } else {
- for (int i = firstIndex; i < lastIndex; i++) {
- if (array[i] == null) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
* Ensures that after this operation the {@code ArrayList} can hold the
* specified number of elements without further growing.
*
@@ -322,145 +289,93 @@ public class ArrayList<E> extends AbstractList<E> implements List<E>,
* the minimum capacity asked for.
*/
public void ensureCapacity(int minimumCapacity) {
- if (array.length < minimumCapacity) {
- if (firstIndex > 0) {
- growAtFront(minimumCapacity - array.length);
- } else {
- growAtEnd(minimumCapacity - array.length);
- }
+ Object[] a = array;
+ if (a.length < minimumCapacity) {
+ Object[] newArray = new Object[minimumCapacity];
+ System.arraycopy(a, 0, newArray, 0, size);
+ array = newArray;
+ modCount++;
}
}
- @Override
- public E get(int location) {
- // BEGIN android-changed: slight performance improvement
- int _firstIndex = firstIndex;
- if (0 <= location && location < lastIndex - _firstIndex) {
- return array[_firstIndex + location];
- }
- throw new IndexOutOfBoundsException("Invalid location " + location
- + ", size is " + (lastIndex - _firstIndex));
- // END android-changed
+ @SuppressWarnings("unchecked") @Override public E get(int index) {
+ if (index >= size) {
+ throwIndexOutOfBoundsException(index, size);
+ }
+ return (E) array[index];
}
- private void growAtEnd(int required) {
- int size = lastIndex - firstIndex;
- if (firstIndex >= required - (array.length - lastIndex)) {
- int newLast = lastIndex - firstIndex;
- if (size > 0) {
- System.arraycopy(array, firstIndex, array, 0, size);
- int start = newLast < firstIndex ? firstIndex : newLast;
- Arrays.fill(array, start, array.length, null);
- }
- firstIndex = 0;
- lastIndex = newLast;
- } else {
- int increment = size / 2;
- if (required > increment) {
- increment = required;
- }
- if (increment < 12) {
- increment = 12;
- }
- E[] newArray = newElementArray(size + increment);
- if (size > 0) {
- System.arraycopy(array, firstIndex, newArray, 0, size);
- firstIndex = 0;
- lastIndex = size;
- }
- array = newArray;
- }
+ /**
+ * Returns the number of elements in this {@code ArrayList}.
+ *
+ * @return the number of elements in this {@code ArrayList}.
+ */
+ @Override public int size() {
+ return size;
+ }
+
+ @Override public boolean isEmpty() {
+ return size == 0;
}
- private void growAtFront(int required) {
- int size = lastIndex - firstIndex;
- if (array.length - lastIndex + firstIndex >= required) {
- int newFirst = array.length - size;
- if (size > 0) {
- System.arraycopy(array, firstIndex, array, newFirst, size);
- int length = firstIndex + size > newFirst ? newFirst
- : firstIndex + size;
- Arrays.fill(array, firstIndex, length, null);
+ /**
+ * Searches this {@code ArrayList} for the specified object.
+ *
+ * @param object
+ * the object to search for.
+ * @return {@code true} if {@code object} is an element of this
+ * {@code ArrayList}, {@code false} otherwise
+ */
+ @Override public boolean contains(Object object) {
+ Object[] a = array;
+ int s = size;
+ if (object != null) {
+ for (int i = 0; i < s; i++) {
+ if (object.equals(a[i])) {
+ return true;
+ }
}
- firstIndex = newFirst;
- lastIndex = array.length;
} else {
- int increment = size / 2;
- if (required > increment) {
- increment = required;
- }
- if (increment < 12) {
- increment = 12;
- }
- E[] newArray = newElementArray(size + increment);
- if (size > 0) {
- System.arraycopy(array, firstIndex, newArray, newArray.length
- - size, size);
+ for (int i = 0; i < s; i++) {
+ if (a[i] == null) {
+ return true;
+ }
}
- firstIndex = newArray.length - size;
- lastIndex = newArray.length;
- array = newArray;
}
+ return false;
}
- private void growForInsert(int location, int required) {
- int size = lastIndex - firstIndex;
- int increment = size / 2;
- if (required > increment) {
- increment = required;
- }
- if (increment < 12) {
- increment = 12;
- }
- E[] newArray = newElementArray(size + increment);
- int newFirst = increment - required;
- // Copy elements after location to the new array skipping inserted
- // elements
- System.arraycopy(array, location + firstIndex, newArray, newFirst
- + location + required, size - location);
- // Copy elements before location to the new array from firstIndex
- System.arraycopy(array, firstIndex, newArray, newFirst, location);
- firstIndex = newFirst;
- lastIndex = size + increment;
-
- array = newArray;
- }
-
- @Override
- public int indexOf(Object object) {
+ @Override public int indexOf(Object object) {
+ Object[] a = array;
+ int s = size;
if (object != null) {
- for (int i = firstIndex; i < lastIndex; i++) {
- if (object.equals(array[i])) {
- return i - firstIndex;
+ for (int i = 0; i < s; i++) {
+ if (object.equals(a[i])) {
+ return i;
}
}
} else {
- for (int i = firstIndex; i < lastIndex; i++) {
- if (array[i] == null) {
- return i - firstIndex;
+ for (int i = 0; i < s; i++) {
+ if (a[i] == null) {
+ return i;
}
}
}
return -1;
}
- @Override
- public boolean isEmpty() {
- return lastIndex == firstIndex;
- }
-
- @Override
- public int lastIndexOf(Object object) {
+ @Override public int lastIndexOf(Object object) {
+ Object[] a = array;
if (object != null) {
- for (int i = lastIndex - 1; i >= firstIndex; i--) {
- if (object.equals(array[i])) {
- return i - firstIndex;
+ for (int i = size - 1; i >= 0; i--) {
+ if (object.equals(a[i])) {
+ return i;
}
}
} else {
- for (int i = lastIndex - 1; i >= firstIndex; i--) {
- if (array[i] == null) {
- return i - firstIndex;
+ for (int i = size - 1; i >= 0; i--) {
+ if (a[i] == null) {
+ return i;
}
}
}
@@ -470,99 +385,81 @@ public class ArrayList<E> extends AbstractList<E> implements List<E>,
/**
* Removes the object at the specified location from this list.
*
- * @param location
+ * @param index
* the index of the object to remove.
* @return the removed object.
* @throws IndexOutOfBoundsException
* when {@code location < 0 || >= size()}
*/
- @Override
- public E remove(int location) {
- E result;
- int size = lastIndex - firstIndex;
- if (0 <= location && location < size) {
- if (location == size - 1) {
- result = array[--lastIndex];
- array[lastIndex] = null;
- } else if (location == 0) {
- result = array[firstIndex];
- array[firstIndex++] = null;
- } else {
- int elementIndex = firstIndex + location;
- result = array[elementIndex];
- if (location < size / 2) {
- System.arraycopy(array, firstIndex, array, firstIndex + 1,
- location);
- array[firstIndex++] = null;
- } else {
- System.arraycopy(array, elementIndex + 1, array,
- elementIndex, size - location - 1);
- array[--lastIndex] = null;
- }
- }
- if (firstIndex == lastIndex) {
- firstIndex = lastIndex = 0;
- }
- } else {
- throw new IndexOutOfBoundsException();
+ @Override public E remove(int index) {
+ Object[] a = array;
+ int s = size;
+ if (index >= s) {
+ throwIndexOutOfBoundsException(index, s);
}
-
+ @SuppressWarnings("unchecked") E result = (E) a[index];
+ System.arraycopy(a, index + 1, a, index, --s - index);
+ a[s] = null; // Prevent memory leak
+ size = s;
modCount++;
return result;
}
- @Override
- public boolean remove(Object object) {
- int location = indexOf(object);
- if (location >= 0) {
- remove(location);
- return true;
+ @Override public boolean remove(Object object) {
+ Object[] a = array;
+ int s = size;
+ if (object != null) {
+ for (int i = 0; i < s; i++) {
+ if (object.equals(a[i])) {
+ System.arraycopy(a, i + 1, a, i, --s - i);
+ a[s] = null; // Prevent memory leak
+ size = s;
+ modCount++;
+ return true;
+ }
+ }
+ } else {
+ for (int i = 0; i < s; i++) {
+ if (a[i] == null) {
+ System.arraycopy(a, i + 1, a, i, --s - i);
+ a[s] = null; // Prevent memory leak
+ size = s;
+ modCount++;
+ return true;
+ }
+ }
}
return false;
}
- /**
- * Removes the objects in the specified range from the start to the end, but
- * not including the end index.
- *
- * @param start
- * the index at which to start removing.
- * @param end
- * the index one after the end of the range to remove.
- * @throws IndexOutOfBoundsException
- * when {@code start < 0, start > end} or {@code end > size()}
- */
- @Override
- protected void removeRange(int start, int end) {
- if (start >= 0 && start <= end && end <= (lastIndex - firstIndex)) {
- if (start == end) {
- return;
- }
- int size = lastIndex - firstIndex;
- if (end == size) {
- Arrays.fill(array, firstIndex + start, lastIndex, null);
- lastIndex = firstIndex + start;
- } else if (start == 0) {
- Arrays.fill(array, firstIndex, firstIndex + end, null);
- firstIndex += end;
- } else {
- System.arraycopy(array, firstIndex + end, array, firstIndex
- + start, size - end);
- int newLast = lastIndex + start - end;
- Arrays.fill(array, newLast, lastIndex, null);
- lastIndex = newLast;
- }
- modCount++;
- } else {
- throw new IndexOutOfBoundsException();
+ @Override protected void removeRange(int fromIndex, int toIndex) {
+ Object[] a = array;
+ int s = size;
+ if (fromIndex >= s) {
+ throw new IndexOutOfBoundsException("fromIndex " + fromIndex
+ + " >= size " + size);
}
+ if (toIndex > s) {
+ throw new IndexOutOfBoundsException("toIndex " + toIndex
+ + " > size " + size);
+ }
+ if (fromIndex > toIndex) {
+ throw new IndexOutOfBoundsException("fromIndex " + fromIndex
+ + " > toIndex " + toIndex);
+ }
+
+ System.arraycopy(a, toIndex, a, fromIndex, s - toIndex);
+ int rangeSize = toIndex - fromIndex;
+ Arrays.fill(a, s - rangeSize, s, null);
+ size = s - rangeSize;
+ modCount++;
}
/**
* Replaces the element at the specified location in this {@code ArrayList}
* with the specified object.
*
- * @param location
+ * @param index
* the index at which to put the specified object.
* @param object
* the object to add.
@@ -570,24 +467,14 @@ public class ArrayList<E> extends AbstractList<E> implements List<E>,
* @throws IndexOutOfBoundsException
* when {@code location < 0 || >= size()}
*/
- @Override
- public E set(int location, E object) {
- if (0 <= location && location < (lastIndex - firstIndex)) {
- E result = array[firstIndex + location];
- array[firstIndex + location] = object;
- return result;
+ @Override public E set(int index, E object) {
+ Object[] a = array;
+ if (index >= size) {
+ throwIndexOutOfBoundsException(index, size);
}
- throw new IndexOutOfBoundsException();
- }
-
- /**
- * Returns the number of elements in this {@code ArrayList}.
- *
- * @return the number of elements in this {@code ArrayList}.
- */
- @Override
- public int size() {
- return lastIndex - firstIndex;
+ @SuppressWarnings("unchecked") E result = (E) a[index];
+ a[index] = object;
+ return result;
}
/**
@@ -596,11 +483,10 @@ public class ArrayList<E> extends AbstractList<E> implements List<E>,
*
* @return an array of the elements from this {@code ArrayList}
*/
- @Override
- public Object[] toArray() {
- int size = lastIndex - firstIndex;
- Object[] result = new Object[size];
- System.arraycopy(array, firstIndex, result, 0, size);
+ @Override public Object[] toArray() {
+ int s = size;
+ Object[] result = new Object[s];
+ System.arraycopy(array, 0, result, 0, s);
return result;
}
@@ -619,17 +505,16 @@ public class ArrayList<E> extends AbstractList<E> implements List<E>,
* when the type of an element in this {@code ArrayList} cannot
* be stored in the type of the specified array.
*/
- @Override
- @SuppressWarnings("unchecked")
- public <T> T[] toArray(T[] contents) {
- int size = lastIndex - firstIndex;
- if (size > contents.length) {
- Class<?> ct = contents.getClass().getComponentType();
- contents = (T[]) Array.newInstance(ct, size);
+ @Override public <T> T[] toArray(T[] contents) {
+ int s = size;
+ if (contents.length < s) {
+ @SuppressWarnings("unchecked") T[] newArray
+ = (T[]) Array.newInstance(contents.getClass().getComponentType(), s);
+ contents = newArray;
}
- System.arraycopy(array, firstIndex, contents, 0, size);
- if (size < contents.length) {
- contents[size] = null;
+ System.arraycopy(this.array, 0, contents, 0, s);
+ if (contents.length > s) {
+ contents[s] = null;
}
return contents;
}
@@ -641,37 +526,132 @@ public class ArrayList<E> extends AbstractList<E> implements List<E>,
* @see #size
*/
public void trimToSize() {
- int size = lastIndex - firstIndex;
- E[] newArray = newElementArray(size);
- System.arraycopy(array, firstIndex, newArray, 0, size);
- array = newArray;
- firstIndex = 0;
- lastIndex = array.length;
- modCount = 0;
+ int s = size;
+ if (s == array.length) {
+ return;
+ }
+ if (s == 0) {
+ array = EMPTY_OBJECT_ARRAY;
+ } else {
+ Object[] newArray = new Object[s];
+ System.arraycopy(array, 0, newArray, 0, s);
+ array = newArray;
+ }
+ modCount++;
+ }
+
+ @Override public Iterator<E> iterator() {
+ return new ArrayListIterator();
+ }
+
+ private class ArrayListIterator implements Iterator<E> {
+ /** Number of elements remaining in this iteration */
+ private int remaining = size;
+
+ /** Index of element that remove() would remove, or -1 if no such elt */
+ private int removalIndex = -1;
+
+ /** The expected modCount value */
+ private int expectedModCount = modCount;
+
+ public boolean hasNext() {
+ return remaining != 0;
+ }
+
+ @SuppressWarnings("unchecked") public E next() {
+ ArrayList<E> ourList = ArrayList.this;
+ int rem = remaining;
+ if (ourList.modCount != expectedModCount) {
+ throw new ConcurrentModificationException();
+ }
+ if (rem == 0) {
+ throw new NoSuchElementException();
+ }
+ remaining = rem - 1;
+ return (E) ourList.array[removalIndex = ourList.size - rem];
+ }
+
+ public void remove() {
+ Object[] a = array;
+ int removalIdx = removalIndex;
+ if (modCount != expectedModCount) {
+ throw new ConcurrentModificationException();
+ }
+ if (removalIdx < 0) {
+ throw new IllegalStateException();
+ }
+ System.arraycopy(a, removalIdx + 1, a, removalIdx, remaining);
+ a[--size] = null; // Prevent memory leak
+ removalIndex = -1;
+ expectedModCount = ++modCount;
+ }
}
- private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField(
- "size", Integer.TYPE) }; //$NON-NLS-1$
+ @Override public int hashCode() {
+ Object[] a = array;
+ int hashCode = 1;
+ for (int i = 0, s = size; i < s; i++) {
+ Object e = a[i];
+ hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode());
+ }
+ return hashCode;
+ }
+
+ @Override public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof List)) {
+ return false;
+ }
+ List<?> that = (List<?>) o;
+ int s = size;
+ if (that.size() != s) {
+ return false;
+ }
+ Object[] a = array;
+ if (that instanceof RandomAccess) {
+ for (int i = 0; i < s; i++) {
+ Object eThis = a[i];
+ Object ethat = that.get(i);
+ if (eThis == null ? ethat != null : !eThis.equals(ethat)) {
+ return false;
+ }
+ }
+ } else { // Argument list is not random access; use its iterator
+ Iterator<?> it = that.iterator();
+ for (int i = 0; i < s; i++) {
+ Object eThis = a[i];
+ Object eThat = it.next();
+ if (eThis == null ? eThat != null : !eThis.equals(eThat)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private static final long serialVersionUID = 8683452581122892189L;
private void writeObject(ObjectOutputStream stream) throws IOException {
- ObjectOutputStream.PutField fields = stream.putFields();
- fields.put("size", lastIndex - firstIndex); //$NON-NLS-1$
- stream.writeFields();
+ stream.defaultWriteObject();
stream.writeInt(array.length);
- Iterator<?> it = iterator();
- while (it.hasNext()) {
- stream.writeObject(it.next());
+ for (int i = 0; i < size; i++) {
+ stream.writeObject(array[i]);
}
}
- @SuppressWarnings("unchecked")
private void readObject(ObjectInputStream stream) throws IOException,
ClassNotFoundException {
- ObjectInputStream.GetField fields = stream.readFields();
- lastIndex = fields.get("size", 0); //$NON-NLS-1$
- array = newElementArray(stream.readInt());
- for (int i = 0; i < lastIndex; i++) {
- array[i] = (E) stream.readObject();
+ stream.defaultReadObject();
+ int cap = stream.readInt();
+ if (cap < size) {
+ throw new InvalidObjectException(
+ "Capacity: " + cap + " < size: " + size);
+ }
+ array = (cap == 0 ? EMPTY_OBJECT_ARRAY : new Object[cap]);
+ for (int i = 0; i < size; i++) {
+ array[i] = stream.readObject();
}
}
-}
+ }
diff --git a/luni/src/main/java/java/util/Formatter.java b/luni/src/main/java/java/util/Formatter.java
index d1dd417..3d8b94e 100644
--- a/luni/src/main/java/java/util/Formatter.java
+++ b/luni/src/main/java/java/util/Formatter.java
@@ -885,7 +885,6 @@ public final class Formatter implements Closeable, Flushable {
if (transformer == null || ! transformer.locale.equals(l)) {
transformer = new Transformer(this, l);
}
- // END android-changed
int currentObjectIndex = 0;
Object lastArgument = null;
@@ -893,12 +892,13 @@ public final class Formatter implements Closeable, Flushable {
while (formatBuffer.hasRemaining()) {
parser.reset();
FormatToken token = parser.getNextFormatToken();
- String result;
String plainText = token.getPlainText();
if (token.getConversionType() == (char) FormatToken.UNSET) {
- result = plainText;
+ outputCharSequence(plainText);
} else {
plainText = plainText.substring(0, plainText.indexOf('%'));
+ outputCharSequence(plainText);
+
Object argument = null;
if (token.requireArgument()) {
int index = token.getArgIndex() == FormatToken.UNSET ? currentObjectIndex++
@@ -908,21 +908,26 @@ public final class Formatter implements Closeable, Flushable {
lastArgument = argument;
hasLastArgumentSet = true;
}
- result = transformer.transform(token, argument);
- result = (null == result ? plainText : plainText + result);
- }
- // if output is made by formattable callback
- if (null != result) {
- try {
- out.append(result);
- } catch (IOException e) {
- lastIOException = e;
- }
+ outputCharSequence(transformer.transform(token, argument));
}
}
+ // END android-changed
return this;
}
+ // BEGIN android-added
+ // Fixes http://code.google.com/p/android/issues/detail?id=1767.
+ private void outputCharSequence(CharSequence cs) {
+ if (cs != null) {
+ try {
+ out.append(cs);
+ } catch (IOException e) {
+ lastIOException = e;
+ }
+ }
+ }
+ // END android-added
+
private Object getArgument(Object[] args, int index, FormatToken token,
Object lastArgument, boolean hasLastArgumentSet) {
if (index == FormatToken.LAST_ARGUMENT_INDEX && !hasLastArgumentSet) {
@@ -1184,13 +1189,13 @@ public final class Formatter implements Closeable, Flushable {
* Gets the formatted string according to the format token and the
* argument.
*/
- String transform(FormatToken token, Object argument) {
+ CharSequence transform(FormatToken token, Object argument) {
/* init data member to print */
this.formatToken = token;
this.arg = argument;
- String result;
+ CharSequence result;
switch (token.getConversionType()) {
case 'B':
case 'b': {
@@ -1254,7 +1259,7 @@ public final class Formatter implements Closeable, Flushable {
if (Character.isUpperCase(token.getConversionType())) {
if (null != result) {
- result = result.toUpperCase(Locale.US);
+ result = result.toString().toUpperCase(Locale.US);
}
}
return result;
@@ -1263,7 +1268,7 @@ public final class Formatter implements Closeable, Flushable {
/*
* Transforms the Boolean argument to a formatted string.
*/
- private String transformFromBoolean() {
+ private CharSequence transformFromBoolean() {
StringBuilder result = new StringBuilder();
int startIndex = 0;
int flags = formatToken.getFlags();
@@ -1294,7 +1299,7 @@ public final class Formatter implements Closeable, Flushable {
/*
* Transforms the hashcode of the argument to a formatted string.
*/
- private String transformFromHashCode() {
+ private CharSequence transformFromHashCode() {
StringBuilder result = new StringBuilder();
int startIndex = 0;
@@ -1324,7 +1329,7 @@ public final class Formatter implements Closeable, Flushable {
/*
* Transforms the String to a formatted string.
*/
- private String transformFromString() {
+ private CharSequence transformFromString() {
StringBuilder result = new StringBuilder();
int startIndex = 0;
int flags = formatToken.getFlags();
@@ -1374,7 +1379,7 @@ public final class Formatter implements Closeable, Flushable {
/*
* Transforms the Character to a formatted string.
*/
- private String transformFromCharacter() {
+ private CharSequence transformFromCharacter() {
StringBuilder result = new StringBuilder();
int startIndex = 0;
@@ -1434,7 +1439,7 @@ public final class Formatter implements Closeable, Flushable {
* Transforms percent to a formatted string. Only '-' is legal flag.
* Precision is illegal.
*/
- private String transformFromPercent() {
+ private CharSequence transformFromPercent() {
StringBuilder result = new StringBuilder("%"); //$NON-NLS-1$
int startIndex = 0;
@@ -1462,7 +1467,7 @@ public final class Formatter implements Closeable, Flushable {
* Transforms line separator to a formatted string. Any flag, the width
* or the precision is illegal.
*/
- private String transformFromLineSeparator() {
+ private CharSequence transformFromLineSeparator() {
if (formatToken.isPrecisionSet()) {
throw new IllegalFormatPrecisionException(formatToken
.getPrecision());
@@ -1492,7 +1497,7 @@ public final class Formatter implements Closeable, Flushable {
/*
* Pads characters to the formatted string.
*/
- private String padding(StringBuilder source, int startIndex) {
+ private CharSequence padding(StringBuilder source, int startIndex) {
int start = startIndex;
boolean paddingRight = formatToken
.isFlagSet(FormatToken.FLAG_MINUS);
@@ -1520,7 +1525,7 @@ public final class Formatter implements Closeable, Flushable {
width = Math.max(source.length(), width);
}
if (length >= width) {
- return source.toString();
+ return source;
}
char[] paddings = new char[width - length];
@@ -1532,13 +1537,13 @@ public final class Formatter implements Closeable, Flushable {
} else {
source.insert(start, insertString);
}
- return source.toString();
+ return source;
}
/*
* Transforms the Integer to a formatted string.
*/
- private String transformFromInteger() {
+ private CharSequence transformFromInteger() {
int startIndex = 0;
boolean isNegative = false;
StringBuilder result = new StringBuilder();
@@ -1651,7 +1656,7 @@ public final class Formatter implements Closeable, Flushable {
if (isNegative
&& formatToken.isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
result = wrapParentheses(result);
- return result.toString();
+ return result;
}
if (isNegative && formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
@@ -1680,7 +1685,7 @@ public final class Formatter implements Closeable, Flushable {
return result;
}
- private String transformFromSpecialNumber() {
+ private CharSequence transformFromSpecialNumber() {
String source = null;
if (!(arg instanceof Number) || arg instanceof BigDecimal) {
@@ -1713,12 +1718,12 @@ public final class Formatter implements Closeable, Flushable {
formatToken.setPrecision(FormatToken.UNSET);
formatToken.setFlags(formatToken.getFlags()
& (~FormatToken.FLAG_ZERO));
- source = padding(new StringBuilder(source), 0);
+ return padding(new StringBuilder(source), 0);
}
return source;
}
- private String transformFromNull() {
+ private CharSequence transformFromNull() {
formatToken.setFlags(formatToken.getFlags()
& (~FormatToken.FLAG_ZERO));
return padding(new StringBuilder("null"), 0); //$NON-NLS-1$
@@ -1727,7 +1732,7 @@ public final class Formatter implements Closeable, Flushable {
/*
* Transforms a BigInteger to a formatted string.
*/
- private String transformFromBigInteger() {
+ private CharSequence transformFromBigInteger() {
int startIndex = 0;
boolean isNegative = false;
StringBuilder result = new StringBuilder();
@@ -1817,7 +1822,7 @@ public final class Formatter implements Closeable, Flushable {
if (isNegative
&& formatToken.isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
result = wrapParentheses(result);
- return result.toString();
+ return result;
}
if (isNegative && formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
@@ -1829,7 +1834,7 @@ public final class Formatter implements Closeable, Flushable {
/*
* Transforms a Float,Double or BigDecimal to a formatted string.
*/
- private String transformFromFloat() {
+ private CharSequence transformFromFloat() {
StringBuilder result = new StringBuilder();
int startIndex = 0;
char currentConversionType = formatToken.getConversionType();
@@ -1883,7 +1888,7 @@ public final class Formatter implements Closeable, Flushable {
currentConversionType, arg.getClass());
}
- String specialNumberResult = transformFromSpecialNumber();
+ CharSequence specialNumberResult = transformFromSpecialNumber();
if (null != specialNumberResult) {
return specialNumberResult;
}
@@ -1896,7 +1901,7 @@ public final class Formatter implements Closeable, Flushable {
}
// output result
FloatUtil floatUtil = new FloatUtil(result, formatToken,
- (DecimalFormat) NumberFormat.getInstance(locale), arg);
+ (DecimalFormat) getNumberFormat(), arg);
floatUtil.transform(formatToken, result);
formatToken.setPrecision(FormatToken.UNSET);
@@ -1904,7 +1909,7 @@ public final class Formatter implements Closeable, Flushable {
if (getDecimalFormatSymbols().getMinusSign() == result.charAt(0)) {
if (formatToken.isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
result = wrapParentheses(result);
- return result.toString();
+ return result;
}
} else {
if (formatToken.isFlagSet(FormatToken.FLAG_SPACE)) {
@@ -1933,7 +1938,7 @@ public final class Formatter implements Closeable, Flushable {
/*
* Transforms a Date to a formatted string.
*/
- private String transformFromDateTime() {
+ private CharSequence transformFromDateTime() {
int startIndex = 0;
char currentConversionType = formatToken.getConversionType();
diff --git a/luni/src/main/java/java/util/HashMap.java b/luni/src/main/java/java/util/HashMap.java
index 28978d4..f79601f 100644
--- a/luni/src/main/java/java/util/HashMap.java
+++ b/luni/src/main/java/java/util/HashMap.java
@@ -36,7 +36,7 @@ import java.io.Serializable;
* @param <V> the type of mapped values
*/
public class HashMap<K, V> extends AbstractMap<K, V>
- implements Cloneable, Serializable, Map<K, V> {
+ implements Cloneable, Serializable {
/**
* Min capacity (other than zero) for a HashMap. Must be a power of two
* greater than 1 (and less than 1 << 30).
diff --git a/luni/src/main/java/org/apache/harmony/luni/internal/util/ZoneInfo.java b/luni/src/main/java/org/apache/harmony/luni/internal/util/ZoneInfo.java
index 110a0fd..01319e1 100644
--- a/luni/src/main/java/org/apache/harmony/luni/internal/util/ZoneInfo.java
+++ b/luni/src/main/java/org/apache/harmony/luni/internal/util/ZoneInfo.java
@@ -111,12 +111,23 @@ public class ZoneInfo extends TimeZone {
// Subtract the raw offset from all offsets so it can be changed
// and affect them too.
- // Find whether there exist any observances of DST.
-
for (int i = 0; i < mGmtOffs.length; i++) {
mGmtOffs[i] -= mRawOffset;
+ }
- if (mIsDsts[i] != 0) {
+ // Is this zone still observing DST?
+ // We don't care if they've historically used it: most places have at least once.
+ // We want to know whether the last "schedule info" (the unix times in the mTransitions
+ // array) is in the future. If it is, DST is still relevant.
+ // See http://code.google.com/p/android/issues/detail?id=877.
+ // This test means that for somewhere like Morocco, which tried DST in 2009 but has
+ // no future plans (and thus no future schedule info) will report "true" from
+ // useDaylightTime at the start of 2009 but "false" at the end. This seems appropriate.
+ long currentUnixTime = System.currentTimeMillis() / 1000;
+ if (mTransitions.length > 0) {
+ // (We're really dealing with uint32_t values, so long is most convenient in Java.)
+ long latestScheduleTime = mTransitions[mTransitions.length - 1] & 0xffffffff;
+ if (currentUnixTime < latestScheduleTime) {
mUseDst = true;
}
}
diff --git a/luni/src/main/java/org/apache/harmony/luni/platform/IFileSystem.java b/luni/src/main/java/org/apache/harmony/luni/platform/IFileSystem.java
index 7613f0e..bee1557 100644
--- a/luni/src/main/java/org/apache/harmony/luni/platform/IFileSystem.java
+++ b/luni/src/main/java/org/apache/harmony/luni/platform/IFileSystem.java
@@ -108,10 +108,9 @@ public interface IFileSystem {
// BEGIN android-deleted
// public long ttyAvailable() throws IOException;
+ // public long ttyRead(byte[] bytes, int offset, int length) throws IOException;
// END android-deleted
- public long ttyRead(byte[] bytes, int offset, int length) throws IOException;
-
// BEGIN android-added
public int ioctlAvailable(int fileDescriptor) throws IOException;
// END android-added
diff --git a/luni/src/main/java/org/apache/harmony/luni/platform/OSFileSystem.java b/luni/src/main/java/org/apache/harmony/luni/platform/OSFileSystem.java
index 08bdac6..b7a62e2 100644
--- a/luni/src/main/java/org/apache/harmony/luni/platform/OSFileSystem.java
+++ b/luni/src/main/java/org/apache/harmony/luni/platform/OSFileSystem.java
@@ -69,7 +69,7 @@ class OSFileSystem implements IFileSystem {
* Note that this value for Windows differs from the one for the
* page size (64K and 4K respectively).
*/
- public native int getAllocGranularity() throws IOException;
+ public native int getAllocGranularity();
public boolean lock(int fileDescriptor, long start, long length, int type,
boolean waitFlag) throws IOException {
@@ -79,160 +79,71 @@ class OSFileSystem implements IFileSystem {
return result != -1;
}
- private native int unlockImpl(int fileDescriptor, long start, long length);
+ // BEGIN android-changed
+ private native void unlockImpl(int fileDescriptor, long start, long length) throws IOException;
public void unlock(int fileDescriptor, long start, long length)
throws IOException {
// Validate arguments
validateLockArgs(IFileSystem.SHARED_LOCK_TYPE, start, length);
- int result = unlockImpl(fileDescriptor, start, length);
- if (result == -1) {
- throw new IOException();
- }
+ unlockImpl(fileDescriptor, start, length);
}
- private native int fflushImpl(int fd, boolean metadata);
-
- public void fflush(int fileDescriptor, boolean metadata)
- throws IOException {
- int result = fflushImpl(fileDescriptor, metadata);
- if (result == -1) {
- throw new IOException();
- }
- }
+ public native void fflush(int fileDescriptor, boolean metadata) throws IOException;
/*
* File position seeking.
*/
-
- private native long seekImpl(int fd, long offset, int whence);
-
- public long seek(int fileDescriptor, long offset, int whence)
- throws IOException {
- long pos = seekImpl(fileDescriptor, offset, whence);
- if (pos == -1) {
- throw new IOException();
- }
- return pos;
- }
+ public native long seek(int fd, long offset, int whence) throws IOException;
/*
* Direct read/write APIs work on addresses.
*/
- private native long readDirectImpl(int fileDescriptor, int address,
- int offset, int length);
-
- public long readDirect(int fileDescriptor, int address, int offset,
- int length) throws IOException {
- long bytesRead = readDirectImpl(fileDescriptor, address, offset, length);
- if (bytesRead < -1) {
- throw new IOException();
- }
- return bytesRead;
- }
-
- private native long writeDirectImpl(int fileDescriptor, int address,
- int offset, int length);
+ public native long readDirect(int fileDescriptor, int address, int offset, int length);
- public long writeDirect(int fileDescriptor, int address, int offset,
- int length) throws IOException {
- long bytesWritten = writeDirectImpl(fileDescriptor, address, offset,
- length);
- if (bytesWritten < 0) {
- throw new IOException();
- }
- return bytesWritten;
- }
+ public native long writeDirect(int fileDescriptor, int address, int offset, int length)
+ throws IOException;
/*
* Indirect read/writes work on byte[]'s
*/
private native long readImpl(int fileDescriptor, byte[] bytes, int offset,
- int length);
+ int length) throws IOException;
public long read(int fileDescriptor, byte[] bytes, int offset, int length)
throws IOException {
if (bytes == null) {
throw new NullPointerException();
}
- long bytesRead = readImpl(fileDescriptor, bytes, offset, length);
- if (bytesRead < -1) {
- /*
- * TODO: bytesRead is never less than -1 so this code
- * does nothing?
- * The native code throws an exception in only one case
- * so perhaps this should be 'bytesRead < 0' to handle
- * any other cases. But the other cases have been
- * ignored until now so fixing this could break things
- */
- throw new IOException();
- }
- return bytesRead;
+ return readImpl(fileDescriptor, bytes, offset, length);
}
private native long writeImpl(int fileDescriptor, byte[] bytes,
- int offset, int length);
+ int offset, int length) throws IOException;
public long write(int fileDescriptor, byte[] bytes, int offset, int length)
throws IOException {
- long bytesWritten = writeImpl(fileDescriptor, bytes, offset, length);
- if (bytesWritten < 0) {
- throw new IOException();
+ if (bytes == null) {
+ throw new NullPointerException();
}
- return bytesWritten;
+ return writeImpl(fileDescriptor, bytes, offset, length);
}
+ // END android-changed
/*
* Scatter/gather calls.
*/
- public long readv(int fileDescriptor, int[] addresses, int[] offsets,
- int[] lengths, int size) throws IOException {
- long bytesRead = readvImpl(fileDescriptor, addresses, offsets, lengths,
- size);
- if (bytesRead < -1) {
- throw new IOException();
- }
- return bytesRead;
- }
+ public native long readv(int fileDescriptor, int[] addresses,
+ int[] offsets, int[] lengths, int size) throws IOException;
- private native long readvImpl(int fileDescriptor, int[] addresses,
- int[] offsets, int[] lengths, int size);
+ public native long writev(int fileDescriptor, int[] addresses, int[] offsets,
+ int[] lengths, int size) throws IOException;
- public long writev(int fileDescriptor, int[] addresses, int[] offsets,
- int[] lengths, int size) throws IOException {
- long bytesWritten = writevImpl(fileDescriptor, addresses, offsets,
- lengths, size);
- if (bytesWritten < 0) {
- throw new IOException();
- }
- return bytesWritten;
- }
-
- private native long writevImpl(int fileDescriptor, int[] addresses,
- int[] offsets, int[] lengths, int size);
-
- private native int closeImpl(int fileDescriptor);
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.harmony.luni.platform.IFileSystem#close(long)
- */
- public void close(int fileDescriptor) throws IOException {
- int rc = closeImpl(fileDescriptor);
- if (rc == -1) {
- throw new IOException();
- }
- }
-
- public void truncate(int fileDescriptor, long size) throws IOException {
- int rc = truncateImpl(fileDescriptor, size);
- if (rc < 0) {
- throw new IOException();
- }
- }
+ // BEGIN android-changed
+ public native void close(int fileDescriptor) throws IOException;
- private native int truncateImpl(int fileDescriptor, long size);
+ public native void truncate(int fileDescriptor, long size) throws IOException;
+ // END android-changed
public int open(byte[] fileName, int mode) throws FileNotFoundException {
if (fileName == null) {
@@ -254,16 +165,10 @@ class OSFileSystem implements IFileSystem {
private native int openImpl(byte[] fileName, int mode);
- public long transfer(int fileHandler, FileDescriptor socketDescriptor,
- long offset, long count) throws IOException {
- long result = transferImpl(fileHandler, socketDescriptor, offset, count);
- if (result < 0)
- throw new IOException();
- return result;
- }
-
- private native long transferImpl(int fileHandler,
- FileDescriptor socketDescriptor, long offset, long count);
+ // BEGIN android-changed
+ public native long transfer(int fd, FileDescriptor sd, long offset, long count)
+ throws IOException;
+ // END android-changed
// BEGIN android-deleted
// public long ttyAvailable() throws IOException {
@@ -277,17 +182,15 @@ class OSFileSystem implements IFileSystem {
// private native long ttyAvailableImpl();
// END android-deleted
- public long ttyRead(byte[] bytes, int offset, int length) throws IOException {
- long nChar = ttyReadImpl(bytes, offset, length);
- // BEGIN android-changed
- if (nChar < -1) {
- throw new IOException();
- }
- // END android-changed
- return nChar;
- }
-
- private native long ttyReadImpl(byte[] bytes, int offset, int length);
+ // BEGIN android-deleted
+ // public long ttyRead(byte[] bytes, int offset, int length) throws IOException {
+ // if (bytes == null) {
+ // throw new NullPointerException();
+ // }
+ // return ttyReadImpl(bytes, offset, length);
+ // }
+ // private native long ttyReadImpl(byte[] bytes, int offset, int length) throws IOException;
+ // END android-deleted
// BEGIN android-added
public native int ioctlAvailable(int fileDescriptor) throws IOException;
diff --git a/luni/src/main/native/java_net_InetAddress.cpp b/luni/src/main/native/java_net_InetAddress.cpp
index d7b4931..4e58a1f 100644
--- a/luni/src/main/native/java_net_InetAddress.cpp
+++ b/luni/src/main/native/java_net_InetAddress.cpp
@@ -24,7 +24,6 @@
#include <stdio.h>
#include <string.h>
-#include <assert.h>
#include <netdb.h>
#include <errno.h>
@@ -48,19 +47,6 @@ static jstring InetAddress_gethostname(JNIEnv* env, jobject obj)
}
}
-static void throwNullPointerException(JNIEnv* env)
-{
- const char* className = "java/lang/NullPointerException";
-
- jclass exClass = env->FindClass(className);
-
- if (exClass == NULL) {
- LOGE("Unable to find class %s", className);
- } else {
- env->ThrowNew(exClass, NULL);
- }
-}
-
#if LOG_DNS
static void logIpString(struct addrinfo* ai, const char* name)
{
@@ -208,7 +194,7 @@ jobjectArray InetAddress_getallbyname(JNIEnv* env, jobject obj,
jboolean preferIPv4Stack)
{
if (javaName == NULL) {
- throwNullPointerException(env);
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
return NULL;
}
@@ -247,57 +233,44 @@ static jstring InetAddress_gethostbyaddr(JNIEnv* env, jobject obj,
jbyteArray javaAddress)
{
if (javaAddress == NULL) {
- throwNullPointerException(env);
- return NULL;
- }
-
- size_t addrlen = env->GetArrayLength(javaAddress);
- jbyte* rawAddress = env->GetByteArrayElements(javaAddress, NULL);
- if (rawAddress == NULL) {
- throwNullPointerException(env);
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
return NULL;
}
// Convert the raw address bytes into a socket address structure.
- int ret = 0;
struct sockaddr_storage ss;
- struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &ss;
- size_t socklen;
memset(&ss, 0, sizeof(ss));
- switch (addrlen) {
- case 4:
- socklen = sizeof(struct sockaddr_in);
- sin->sin_family = AF_INET;
- memcpy(&sin->sin_addr.s_addr, rawAddress, addrlen);
- env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
- break;
- case 16:
- socklen = sizeof(struct sockaddr_in6);
- sin6->sin6_family = AF_INET6;
- memcpy(&sin6->sin6_addr.s6_addr, rawAddress, addrlen);
- env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
- break;
- default:
- // The caller already throws an exception in this case. Don't worry
- // about it here.
- env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
- return NULL;
+
+ size_t socklen;
+ const size_t addressLength = env->GetArrayLength(javaAddress);
+ if (addressLength == 4) {
+ struct sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(&ss);
+ sin->sin_family = AF_INET;
+ socklen = sizeof(struct sockaddr_in);
+ jbyte* dst = reinterpret_cast<jbyte*>(&sin->sin_addr.s_addr);
+ env->GetByteArrayRegion(javaAddress, 0, 4, dst);
+ } else if (addressLength == 16) {
+ struct sockaddr_in6 *sin6 = reinterpret_cast<sockaddr_in6*>(&ss);
+ sin6->sin6_family = AF_INET6;
+ socklen = sizeof(struct sockaddr_in6);
+ jbyte* dst = reinterpret_cast<jbyte*>(&sin6->sin6_addr.s6_addr);
+ env->GetByteArrayRegion(javaAddress, 0, 16, dst);
+ } else {
+ // The caller already throws an exception in this case. Don't worry
+ // about it here.
+ return NULL;
}
// Look up the host name from the IP address.
char name[NI_MAXHOST];
- if (ret == 0) {
- ret = getnameinfo((struct sockaddr *) &ss, socklen, name, sizeof(name),
- NULL, 0, NI_NAMEREQD);
- }
-
- if (ret == 0) {
- return env->NewStringUTF(name);
+ int ret = getnameinfo(reinterpret_cast<sockaddr*>(&ss), socklen,
+ name, sizeof(name), NULL, 0, NI_NAMEREQD);
+ if (ret != 0) {
+ jniThrowException(env, "java/net/UnknownHostException", gai_strerror(ret));
+ return NULL;
}
- jniThrowException(env, "java/net/UnknownHostException", gai_strerror(ret));
- return NULL;
+ return env->NewStringUTF(name);
}
/*
diff --git a/luni/src/main/native/java_net_NetworkInterface.c b/luni/src/main/native/java_net_NetworkInterface.c
index db6d503..e994aea 100644
--- a/luni/src/main/native/java_net_NetworkInterface.c
+++ b/luni/src/main/native/java_net_NetworkInterface.c
@@ -34,27 +34,7 @@
* Throws an IOException with the given message.
*/
static void throwSocketException(JNIEnv *env, const char *message) {
- jclass exClass = (*env)->FindClass(env, "java/net/SocketException");
-
- if(exClass == NULL) {
- LOGE("Unable to find class java/net/SocketException");
- } else {
- (*env)->ThrowNew(env, exClass, message);
- }
-}
-
-
-/**
- * Throws a NullPointerException.
- */
-static void throwNullPointerException(JNIEnv *env) {
- jclass exClass = (*env)->FindClass(env, "java/lang/NullPointerException");
-
- if(exClass == NULL) {
- LOGE("Unable to find class java/lang/NullPointerException");
- } else {
- (*env)->ThrowNew(env, exClass, NULL);
- }
+ jniThrowException(env, "java/net/SocketException", message);
}
/**
@@ -241,24 +221,18 @@ static char * netLookupErrorString(int anErrorNum) {
static int structInToJavaAddress(
JNIEnv *env, struct in_addr *address, jbyteArray java_address) {
- if(java_address == NULL) {
- throwNullPointerException(env);
+ if (java_address == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
return -1;
}
- if((*env)->GetArrayLength(env, java_address) != sizeof(address->s_addr)) {
+ if ((*env)->GetArrayLength(env, java_address) != sizeof(address->s_addr)) {
jniThrowIOException(env, errno);
return -1;
}
- jbyte *java_address_bytes;
-
- java_address_bytes = (*env)->GetByteArrayElements(env, java_address, NULL);
-
- memcpy(java_address_bytes, &(address->s_addr), sizeof(address->s_addr));
-
- (*env)->ReleaseByteArrayElements(env, java_address, java_address_bytes, 0);
-
+ jbyte* src = (jbyte*)(&(address->s_addr));
+ (*env)->SetByteArrayRegion(env, java_address, 0, sizeof(address->s_addr), src);
return 0;
}
diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp
index 38f3d36..3e229d0 100644
--- a/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp
+++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp
@@ -14,401 +14,316 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+// BEGIN android-note
+// This file corresponds to harmony's OSFileSystem.c and OSFileSystemLinux32.c.
+// It has been greatly simplified by the assumption that the underlying
+// platform is always Linux.
+// END android-note
+
/*
* Common natives supporting the file system interface.
*/
#define HyMaxPath 1024
-#define HyOpenRead 1 /* Values for HyFileOpen */
+
+/* Values for HyFileOpen */
+#define HyOpenRead 1
#define HyOpenWrite 2
#define HyOpenCreate 4
#define HyOpenTruncate 8
#define HyOpenAppend 16
#define HyOpenText 32
-
/* Use this flag with HyOpenCreate, if this flag is specified then
- * trying to create an existing file will fail
+ * trying to create an existing file will fail
*/
#define HyOpenCreateNew 64
-#define HyOpenSync 128
+#define HyOpenSync 128
#define SHARED_LOCK_TYPE 1L
#include "JNIHelp.h"
#include "AndroidSystemNatives.h"
-#include <string.h>
-#include <stdio.h>
+#include <assert.h>
#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
#include <sys/sendfile.h>
#include <sys/uio.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-typedef struct socket_struct {
- int sock;
- unsigned short family;
-} socket_struct;
+// An equivalent of the glibc macro of the same name.
+// We want to hide EINTR from Java by simply retrying directly in
+// the native code. We care about all other errors, though.
+#define EINTR_RETRY(exp) ({ \
+ typeof (exp) _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1 && errno == EINTR); \
+ _rc; })
static void convertToPlatform(char *path) {
char *pathIndex;
pathIndex = path;
while (*pathIndex != '\0') {
- if(*pathIndex == '\\') {
+ if (*pathIndex == '\\') {
*pathIndex = '/';
}
pathIndex++;
}
}
-static int
-EsTranslateOpenFlags(int flags) {
+static int EsTranslateOpenFlags(int flags) {
int realFlags = 0;
- if(flags & HyOpenAppend) {
+ if (flags & HyOpenAppend) {
realFlags |= O_APPEND;
}
- if(flags & HyOpenTruncate) {
+ if (flags & HyOpenTruncate) {
realFlags |= O_TRUNC;
}
- if(flags & HyOpenCreate) {
+ if (flags & HyOpenCreate) {
realFlags |= O_CREAT;
}
- if(flags & HyOpenCreateNew) {
+ if (flags & HyOpenCreateNew) {
realFlags |= O_EXCL | O_CREAT;
}
#ifdef O_SYNC
- if(flags & HyOpenSync) {
- realFlags |= O_SYNC;
- }
-#endif
- if(flags & HyOpenRead) {
- if(flags & HyOpenWrite) {
+ if (flags & HyOpenSync) {
+ realFlags |= O_SYNC;
+ }
+#endif
+ if (flags & HyOpenRead) {
+ if (flags & HyOpenWrite) {
return (O_RDWR | realFlags);
}
return (O_RDONLY | realFlags);
}
- if(flags & HyOpenWrite) {
+ if (flags & HyOpenWrite) {
return (O_WRONLY | realFlags);
}
return -1;
}
-/**
- * Lock the file identified by the given handle.
- * The range and lock type are given.
- */
-static jint harmony_io_lockImpl(JNIEnv * env, jobject thiz, jint handle,
- jlong start, jlong length, jint typeFlag, jboolean waitFlag) {
+// Checks whether we can safely treat the given jlong as an off_t without
+// accidental loss of precision.
+// TODO: this is bogus; we should use _FILE_OFFSET_BITS=64.
+static bool offsetTooLarge(JNIEnv* env, jlong longOffset) {
+ if (sizeof(off_t) >= sizeof(jlong)) {
+ // We're only concerned about the possibility that off_t is
+ // smaller than jlong. off_t is signed, so we don't need to
+ // worry about signed/unsigned.
+ return false;
+ }
- int rc;
- int waitMode = (waitFlag) ? F_SETLKW : F_SETLK;
- struct flock lock;
+ // TODO: use std::numeric_limits<off_t>::max() and min() when we have them.
+ assert(sizeof(off_t) == sizeof(int));
+ static const off_t off_t_max = INT_MAX;
+ static const off_t off_t_min = INT_MIN;
- memset(&lock, 0, sizeof(lock));
-
- // If start or length overflow the max values we can represent, then max them out.
- if(start > 0x7fffffffL) {
- start = 0x7fffffffL;
- }
- if(length > 0x7fffffffL) {
- length = 0x7fffffffL;
+ if (longOffset > off_t_max || longOffset < off_t_min) {
+ // "Value too large for defined data type".
+ jniThrowIOException(env, EOVERFLOW);
+ return true;
}
+ return false;
+}
+
+static jlong translateLockLength(jlong length) {
+ // FileChannel.tryLock uses Long.MAX_VALUE to mean "lock the whole
+ // file", where POSIX would use 0. We can support that special case,
+ // even for files whose actual length we can't represent. For other
+ // out of range lengths, though, we want our range checking to fire.
+ return (length == 0x7fffffffffffffffLL) ? 0 : length;
+}
+
+static struct flock flockFromStartAndLength(jlong start, jlong length) {
+ struct flock lock;
+ memset(&lock, 0, sizeof(lock));
lock.l_whence = SEEK_SET;
lock.l_start = start;
lock.l_len = length;
- if((typeFlag & SHARED_LOCK_TYPE) == SHARED_LOCK_TYPE) {
+ return lock;
+}
+
+static jint harmony_io_lockImpl(JNIEnv* env, jobject, jint handle,
+ jlong start, jlong length, jint typeFlag, jboolean waitFlag) {
+
+ length = translateLockLength(length);
+ if (offsetTooLarge(env, start) || offsetTooLarge(env, length)) {
+ return -1;
+ }
+
+ struct flock lock(flockFromStartAndLength(start, length));
+
+ if ((typeFlag & SHARED_LOCK_TYPE) == SHARED_LOCK_TYPE) {
lock.l_type = F_RDLCK;
} else {
lock.l_type = F_WRLCK;
}
- do {
- rc = fcntl(handle, waitMode, &lock);
- } while ((rc < 0) && (errno == EINTR));
-
- return (rc == -1) ? -1 : 0;
+ int waitMode = (waitFlag) ? F_SETLKW : F_SETLK;
+ return EINTR_RETRY(fcntl(handle, waitMode, &lock));
}
-/**
- * Unlocks the specified region of the file.
- */
-static jint harmony_io_unlockImpl(JNIEnv * env, jobject thiz, jint handle,
+static void harmony_io_unlockImpl(JNIEnv* env, jobject, jint handle,
jlong start, jlong length) {
- int rc;
- struct flock lock;
-
- memset(&lock, 0, sizeof(lock));
-
- // If start or length overflow the max values we can represent, then max them out.
- if(start > 0x7fffffffL) {
- start = 0x7fffffffL;
- }
- if(length > 0x7fffffffL) {
- length = 0x7fffffffL;
+ length = translateLockLength(length);
+ if (offsetTooLarge(env, start) || offsetTooLarge(env, length)) {
+ return;
}
- lock.l_whence = SEEK_SET;
- lock.l_start = start;
- lock.l_len = length;
+ struct flock lock(flockFromStartAndLength(start, length));
lock.l_type = F_UNLCK;
- do {
- rc = fcntl(handle, F_SETLKW, &lock);
- } while ((rc < 0) && (errno == EINTR));
-
- return (rc == -1) ? -1 : 0;
+ int rc = EINTR_RETRY(fcntl(handle, F_SETLKW, &lock));
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
+ }
}
/**
* Returns the granularity of the starting address for virtual memory allocation.
* (It's the same as the page size.)
- * Class: org_apache_harmony_luni_platform_OSFileSystem
- * Method: getAllocGranularity
- * Signature: ()I
*/
-static jint harmony_io_getAllocGranularity(JNIEnv * env, jobject thiz) {
- static int allocGranularity = 0;
- if(allocGranularity == 0) {
- allocGranularity = getpagesize();
- }
+static jint harmony_io_getAllocGranularity(JNIEnv* env, jobject) {
+ static int allocGranularity = getpagesize();
return allocGranularity;
}
-/*
- * Class: org_apache_harmony_luni_platform_OSFileSystem
- * Method: readvImpl
- * Signature: (I[J[I[I)J
- */
-static jlong harmony_io_readvImpl(JNIEnv *env, jobject thiz, jint fd,
- jintArray jbuffers, jintArray joffsets, jintArray jlengths, jint size) {
-
- jboolean bufsCopied = JNI_FALSE;
- jboolean offsetsCopied = JNI_FALSE;
- jboolean lengthsCopied = JNI_FALSE;
- jint *bufs;
- jint *offsets;
- jint *lengths;
- int i = 0;
- long totalRead = 0;
- struct iovec *vectors = (struct iovec *)malloc(size * sizeof(struct iovec));
- if(vectors == NULL) {
+static jlong harmony_io_readv(JNIEnv* env, jobject, jint fd,
+ jintArray jBuffers, jintArray jOffsets, jintArray jLengths, jint size) {
+ iovec* vectors = new iovec[size];
+ if (vectors == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", "native heap");
return -1;
}
- bufs = env->GetIntArrayElements(jbuffers, &bufsCopied);
- offsets = env->GetIntArrayElements(joffsets, &offsetsCopied);
- lengths = env->GetIntArrayElements(jlengths, &lengthsCopied);
- while(i < size) {
- vectors[i].iov_base = (void *)((int)(bufs[i]+offsets[i]));
+ jint *buffers = env->GetIntArrayElements(jBuffers, NULL);
+ jint *offsets = env->GetIntArrayElements(jOffsets, NULL);
+ jint *lengths = env->GetIntArrayElements(jLengths, NULL);
+ for (int i = 0; i < size; ++i) {
+ vectors[i].iov_base = (void *)((int)(buffers[i]+offsets[i]));
vectors[i].iov_len = lengths[i];
- i++;
- }
- totalRead = readv(fd, vectors, size);
- if(bufsCopied) {
- env->ReleaseIntArrayElements(jbuffers, bufs, JNI_ABORT);
}
- if(offsetsCopied) {
- env->ReleaseIntArrayElements(joffsets, offsets, JNI_ABORT);
- }
- if(lengthsCopied) {
- env->ReleaseIntArrayElements(jlengths, lengths, JNI_ABORT);
+ long result = readv(fd, vectors, size);
+ env->ReleaseIntArrayElements(jBuffers, buffers, JNI_ABORT);
+ env->ReleaseIntArrayElements(jOffsets, offsets, JNI_ABORT);
+ env->ReleaseIntArrayElements(jLengths, lengths, JNI_ABORT);
+ delete[] vectors;
+ if (result == -1) {
+ jniThrowIOException(env, errno);
}
- free(vectors);
- return totalRead;
+ return result;
}
-/*
- * Class: org_apache_harmony_luni_platform_OSFileSystem
- * Method: writevImpl
- * Signature: (I[J[I[I)J
- */
-static jlong harmony_io_writevImpl(JNIEnv *env, jobject thiz, jint fd,
- jintArray jbuffers, jintArray joffsets, jintArray jlengths, jint size) {
-
- jboolean bufsCopied = JNI_FALSE;
- jboolean offsetsCopied = JNI_FALSE;
- jboolean lengthsCopied = JNI_FALSE;
- jint *bufs;
- jint *offsets;
- jint *lengths;
- int i = 0;
- long totalRead = 0;
- struct iovec *vectors = (struct iovec *)malloc(size * sizeof(struct iovec));
- if(vectors == NULL) {
+static jlong harmony_io_writev(JNIEnv* env, jobject, jint fd,
+ jintArray jBuffers, jintArray jOffsets, jintArray jLengths, jint size) {
+ iovec* vectors = new iovec[size];
+ if (vectors == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", "native heap");
return -1;
}
- bufs = env->GetIntArrayElements(jbuffers, &bufsCopied);
- offsets = env->GetIntArrayElements(joffsets, &offsetsCopied);
- lengths = env->GetIntArrayElements(jlengths, &lengthsCopied);
- while(i < size) {
- vectors[i].iov_base = (void *)((int)(bufs[i]+offsets[i]));
+ jint *buffers = env->GetIntArrayElements(jBuffers, NULL);
+ jint *offsets = env->GetIntArrayElements(jOffsets, NULL);
+ jint *lengths = env->GetIntArrayElements(jLengths, NULL);
+ for (int i = 0; i < size; ++i) {
+ vectors[i].iov_base = (void *)((int)(buffers[i]+offsets[i]));
vectors[i].iov_len = lengths[i];
- i++;
}
- totalRead = writev(fd, vectors, size);
- if(bufsCopied) {
- env->ReleaseIntArrayElements(jbuffers, bufs, JNI_ABORT);
- }
- if(offsetsCopied) {
- env->ReleaseIntArrayElements(joffsets, offsets, JNI_ABORT);
- }
- if(lengthsCopied) {
- env->ReleaseIntArrayElements(jlengths, lengths, JNI_ABORT);
+ long result = writev(fd, vectors, size);
+ env->ReleaseIntArrayElements(jBuffers, buffers, JNI_ABORT);
+ env->ReleaseIntArrayElements(jOffsets, offsets, JNI_ABORT);
+ env->ReleaseIntArrayElements(jLengths, lengths, JNI_ABORT);
+ delete[] vectors;
+ if (result == -1) {
+ jniThrowIOException(env, errno);
}
- free(vectors);
- return totalRead;
+ return result;
}
-/*
- * Class: org_apache_harmony_luni_platform_OSFileSystem
- * Method: transferImpl
- * Signature: (IJJ)J
- */
-static jlong harmony_io_transferImpl(JNIEnv *env, jobject thiz, jint fd,
- jobject sd, jlong offset, jlong count) {
-
- int socket;
- off_t off;
+static jlong harmony_io_transfer(JNIEnv* env, jobject, jint fd, jobject sd,
+ jlong offset, jlong count) {
- socket = jniGetFDFromFileDescriptor(env, sd);
- if(socket == 0 || socket == -1) {
+ int socket = jniGetFDFromFileDescriptor(env, sd);
+ if (socket == -1) {
return -1;
}
/* Value of offset is checked in jint scope (checked in java layer)
The conversion here is to guarantee no value lost when converting offset to off_t
*/
- off = offset;
+ off_t off = offset;
- return sendfile(socket,(int)fd,(off_t *)&off,(size_t)count);
+ ssize_t rc = sendfile(socket, fd, &off, count);
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
+ }
+ return rc;
}
-/*
- * Class: org_apache_harmony_io
- * Method: readDirectImpl
- * Signature: (IJI)J
- */
-static jlong harmony_io_readDirectImpl(JNIEnv * env, jobject thiz, jint fd,
+static jlong harmony_io_readDirect(JNIEnv* env, jobject, jint fd,
jint buf, jint offset, jint nbytes) {
- jint result;
- if(nbytes == 0) {
- return (jlong) 0;
+ if (nbytes == 0) {
+ return 0;
}
- result = read(fd, (void *) ((jint *)(buf+offset)), (int) nbytes);
- if(result == 0) {
- return (jlong) -1;
- } else {
- return (jlong) result;
+ jbyte* dst = reinterpret_cast<jbyte*>(buf + offset);
+ jlong rc = EINTR_RETRY(read(fd, dst, nbytes));
+ if (rc == 0) {
+ return -1;
}
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
+ }
+ return rc;
}
-/*
- * Class: org_apache_harmony_io
- * Method: writeDirectImpl
- * Signature: (IJI)J
- */
-static jlong harmony_io_writeDirectImpl(JNIEnv * env, jobject thiz, jint fd,
+static jlong harmony_io_writeDirect(JNIEnv* env, jobject, jint fd,
jint buf, jint offset, jint nbytes) {
-
-
- int rc = 0;
-
- /* write will just do the right thing for HYPORT_TTY_OUT and HYPORT_TTY_ERR */
- rc = write (fd, (const void *) ((jint *)(buf+offset)), (int) nbytes);
-
- if(rc == -1) {
- jniThrowException(env, "java/io/IOException", strerror(errno));
- return -2;
+ jbyte* src = reinterpret_cast<jbyte*>(buf + offset);
+ jlong rc = EINTR_RETRY(write(fd, src, nbytes));
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
}
- return (jlong) rc;
-
+ return rc;
}
-// BEGIN android-changed
-/*
- * Class: org_apache_harmony_io
- * Method: readImpl
- * Signature: (I[BII)J
- */
-static jlong harmony_io_readImpl(JNIEnv * env, jobject thiz, jint fd,
+static jlong harmony_io_readImpl(JNIEnv* env, jobject, jint fd,
jbyteArray byteArray, jint offset, jint nbytes) {
- jboolean isCopy;
- jbyte *bytes;
- jlong result;
-
if (nbytes == 0) {
return 0;
}
- bytes = env->GetByteArrayElements(byteArray, &isCopy);
-
- for (;;) {
- result = read(fd, (void *) (bytes + offset), (int) nbytes);
-
- if ((result != -1) || (errno != EINTR)) {
- break;
- }
-
- /*
- * If we didn't break above, that means that the read() call
- * returned due to EINTR. We shield Java code from this
- * possibility by trying again. Note that this is different
- * from EAGAIN, which should result in this code throwing
- * an InterruptedIOException.
- */
- }
-
+ jbyte* bytes = env->GetByteArrayElements(byteArray, NULL);
+ jlong rc = EINTR_RETRY(read(fd, bytes + offset, nbytes));
env->ReleaseByteArrayElements(byteArray, bytes, 0);
- if (result == 0) {
+ if (rc == 0) {
return -1;
}
-
- if (result == -1) {
+ if (rc == -1) {
if (errno == EAGAIN) {
jniThrowException(env, "java/io/InterruptedIOException",
"Read timed out");
} else {
- jniThrowException(env, "java/io/IOException", strerror(errno));
+ jniThrowIOException(env, errno);
}
}
-
- return result;
+ return rc;
}
-/*
- * Class: org_apache_harmony_io
- * Method: writeImpl
- * Signature: (I[BII)J
- */
-static jlong harmony_io_writeImpl(JNIEnv * env, jobject thiz, jint fd,
+static jlong harmony_io_writeImpl(JNIEnv* env, jobject, jint fd,
jbyteArray byteArray, jint offset, jint nbytes) {
- jboolean isCopy;
- jbyte *bytes = env->GetByteArrayElements(byteArray, &isCopy);
- jlong result;
-
- for (;;) {
- result = write(fd, (const char *) bytes + offset, (int) nbytes);
-
- if ((result != -1) || (errno != EINTR)) {
- break;
- }
-
- /*
- * If we didn't break above, that means that the read() call
- * returned due to EINTR. We shield Java code from this
- * possibility by trying again. Note that this is different
- * from EAGAIN, which should result in this code throwing
- * an InterruptedIOException.
- */
- }
-
+ jbyte* bytes = env->GetByteArrayElements(byteArray, NULL);
+ jlong result = EINTR_RETRY(write(fd, bytes + offset, nbytes));
env->ReleaseByteArrayElements(byteArray, bytes, JNI_ABORT);
if (result == -1) {
@@ -416,157 +331,77 @@ static jlong harmony_io_writeImpl(JNIEnv * env, jobject thiz, jint fd,
jniThrowException(env, "java/io/InterruptedIOException",
"Write timed out");
} else {
- jniThrowException(env, "java/io/IOException", strerror(errno));
+ jniThrowIOException(env, errno);
}
}
-
return result;
}
-// END android-changed
-
-/**
- * Seeks a file descriptor to a given file position.
- *
- * @param env pointer to Java environment
- * @param thiz pointer to object receiving the message
- * @param fd handle of file to be seeked
- * @param offset distance of movement in bytes relative to whence arg
- * @param whence enum value indicating from where the offset is relative
- * The valid values are defined in fsconstants.h.
- * @return the new file position from the beginning of the file, in bytes;
- * or -1 if a problem occurs.
- */
-static jlong harmony_io_seekImpl(JNIEnv * env, jobject thiz, jint fd,
- jlong offset, jint whence) {
-
- int mywhence = 0;
+static jlong harmony_io_seek(JNIEnv* env, jobject, jint fd, jlong offset,
+ jint javaWhence) {
/* Convert whence argument */
- switch (whence) {
- case 1:
- mywhence = 0;
- break;
- case 2:
- mywhence = 1;
- break;
- case 4:
- mywhence = 2;
- break;
- default:
- return -1;
+ int nativeWhence = 0;
+ switch (javaWhence) {
+ case 1:
+ nativeWhence = SEEK_SET;
+ break;
+ case 2:
+ nativeWhence = SEEK_CUR;
+ break;
+ case 4:
+ nativeWhence = SEEK_END;
+ break;
+ default:
+ return -1;
}
-
- off_t localOffset = (int) offset;
-
- if((mywhence < 0) || (mywhence > 2)) {
+ // If the offset is relative, lseek(2) will tell us whether it's too large.
+ // We're just worried about too large an absolute offset, which would cause
+ // us to lie to lseek(2).
+ if (offsetTooLarge(env, offset)) {
return -1;
}
- /* If file offsets are 32 bit, truncate the seek to that range */
- if(sizeof (off_t) < sizeof (jlong)) {
- if(offset > 0x7FFFFFFF) {
- localOffset = 0x7FFFFFFF;
- } else if(offset < -0x7FFFFFFF) {
- localOffset = -0x7FFFFFFF;
- }
+ jlong result = lseek(fd, offset, nativeWhence);
+ if (result == -1) {
+ jniThrowIOException(env, errno);
}
-
- return (jlong) lseek(fd, localOffset, mywhence);
+ return result;
}
-/**
- * Flushes a file state to disk.
- *
- * @param env pointer to Java environment
- * @param thiz pointer to object receiving the message
- * @param fd handle of file to be flushed
- * @param metadata if true also flush metadata,
- * otherwise just flush data is possible.
- * @return zero on success and -1 on failure
- *
- * Method: fflushImpl
- * Signature: (IZ)I
- */
-static jint harmony_io_fflushImpl(JNIEnv * env, jobject thiz, jint fd,
+// TODO: are we supposed to support the 'metadata' flag? (false => fdatasync.)
+static void harmony_io_fflush(JNIEnv* env, jobject, jint fd,
jboolean metadata) {
- return (jint) fsync(fd);
+ int rc = fsync(fd);
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
+ }
}
-// BEGIN android-changed
-/**
- * Closes the given file handle
- *
- * @param env pointer to Java environment
- * @param thiz pointer to object receiving the message
- * @param fd handle of file to be closed
- * @return zero on success and -1 on failure
- *
- * Class: org_apache_harmony_io
- * Method: closeImpl
- * Signature: (I)I
- */
-static jint harmony_io_closeImpl(JNIEnv * env, jobject thiz, jint fd) {
- jint result;
-
- for (;;) {
- result = (jint) close(fd);
-
- if ((result != -1) || (errno != EINTR)) {
- break;
- }
-
- /*
- * If we didn't break above, that means that the close() call
- * returned due to EINTR. We shield Java code from this
- * possibility by trying again.
- */
+static jint harmony_io_close(JNIEnv* env, jobject, jint fd) {
+ jint rc = EINTR_RETRY(close(fd));
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
}
-
- return result;
+ return rc;
}
-// END android-changed
-
-/*
- * Class: org_apache_harmony_io
- * Method: truncateImpl
- * Signature: (IJ)I
- */
-static jint harmony_io_truncateImpl(JNIEnv * env, jobject thiz, jint fd,
- jlong size) {
-
- int rc;
- off_t length = (off_t) size;
-
- // If file offsets are 32 bit, truncate the newLength to that range
- if(sizeof (off_t) < sizeof (jlong)) {
- if(length > 0x7FFFFFFF) {
- length = 0x7FFFFFFF;
- } else if(length < -0x7FFFFFFF) {
- length = -0x7FFFFFFF;
- }
+static jint harmony_io_truncate(JNIEnv* env, jobject, jint fd, jlong length) {
+ if (offsetTooLarge(env, length)) {
+ return -1;
}
- rc = ftruncate((int)fd, length);
-
- return (jint) rc;
-
+ int rc = ftruncate(fd, length);
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
+ }
+ return rc;
}
-/*
- * Class: org_apache_harmony_io
- * Method: openImpl
- * Signature: ([BI)I
- */
-static jint harmony_io_openImpl(JNIEnv * env, jobject obj, jbyteArray path,
+static jint harmony_io_openImpl(JNIEnv* env, jobject, jbyteArray path,
jint jflags) {
-
int flags = 0;
- int mode = 0;
- jint * portFD;
- jsize length;
- char pathCopy[HyMaxPath];
+ int mode = 0;
// BEGIN android-changed
// don't want default permissions to allow global access.
@@ -588,7 +423,7 @@ static jint harmony_io_openImpl(JNIEnv * env, jobject obj, jbyteArray path,
mode = 0600;
break;
case 256:
- flags = HyOpenWrite | HyOpenCreate | HyOpenAppend;
+ flags = HyOpenWrite | HyOpenCreate | HyOpenAppend;
mode = 0600;
break;
}
@@ -596,116 +431,56 @@ static jint harmony_io_openImpl(JNIEnv * env, jobject obj, jbyteArray path,
flags = EsTranslateOpenFlags(flags);
- length = env->GetArrayLength (path);
+ // TODO: clean this up when we clean up the java.io.File equivalent.
+ jsize length = env->GetArrayLength (path);
length = length < HyMaxPath - 1 ? length : HyMaxPath - 1;
+ char pathCopy[HyMaxPath];
env->GetByteArrayRegion (path, 0, length, (jbyte *)pathCopy);
pathCopy[length] = '\0';
convertToPlatform (pathCopy);
- int cc;
-
- if(pathCopy == NULL) {
- jniThrowException(env, "java/lang/NullPointerException", NULL);
- return -1;
- }
-
- do {
- cc = open(pathCopy, flags, mode);
- } while(cc < 0 && errno == EINTR);
-
- if(cc < 0 && errno > 0) {
+ jint cc = EINTR_RETRY(open(pathCopy, flags, mode));
+ // TODO: chase up the callers of this and check they wouldn't rather
+ // have us throw a meaningful IOException right here.
+ if (cc < 0 && errno > 0) {
cc = -errno;
}
-
return cc;
-
-
}
-// BEGIN android-deleted
-#if 0
-/*
- * Answers the number of remaining chars in the stdin.
- *
- * Class: org_apache_harmony_io
- * Method: ttyAvailableImpl
- * Signature: ()J
- */
-static jlong harmony_io_ttyAvailableImpl(JNIEnv *env, jobject thiz) {
-
- int rc;
- off_t curr, end;
-
- int avail = 0;
-
- // when redirected from a file
- curr = lseek(STDIN_FILENO, 0L, 2); /* don't use tell(), it doesn't exist on all platforms, i.e. linux */
- if(curr != -1) {
- end = lseek(STDIN_FILENO, 0L, 4);
- lseek(STDIN_FILENO, curr, 1);
- if(end >= curr) {
- return (jlong) (end - curr);
- }
- }
-
- /* ioctl doesn't work for files on all platforms (i.e. SOLARIS) */
-
- rc = ioctl (STDIN_FILENO, FIONREAD, &avail);
-
- /* 64 bit platforms use a 32 bit value, using IDATA fails on big endian */
- /* Pass in IDATA because ioctl() is device dependent, some devices may write 64 bits */
- if(rc != -1) {
- return (jlong) *(jint *) & avail;
- }
- return (jlong) 0;
-}
-#endif
-// END android-deleted
-
-// BEGIN android-added
-/*
- * Answers the number of remaining bytes in a file descriptor
- * using IOCTL.
- *
- * Class: org_apache_harmony_io
- * Method: ioctlAvailable
- * Signature: ()I
- */
-static jint harmony_io_ioctlAvailable(JNIEnv *env, jobject thiz, jint fd) {
- int avail = 0;
- int rc = ioctl(fd, FIONREAD, &avail);
-
+static jint harmony_io_ioctlAvailable(JNIEnv*env, jobject, jint fd) {
/*
* On underlying platforms Android cares about (read "Linux"),
* ioctl(fd, FIONREAD, &avail) is supposed to do the following:
- *
+ *
* If the fd refers to a regular file, avail is set to
* the difference between the file size and the current cursor.
* This may be negative if the cursor is past the end of the file.
- *
+ *
* If the fd refers to an open socket or the read end of a
* pipe, then avail will be set to a number of bytes that are
* available to be read without blocking.
- *
+ *
* If the fd refers to a special file/device that has some concept
* of buffering, then avail will be set in a corresponding way.
- *
+ *
* If the fd refers to a special device that does not have any
* concept of buffering, then the ioctl call will return a negative
* number, and errno will be set to ENOTTY.
- *
+ *
* If the fd refers to a special file masquerading as a regular file,
* then avail may be returned as negative, in that the special file
* may appear to have zero size and yet a previous read call may have
* actually read some amount of data and caused the cursor to be
* advanced.
*/
-
+ int avail = 0;
+ int rc = ioctl(fd, FIONREAD, &avail);
if (rc >= 0) {
/*
* Success, but make sure not to return a negative number (see
* above).
- */
+ */
if (avail < 0) {
avail = 0;
}
@@ -714,61 +489,10 @@ static jint harmony_io_ioctlAvailable(JNIEnv *env, jobject thiz, jint fd) {
avail = 0;
} else {
/* Something strange is happening. */
- jniThrowException(env, "java/io/IOException", strerror(errno));
- avail = 0;
- }
-
- return (jint) avail;
-}
-// END android-added
-
-/*
- * Reads the number of bytes from stdin.
- *
- * Class: org_apache_harmony_io
- * Method: ttyReadImpl
- * Signature: ([BII)J
- */
-static jlong harmony_io_ttyReadImpl(JNIEnv *env, jobject thiz,
- jbyteArray byteArray, jint offset, jint nbytes) {
-
- jboolean isCopy;
- jbyte *bytes = env->GetByteArrayElements(byteArray, &isCopy);
- jlong result;
-
- for(;;) {
-
- result = (jlong) read(STDIN_FILENO, (char *)(bytes + offset), (int) nbytes);
-
- if ((result != -1) || (errno != EINTR)) {
- break;
- }
-
- /*
- * If we didn't break above, that means that the read() call
- * returned due to EINTR. We shield Java code from this
- * possibility by trying again. Note that this is different
- * from EAGAIN, which should result in this code throwing
- * an InterruptedIOException.
- */
- }
-
- env->ReleaseByteArrayElements(byteArray, bytes, 0);
-
- if (result == 0) {
- return -1;
- }
-
- if (result == -1) {
- if (errno == EAGAIN) {
- jniThrowException(env, "java/io/InterruptedIOException",
- "Read timed out");
- } else {
- jniThrowException(env, "java/io/IOException", strerror(errno));
- }
+ jniThrowIOException(env, errno);
}
- return result;
+ return (jint) avail;
}
/*
@@ -776,32 +500,26 @@ static jlong harmony_io_ttyReadImpl(JNIEnv *env, jobject thiz,
*/
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
+ { "close", "(I)V", (void*) harmony_io_close },
+ { "fflush", "(IZ)V", (void*) harmony_io_fflush },
+ { "getAllocGranularity","()I", (void*) harmony_io_getAllocGranularity },
+ { "ioctlAvailable", "(I)I", (void*) harmony_io_ioctlAvailable },
{ "lockImpl", "(IJJIZ)I", (void*) harmony_io_lockImpl },
- { "getAllocGranularity","()I", (void*) harmony_io_getAllocGranularity },
- { "unlockImpl", "(IJJ)I", (void*) harmony_io_unlockImpl },
- { "fflushImpl", "(IZ)I", (void*) harmony_io_fflushImpl },
- { "seekImpl", "(IJI)J", (void*) harmony_io_seekImpl },
- { "readDirectImpl", "(IIII)J", (void*) harmony_io_readDirectImpl },
- { "writeDirectImpl", "(IIII)J", (void*) harmony_io_writeDirectImpl },
+ { "openImpl", "([BI)I", (void*) harmony_io_openImpl },
+ { "readDirect", "(IIII)J", (void*) harmony_io_readDirect },
{ "readImpl", "(I[BII)J", (void*) harmony_io_readImpl },
+ { "readv", "(I[I[I[II)J",(void*) harmony_io_readv },
+ { "seek", "(IJI)J", (void*) harmony_io_seek },
+ { "transfer", "(ILjava/io/FileDescriptor;JJ)J",
+ (void*) harmony_io_transfer },
+ { "truncate", "(IJ)V", (void*) harmony_io_truncate },
+ { "unlockImpl", "(IJJ)V", (void*) harmony_io_unlockImpl },
+ { "writeDirect", "(IIII)J", (void*) harmony_io_writeDirect },
{ "writeImpl", "(I[BII)J", (void*) harmony_io_writeImpl },
- { "readvImpl", "(I[I[I[II)J",(void*) harmony_io_readvImpl },
- { "writevImpl", "(I[I[I[II)J",(void*) harmony_io_writevImpl },
- { "closeImpl", "(I)I", (void*) harmony_io_closeImpl },
- { "truncateImpl", "(IJ)I", (void*) harmony_io_truncateImpl },
- { "openImpl", "([BI)I", (void*) harmony_io_openImpl },
- { "transferImpl", "(ILjava/io/FileDescriptor;JJ)J",
- (void*) harmony_io_transferImpl },
- // BEGIN android-deleted
- //{ "ttyAvailableImpl", "()J", (void*) harmony_io_ttyAvailableImpl },
- // END android-deleted
- // BEGIN android-added
- { "ioctlAvailable", "(I)I", (void*) harmony_io_ioctlAvailable },
- // END android added
- { "ttyReadImpl", "([BII)J", (void*) harmony_io_ttyReadImpl }
+ { "writev", "(I[I[I[II)J",(void*) harmony_io_writev },
};
-int register_org_apache_harmony_luni_platform_OSFileSystem(JNIEnv *_env) {
- return jniRegisterNativeMethods(_env,
- "org/apache/harmony/luni/platform/OSFileSystem", gMethods,
- NELEM(gMethods));
+int register_org_apache_harmony_luni_platform_OSFileSystem(JNIEnv* _env) {
+ return jniRegisterNativeMethods(_env,
+ "org/apache/harmony/luni/platform/OSFileSystem", gMethods,
+ NELEM(gMethods));
}
diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp
index 2e814cc..b1493f8 100644
--- a/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp
+++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp
@@ -144,9 +144,8 @@ static jbyte harmony_nio_getByteImpl(JNIEnv *_env, jobject _this,
*/
static void harmony_nio_getBytesImpl(JNIEnv *_env, jobject _this, jint pointer,
jbyteArray dst, jint offset, jint length) {
- jbyte *dst_ = (jbyte *)_env->GetPrimitiveArrayCritical(dst, (jboolean *)0);
- memcpy(dst_ + offset, (jbyte *)pointer, length);
- _env->ReleasePrimitiveArrayCritical(dst, dst_, 0);
+ jbyte* src = reinterpret_cast<jbyte*>(static_cast<uintptr_t>(pointer));
+ _env->SetByteArrayRegion(dst, offset, length, src);
}
/*
@@ -166,9 +165,8 @@ static void harmony_nio_putByteImpl(JNIEnv *_env, jobject _this, jint pointer,
*/
static void harmony_nio_putBytesImpl(JNIEnv *_env, jobject _this,
jint pointer, jbyteArray src, jint offset, jint length) {
- jbyte *src_ = (jbyte *)_env->GetPrimitiveArrayCritical(src, (jboolean *)0);
- memcpy((jbyte *)pointer, src_ + offset, length);
- _env->ReleasePrimitiveArrayCritical(src, src_, JNI_ABORT);
+ jbyte* dst = reinterpret_cast<jbyte*>(static_cast<uintptr_t>(pointer));
+ _env->GetByteArrayRegion(src, offset, length, dst);
}
static void
diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
index 7b6023a..fd3820b 100644
--- a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
+++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
@@ -178,8 +178,6 @@ struct CachedFields {
jclass byte_class;
jmethodID byte_class_init;
jfieldID byte_class_value;
- jclass string_class;
- jmethodID string_class_init;
jclass socketimpl_class;
jfieldID socketimpl_address;
jfieldID socketimpl_port;
@@ -211,13 +209,6 @@ static void throwSocketException(JNIEnv *env, int errorCode) {
}
/**
- * Throws an IOException with the given message.
- */
-static void throwIOExceptionStr(JNIEnv *env, const char *message) {
- jniThrowException(env, "java/io/IOException", message);
-}
-
-/**
* Throws a NullPointerException.
*/
static void throwNullPointerException(JNIEnv *env) {
@@ -311,8 +302,7 @@ static bool isJavaMappedAddress(jbyte *addressBytes) {
/**
* Converts a native address structure to an InetAddress object.
* Throws a NullPointerException or an IOException in case of
- * error. This is signaled by a return value of -1. The normal
- * return value is 0.
+ * error.
*
* @param sockaddress the sockaddr_storage structure to convert
*
@@ -377,30 +367,30 @@ static void convertIpv4ToMapped(struct sockaddr_in *sin,
* @exception SocketError if the address family is unknown
*/
static int byteArrayToSocketAddress(JNIEnv *env,
- jbyteArray addressByteArray, int port, sockaddr_storage *sockaddress) {
- if (addressByteArray == NULL) {
- throwNullPointerException(env);
- return EFAULT;
+ jbyteArray addressBytes, int port, sockaddr_storage *sockaddress) {
+ if (addressBytes == NULL) {
+ throwNullPointerException(env);
+ return EFAULT;
}
- size_t addressLength = env->GetArrayLength(addressByteArray);
+ size_t addressLength = env->GetArrayLength(addressBytes);
// Convert the IP address bytes to the proper IP address type.
if (addressLength == 4) {
// IPv4 address.
- sockaddr_in *sin = (sockaddr_in *) sockaddress;
+ sockaddr_in *sin = reinterpret_cast<sockaddr_in*>(sockaddress);
memset(sin, 0, sizeof(sockaddr_in));
sin->sin_family = AF_INET;
sin->sin_port = htons(port);
- jbyte *rawBytes = (jbyte *) &sin->sin_addr.s_addr;
- env->GetByteArrayRegion(addressByteArray, 0, 4, rawBytes);
+ jbyte* dst = reinterpret_cast<jbyte*>(&sin->sin_addr.s_addr);
+ env->GetByteArrayRegion(addressBytes, 0, 4, dst);
} else if (addressLength == 16) {
// IPv6 address.
- sockaddr_in6 *sin6 = (sockaddr_in6 *) sockaddress;
+ sockaddr_in6 *sin6 = reinterpret_cast<sockaddr_in6*>(sockaddress);
memset(sin6, 0, sizeof(sockaddr_in6));
sin6->sin6_family = AF_INET6;
sin6->sin6_port = htons(port);
- jbyte *rawBytes = (jbyte *) &sin6->sin6_addr.s6_addr;
- env->GetByteArrayRegion(addressByteArray, 0, 16, rawBytes);
+ jbyte* dst = reinterpret_cast<jbyte*>(&sin6->sin6_addr.s6_addr);
+ env->GetByteArrayRegion(addressBytes, 0, 16, dst);
} else {
// Unknown address family.
throwSocketException(env, SOCKERR_BADAF);
@@ -419,20 +409,23 @@ static int byteArrayToSocketAddress(JNIEnv *env,
* @param port the port number
* @param sockaddress the sockaddr_storage structure to write to
*
- * @return 0 on success, -1 on failure
+ * @return 0 on success, a system error code on failure
* @throw UnknownHostException if any error occurs
*
* @exception SocketError if the address family is unknown
*/
-static int inetAddressToSocketAddress(JNIEnv *env,
- jobject inetaddress, int port, sockaddr_storage *sockaddress) {
-
+static int inetAddressToSocketAddress(JNIEnv *env, jobject inetaddress,
+ int port, sockaddr_storage *sockaddress) {
// Get the byte array that stores the IP address bytes in the InetAddress.
- jbyteArray addressByteArray;
- addressByteArray = (jbyteArray)env->GetObjectField(inetaddress,
- gCachedFields.iaddr_ipaddress);
+ if (inetaddress == NULL) {
+ throwNullPointerException(env);
+ return EFAULT;
+ }
+ jbyteArray addressBytes =
+ reinterpret_cast<jbyteArray>(env->GetObjectField(inetaddress,
+ gCachedFields.iaddr_ipaddress));
- return byteArrayToSocketAddress(env, addressByteArray, port, sockaddress);
+ return byteArrayToSocketAddress(env, addressBytes, port, sockaddress);
}
/**
@@ -652,22 +645,17 @@ jobject newJavaLangInteger(JNIEnv * env, jint anInt) {
return env->NewObject(tempClass, tempMethod, anInt);
}
-/**
- * Answer a new java.lang.String object.
- *
- * @param env pointer to the JNI library
- * @param anInt the byte[] constructor argument
- *
- * @return the new String
- */
-
-jobject newJavaLangString(JNIEnv * env, jbyteArray bytes) {
- jclass tempClass;
- jmethodID tempMethod;
+// Converts a number of milliseconds to a timeval.
+static timeval toTimeval(long ms) {
+ timeval tv;
+ tv.tv_sec = ms / 1000;
+ tv.tv_usec = (ms - tv.tv_sec*1000) * 1000;
+ return tv;
+}
- tempClass = gCachedFields.string_class;
- tempMethod = gCachedFields.string_class_init;
- return env->NewObject(tempClass, tempMethod, (jbyteArray) bytes);
+// Converts a timeval to a number of milliseconds.
+static long toMs(const timeval& tv) {
+ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
/**
@@ -684,11 +672,10 @@ jobject newJavaLangString(JNIEnv * env, jbyteArray bytes) {
*/
static int time_msec_clock() {
- struct timeval tp;
+ timeval tp;
struct timezone tzp;
-
gettimeofday(&tp, &tzp);
- return (tp.tv_sec * 1000) + (tp.tv_usec / 1000);
+ return toMs(tp);
}
/**
@@ -1102,7 +1089,6 @@ unsigned short ip_checksum(unsigned short* buffer, int size) {
return (unsigned short )(~sum);
}
-
/**
* Wrapper for connect() that converts IPv4 addresses to IPv4-mapped IPv6
* addresses if necessary.
@@ -1177,9 +1163,8 @@ static int doBind(int socket, struct sockaddr_storage *socketAddress) {
* @return 0, if no errors occurred, otherwise the (negative) error code.
*/
static int sockConnectWithTimeout(int handle, struct sockaddr_storage addr,
- unsigned int timeout, unsigned int step, jbyte *ctxt) {
+ int timeout, unsigned int step, jbyte *ctxt) {
int rc = 0;
- struct timeval passedTimeout;
int errorVal;
socklen_t errorValLen = sizeof(int);
struct selectFDSet *context = NULL;
@@ -1239,13 +1224,13 @@ static int sockConnectWithTimeout(int handle, struct sockaddr_storage addr,
* set the timeout value to be used. Because on some unix platforms we
* don't get notified when a socket is closed we only sleep for 100ms
* at a time
+ *
+ * TODO: is this relevant for Android?
*/
- passedTimeout.tv_sec = 0;
if (timeout > 100) {
- passedTimeout.tv_usec = 100 * 1000;
- } else if ((int)timeout >= 0) {
- passedTimeout.tv_usec = timeout * 1000;
+ timeout = 100;
}
+ timeval passedTimeout(toTimeval(timeout));
/* initialize the FD sets for the select */
FD_ZERO(&(context->exceptionSet));
@@ -1259,7 +1244,7 @@ static int sockConnectWithTimeout(int handle, struct sockaddr_storage addr,
&(context->readSet),
&(context->writeSet),
&(context->exceptionSet),
- (int)timeout >= 0 ? &passedTimeout : NULL);
+ timeout >= 0 ? &passedTimeout : NULL);
/* if there is at least one descriptor ready to be checked */
if (0 < rc) {
@@ -1613,7 +1598,6 @@ static void osNetworkSystem_oneTimeInitializationImpl(JNIEnv* env, jobject obj,
{&c->integer_class, "java/lang/Integer"},
{&c->boolean_class, "java/lang/Boolean"},
{&c->byte_class, "java/lang/Byte"},
- {&c->string_class, "java/lang/String"},
{&c->socketimpl_class, "java/net/SocketImpl"},
{&c->dpack_class, "java/net/DatagramPacket"}
};
@@ -1635,7 +1619,6 @@ static void osNetworkSystem_oneTimeInitializationImpl(JNIEnv* env, jobject obj,
{&c->integer_class_init, c->integer_class, "<init>", "(I)V", false},
{&c->boolean_class_init, c->boolean_class, "<init>", "(Z)V", false},
{&c->byte_class_init, c->byte_class, "<init>", "(B)V", false},
- {&c->string_class_init, c->string_class, "<init>", "([B)V", false},
{&c->iaddr_getbyaddress, c->iaddr_class, "getByAddress",
"([B)Ljava/net/InetAddress;", true}
};
@@ -2684,13 +2667,10 @@ static jint osNetworkSystem_receiveStreamImpl(JNIEnv* env, jclass clazz,
int spaceAvailable = env->GetArrayLength(data) - offset;
int localCount = count < spaceAvailable? count : spaceAvailable;
- jboolean isCopy;
- jbyte *body = env->GetByteArrayElements(data, &isCopy);
+ jbyte* body = env->GetByteArrayElements(data, NULL);
// set timeout
- struct timeval tv;
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
+ timeval tv(toTimeval(timeout));
setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv,
sizeof(struct timeval));
@@ -2728,8 +2708,7 @@ static jint osNetworkSystem_sendStreamImpl(JNIEnv* env, jclass clazz,
int handle = 0;
int result = 0, sent = 0;
- jboolean isCopy;
- jbyte *message = env->GetByteArrayElements(data, &isCopy);
+ jbyte *message = env->GetByteArrayElements(data, NULL);
// Cap write length to available buf size
int spaceAvailable = env->GetArrayLength(data) - offset;
@@ -2875,111 +2854,87 @@ static jint osNetworkSystem_sendDatagramImpl2(JNIEnv* env, jclass clazz,
return sent;
}
-static jint osNetworkSystem_selectImpl(JNIEnv* env, jclass clazz,
- jobjectArray readFDArray, jobjectArray writeFDArray, jint countReadC,
- jint countWriteC, jintArray outFlags, jlong timeout) {
- // LOGD("ENTER selectImpl");
-
- struct timeval timeP;
- int result = 0;
- int size = 0;
- jobject gotFD;
- fd_set *fdset_read,*fdset_write;
- int handle;
- jboolean isCopy ;
- jint *flagArray;
- int val;
- unsigned int time_sec = (unsigned int)timeout/1000;
- unsigned int time_msec = (unsigned int)(timeout%1000);
-
- fdset_read = (fd_set *)malloc(sizeof(fd_set));
- fdset_write = (fd_set *)malloc(sizeof(fd_set));
-
- FD_ZERO(fdset_read);
- FD_ZERO(fdset_write);
-
- for (val = 0; val<countReadC; val++) {
-
- gotFD = env->GetObjectArrayElement(readFDArray,val);
-
- handle = jniGetFDFromFileDescriptor(env, gotFD);
-
- FD_SET(handle, fdset_read);
-
- if (0 > (size - handle)) {
- size = handle;
+static bool initFdSet(JNIEnv* env, jobjectArray fdArray, jint count, fd_set* fdSet, int* maxFd) {
+ for (int i = 0; i < count; ++i) {
+ jobject fileDescriptor = env->GetObjectArrayElement(fdArray, i);
+ if (fileDescriptor == NULL) {
+ return false;
}
- }
-
- for (val = 0; val<countWriteC; val++) {
-
- gotFD = env->GetObjectArrayElement(writeFDArray,val);
-
- handle = jniGetFDFromFileDescriptor(env, gotFD);
-
- FD_SET(handle, fdset_write);
-
- if (0 > (size - handle)) {
- size = handle;
+
+ const int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ if (fd < 0 || fd > 1024) {
+ LOGE("selectImpl: invalid fd %i", fd);
+ continue;
}
- }
-
- /* the size is the max_fd + 1 */
- size =size + 1;
-
- if (0 > size) {
- result = SOCKERR_FDSET_SIZEBAD;
- } else {
- /* only set when timeout >= 0 (non-block)*/
- if (0 <= timeout) {
-
- timeP.tv_sec = time_sec;
- timeP.tv_usec = time_msec*1000;
-
- result = sockSelect(size, fdset_read, fdset_write, NULL, &timeP);
-
- } else {
- result = sockSelect(size, fdset_read, fdset_write, NULL, NULL);
+
+ FD_SET(fd, fdSet);
+
+ if (fd > *maxFd) {
+ *maxFd = fd;
}
}
+ return true;
+}
- if (0 < result) {
- /*output the result to a int array*/
- flagArray = env->GetIntArrayElements(outFlags, &isCopy);
-
- for (val=0; val<countReadC; val++) {
- gotFD = env->GetObjectArrayElement(readFDArray,val);
-
- handle = jniGetFDFromFileDescriptor(env, gotFD);
-
- if (FD_ISSET(handle,fdset_read)) {
- flagArray[val] = SOCKET_OP_READ;
- } else {
- flagArray[val] = SOCKET_OP_NONE;
- }
+static bool translateFdSet(JNIEnv* env, jobjectArray fdArray, jint count, const fd_set& fdSet, jint* flagArray, size_t offset, jint op) {
+ for (int i = 0; i < count; ++i) {
+ jobject fileDescriptor = env->GetObjectArrayElement(fdArray, i);
+ if (fileDescriptor == NULL) {
+ return false;
}
-
- for (val=0; val<countWriteC; val++) {
-
- gotFD = env->GetObjectArrayElement(writeFDArray,val);
-
- handle = jniGetFDFromFileDescriptor(env, gotFD);
-
- if (FD_ISSET(handle,fdset_write)) {
- flagArray[val+countReadC] = SOCKET_OP_WRITE;
- } else {
- flagArray[val+countReadC] = SOCKET_OP_NONE;
- }
+
+ const int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ const bool valid = fd >= 0 && fd < 1024;
+
+ if (valid && FD_ISSET(fd, &fdSet)) {
+ flagArray[i + offset] = op;
+ } else {
+ flagArray[i + offset] = SOCKET_OP_NONE;
}
-
- env->ReleaseIntArrayElements(outFlags, flagArray, 0);
}
+ return true;
+}
- free(fdset_write);
- free(fdset_read);
-
- /* return both correct and error result, let java handle the exception*/
- return result;
+static jint osNetworkSystem_selectImpl(JNIEnv* env, jclass clazz,
+ jobjectArray readFDArray, jobjectArray writeFDArray, jint countReadC,
+ jint countWriteC, jintArray outFlags, jlong timeoutMs) {
+ // LOGD("ENTER selectImpl");
+
+ // Initialize the fd_sets.
+ int maxFd = -1;
+ fd_set readFds;
+ fd_set writeFds;
+ FD_ZERO(&readFds);
+ FD_ZERO(&writeFds);
+ bool initialized = initFdSet(env, readFDArray, countReadC, &readFds, &maxFd) &&
+ initFdSet(env, writeFDArray, countWriteC, &writeFds, &maxFd);
+ if (!initialized) {
+ return -1;
+ }
+
+ // Initialize the timeout, if any.
+ timeval tv;
+ timeval* tvp = NULL;
+ if (timeoutMs >= 0) {
+ tv = toTimeval(timeoutMs);
+ tvp = &tv;
+ }
+
+ // Perform the select.
+ int result = sockSelect(maxFd + 1, &readFds, &writeFds, NULL, tvp);
+ if (result < 0) {
+ return result;
+ }
+
+ // Translate the result into the int[] we're supposed to fill in.
+ jint* flagArray = env->GetIntArrayElements(outFlags, NULL);
+ if (flagArray == NULL) {
+ return -1;
+ }
+ bool okay = translateFdSet(env, readFDArray, countReadC, readFds, flagArray, 0, SOCKET_OP_READ) &&
+ translateFdSet(env, writeFDArray, countWriteC, writeFds, flagArray, countReadC, SOCKET_OP_WRITE);
+ env->ReleaseIntArrayElements(outFlags, flagArray, 0);
+ return okay ? 0 : -1;
}
static jobject osNetworkSystem_getSocketLocalAddressImpl(JNIEnv* env,
@@ -3212,7 +3167,7 @@ static jobject osNetworkSystem_getSocketOptionImpl(JNIEnv* env, jclass clazz,
throwSocketException(env, convertError(errno));
return NULL;
}
- return newJavaLangInteger(env, timeout.tv_sec * 1000 + timeout.tv_usec/1000);
+ return newJavaLangInteger(env, toMs(timeout));
}
default: {
throwSocketException(env, SOCKERR_OPTUNSUPP);
@@ -3457,9 +3412,7 @@ static void osNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
}
case JAVASOCKOPT_SO_RCVTIMEOUT: {
- struct timeval timeout;
- timeout.tv_sec = intVal / 1000;
- timeout.tv_usec = (intVal % 1000) * 1000;
+ timeval timeout(toTimeval(intVal));
result = setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, &timeout,
sizeof(struct timeval));
if (0 != result) {
diff --git a/luni/src/test/java/com/google/coretests/CoreTestRunner.java b/luni/src/test/java/com/google/coretests/CoreTestRunner.java
index d469c86..d80fa4e 100644
--- a/luni/src/test/java/com/google/coretests/CoreTestRunner.java
+++ b/luni/src/test/java/com/google/coretests/CoreTestRunner.java
@@ -15,6 +15,8 @@
*/
package com.google.coretests;
+import java.util.ArrayList;
+import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -134,10 +136,10 @@ public class CoreTestRunner extends TestRunner {
* Prints a help screen on the console.
*/
private void showHelp() {
- System.out.println("Usage: run-core-tests {<param>} <test>");
+ System.out.println("Usage: run-core-tests [OPTION]... [TEST]...");
System.out.println();
- System.out.println("Where <test> is a class name, optionally followed");
- System.out.println("by \"#\" and a method name, and <param> is one of");
+ System.out.println("Where each TEST is a class name, optionally followed");
+ System.out.println("by \"#\" and a method name, and each OPTION is one of");
System.out.println("the following:");
System.out.println();
System.out.println(" --include-all");
@@ -185,26 +187,29 @@ public class CoreTestRunner extends TestRunner {
}
/**
- * Tries to create a Test instance from a given string. The string might
+ * Tries to create a Test instance from the given strings. The strings might
* either specify a class only or a class plus a method name, separated by
* a "#".
*/
- private Test createTest(String testCase) throws Exception {
- int p = testCase.indexOf("#");
- if (p != -1) {
- String testName = testCase.substring(p + 1);
- testCase = testCase.substring(0, p);
-
- return TestSuite.createTest(Class.forName(testCase), testName);
- } else {
- return getTest(testCase);
+ private Test createTest(List<String> testCases) throws Exception {
+ TestSuite result = new TestSuite();
+ for (String testCase : testCases) {
+ int p = testCase.indexOf("#");
+ if (p != -1) {
+ String testName = testCase.substring(p + 1);
+ testCase = testCase.substring(0, p);
+
+ result.addTest(TestSuite.createTest(Class.forName(testCase), testName));
+ } else {
+ result.addTest(getTest(testCase));
+ }
}
-
+ return result;
}
@Override
protected TestResult start(String args[]) throws Exception {
- String testName = null;
+ List<String> testNames = new ArrayList<String>();
// String victimName = null;
boolean wait = false;
@@ -269,12 +274,12 @@ public class CoreTestRunner extends TestRunner {
showHelp();
System.exit(1);
} else {
- System.err.println("Unknown argument " + args[i] +
- ", try --help");
- System.exit(1);
+ unknownArgument(args[i]);
}
+ } else if (args[i].startsWith("-")) {
+ unknownArgument(args[i]);
} else {
- testName = args[i];
+ testNames.add(args[i]);
}
}
@@ -288,7 +293,7 @@ public class CoreTestRunner extends TestRunner {
System.out.println();
try {
- return doRun(createTest(testName), wait);
+ return doRun(createTest(testNames), wait);
}
catch(Exception e) {
e.printStackTrace();
@@ -296,4 +301,8 @@ public class CoreTestRunner extends TestRunner {
}
}
+ private static void unknownArgument(String arg) {
+ System.err.println("Unknown argument " + arg + ", try --help");
+ System.exit(1);
+ }
}
diff --git a/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/PackageTest.java b/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/PackageTest.java
index cb35324..283c1db 100644
--- a/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/PackageTest.java
+++ b/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/PackageTest.java
@@ -312,7 +312,7 @@ public class PackageTest extends junit.framework.TestCase {
method = "isCompatibleWith",
args = {java.lang.String.class}
)
- @KnownFailure("isCompatibleWith returns incorrect value.")
+ @KnownFailure("Dalvik packages are always version '0.0'.")
public void test_isCompatibleWithLjava_lang_String() throws Exception {
Package p = getTestPackage("hyts_c.jar", "p.C");
diff --git a/luni/src/test/java/tests/api/java/io/FileTest.java b/luni/src/test/java/tests/api/java/io/FileTest.java
index 2850826..5c0cb2a 100644
--- a/luni/src/test/java/tests/api/java/io/FileTest.java
+++ b/luni/src/test/java/tests/api/java/io/FileTest.java
@@ -688,10 +688,7 @@ public class FileTest extends junit.framework.TestCase {
method = "delete",
args = {}
)
- @KnownFailure("Non empty directories are deleted on Android.")
public void test_delete() {
- // this test passes in the emulator, but it fails on the device
-
// Test for method boolean java.io.File.delete()
try {
File dir = new File(System.getProperty("java.io.tmpdir"), platformId
diff --git a/luni/src/test/java/tests/api/java/io/RandomAccessFileTest.java b/luni/src/test/java/tests/api/java/io/RandomAccessFileTest.java
index 3b545e3..dc35610 100644
--- a/luni/src/test/java/tests/api/java/io/RandomAccessFileTest.java
+++ b/luni/src/test/java/tests/api/java/io/RandomAccessFileTest.java
@@ -1200,16 +1200,25 @@ public class RandomAccessFileTest extends junit.framework.TestCase {
} catch (IOException e) {
// Expected.
}
+ // BEGIN android-added
+ try {
+ // Android uses 32-bit off_t, so anything larger than a signed 32-bit int won't work.
+ raf.seek(((long) Integer.MAX_VALUE) + 1);
+ fail("Test 2: IOException expected.");
+ } catch (IOException e) {
+ // Expected.
+ }
+ // END android-added
raf.write(testString.getBytes(), 0, testLength);
raf.seek(12);
- assertEquals("Test 2: Seek failed to set file pointer.", 12,
+ assertEquals("Test 3: Seek failed to set file pointer.", 12,
raf.getFilePointer());
raf.close();
try {
raf.seek(1);
- fail("Test 1: IOException expected.");
+ fail("Test 4: IOException expected.");
} catch (IOException e) {
// Expected.
}
@@ -1296,10 +1305,21 @@ public class RandomAccessFileTest extends junit.framework.TestCase {
assertEquals("Test 7: Incorrect file length;",
testLength + 2, raf.length());
+ // BEGIN android-added
+ // Exception testing.
+ try {
+ // Android uses 32-bit off_t, so anything larger than a signed 32-bit int won't work.
+ raf.setLength(((long) Integer.MAX_VALUE) + 1);
+ fail("Test 8: IOException expected.");
+ } catch (IOException e) {
+ // Expected.
+ }
+ // END android-added
+
// Exception testing.
try {
raf.setLength(-1);
- fail("Test 8: IllegalArgumentException expected.");
+ fail("Test 9: IllegalArgumentException expected.");
} catch (IllegalArgumentException e) {
// Expected.
}
@@ -1307,7 +1327,7 @@ public class RandomAccessFileTest extends junit.framework.TestCase {
raf.close();
try {
raf.setLength(truncLength);
- fail("Test 9: IOException expected.");
+ fail("Test 10: IOException expected.");
} catch (IOException e) {
// Expected.
}
@@ -1501,4 +1521,4 @@ public class RandomAccessFileTest extends junit.framework.TestCase {
super.tearDown();
}
-} \ No newline at end of file
+}
diff --git a/luni/src/test/java/tests/api/java/util/ArrayListTest.java b/luni/src/test/java/tests/api/java/util/ArrayListTest.java
index 8aa77cc..0356731 100644
--- a/luni/src/test/java/tests/api/java/util/ArrayListTest.java
+++ b/luni/src/test/java/tests/api/java/util/ArrayListTest.java
@@ -19,7 +19,7 @@ package tests.api.java.util;
import dalvik.annotation.TestTargetNew;
import dalvik.annotation.TestTargets;
import dalvik.annotation.TestLevel;
-import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetClass;
import java.util.ArrayList;
import java.util.Arrays;
@@ -33,13 +33,13 @@ import java.util.Vector;
import tests.support.Support_ListTest;
-@TestTargetClass(ArrayList.class)
+@TestTargetClass(ArrayList.class)
public class ArrayListTest extends junit.framework.TestCase {
List alist;
Object[] objArray;
-
+
/**
* @tests java.util.ArrayList#ArrayList()
*/
@@ -72,7 +72,7 @@ public class ArrayListTest extends junit.framework.TestCase {
// Test for method java.util.ArrayList(int)
ArrayList al = new ArrayList(5);
assertEquals("Incorrect arrayList created", 0, al.size());
-
+
try {
new ArrayList(-10);
fail("IllegalArgumentException expected");
@@ -130,14 +130,14 @@ public class ArrayListTest extends junit.framework.TestCase {
assertNull("Should have returned null", alist.get(25));
assertTrue("Should have returned the old item from slot 25", alist
.get(26) == oldItem);
-
+
try {
alist.add(-1, null);
fail("IndexOutOfBoundsException expected");
} catch (IndexOutOfBoundsException e) {
//expected
}
-
+
try {
alist.add(alist.size() + 1, null);
fail("IndexOutOfBoundsException expected");
@@ -198,9 +198,9 @@ public class ArrayListTest extends junit.framework.TestCase {
assertTrue("Incorrect size: " + alist.size(), alist.size() == 205);
assertNull("Item at slot 100 should be null", alist.get(100));
assertNull("Item at slot 101 should be null", alist.get(101));
- assertEquals("Item at slot 102 should be 'yoink'",
+ assertEquals("Item at slot 102 should be 'yoink'",
"yoink", alist.get(102));
- assertEquals("Item at slot 103 should be 'kazoo'",
+ assertEquals("Item at slot 103 should be 'kazoo'",
"kazoo", alist.get(103));
assertNull("Item at slot 104 should be null", alist.get(104));
alist.addAll(205, listWithNulls);
@@ -228,24 +228,29 @@ public class ArrayListTest extends junit.framework.TestCase {
}
}
- /**
- * @tests java.util.ArrayList#addAll(int, java.util.Collection)
- */
- @TestTargetNew(
- level = TestLevel.PARTIAL_COMPLETE,
- notes = "Verifies IndexOutOfBoundsException.",
- method = "addAll",
- args = {int.class, java.util.Collection.class}
- )
- public void test_addAllILjava_util_Collection_2() {
- // Regression for HARMONY-467
- ArrayList obj = new ArrayList();
- try {
- obj.addAll((int) -1, (Collection) null);
- fail("IndexOutOfBoundsException expected");
- } catch (IndexOutOfBoundsException e) {
- }
- }
+// BEGIN android-removed
+// The spec does not mandate that IndexOutOfBoundsException be thrown in
+// preference to NullPointerException when the caller desserves both.
+//
+// /**
+// * @tests java.util.ArrayList#addAll(int, java.util.Collection)
+// */
+// @TestTargetNew(
+// level = TestLevel.PARTIAL_COMPLETE,
+// notes = "Verifies IndexOutOfBoundsException.",
+// method = "addAll",
+// args = {int.class, java.util.Collection.class}
+// )
+// public void test_addAllILjava_util_Collection_2() {
+// // Regression for HARMONY-467
+// ArrayList obj = new ArrayList();
+// try {
+// obj.addAll((int) -1, (Collection) null);
+// fail("IndexOutOfBoundsException expected");
+// } catch (IndexOutOfBoundsException e) {
+// }
+// }
+// END android-removed
/**
* @tests java.util.ArrayList#addAll(java.util.Collection)
@@ -287,17 +292,17 @@ public class ArrayListTest extends junit.framework.TestCase {
.get(101) == i.next());
assertTrue("Item at slot 103 is wrong: " + alist.get(102), alist
.get(102) == i.next());
-
-
+
+
// Regression test for Harmony-3481
ArrayList<Integer> originalList = new ArrayList<Integer>(12);
for (int j = 0; j < 12; j++) {
originalList.add(j);
}
-
+
originalList.remove(0);
originalList.remove(0);
-
+
ArrayList<Integer> additionalList = new ArrayList<Integer>(11);
for (int j = 0; j < 11; j++) {
additionalList.add(j);
@@ -672,7 +677,7 @@ public class ArrayListTest extends junit.framework.TestCase {
assertTrue("Returned incorrect array: " + i,
retArray[i] == objArray[i]);
}
-
+
String[] strArray = new String[100];
try {
alist.toArray(strArray);
@@ -746,16 +751,16 @@ public class ArrayListTest extends junit.framework.TestCase {
list.remove(0);
assertEquals(1, list.size());
-
+
ArrayList collection = new ArrayList();
collection.add("1");
collection.add("2");
collection.add("3");
assertEquals(3, collection.size());
-
+
list.addAll(0, collection);
assertEquals(4, list.size());
-
+
list.remove(0);
list.remove(0);
assertEquals(2, list.size());
@@ -769,13 +774,13 @@ public class ArrayListTest extends junit.framework.TestCase {
collection.add("10");
collection.add("11");
collection.add("12");
-
+
assertEquals(12, collection.size());
-
+
list.addAll(0, collection);
assertEquals(14, list.size());
}
-
+
@TestTargetNew(
level = TestLevel.COMPLETE,
notes = "",
@@ -818,7 +823,7 @@ public class ArrayListTest extends junit.framework.TestCase {
mal.add("f");
mal.add("g");
mal.add("h");
-
+
mal.removeRange(2, 4);
String[] result = new String[6];
@@ -827,30 +832,30 @@ public class ArrayListTest extends junit.framework.TestCase {
new String[] { "a", "b", "e", "f", "g", "h"}));
}
-
+
/**
* Sets up the fixture, for example, open a network connection. This method
* is called before a test is executed.
*/
protected void setUp() throws Exception {
super.setUp();
-
+
objArray = new Object[100];
for (int i = 0; i < objArray.length; i++) {
objArray[i] = new Integer(i);
}
-
+
alist = new ArrayList();
for (int i = 0; i < objArray.length; i++) {
alist.add(objArray[i]);
}
}
-
+
@Override
protected void tearDown() throws Exception {
objArray = null;
alist = null;
-
+
super.tearDown();
}
}
diff --git a/luni/src/test/java/tests/api/java/util/FormatterTest.java b/luni/src/test/java/tests/api/java/util/FormatterTest.java
index b2030c9..6f86818 100644
--- a/luni/src/test/java/tests/api/java/util/FormatterTest.java
+++ b/luni/src/test/java/tests/api/java/util/FormatterTest.java
@@ -800,6 +800,36 @@ public class FormatterTest extends TestCase {
}
}
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Tests that supplying a Formattable works. See http://code.google.com/p/android/issues/detail?id=1767.",
+ method = "format",
+ args = {}
+ )
+ public void test_Formattable() {
+ Formattable ones = new Formattable() {
+ public void formatTo(Formatter formatter, int flags, int width, int precision) throws IllegalFormatException {
+ try {
+ formatter.out().append("111");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ };
+ Formattable twos = new Formattable() {
+ public void formatTo(Formatter formatter, int flags, int width, int precision) throws IllegalFormatException {
+ try {
+ formatter.out().append("222");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ };
+
+ assertEquals("aaa 111?", new Formatter().format("aaa %s?", ones).toString());
+ assertEquals("aaa 111 bbb 222?", new Formatter().format("aaa %s bbb %s?", ones, twos).toString());
+ }
+
/**
* @tests java.util.Formatter#out()
*/
diff --git a/luni/src/test/java/tests/api/java/util/TimeZoneTest.java b/luni/src/test/java/tests/api/java/util/TimeZoneTest.java
index efdb8a1..75e9ae3 100644
--- a/luni/src/test/java/tests/api/java/util/TimeZoneTest.java
+++ b/luni/src/test/java/tests/api/java/util/TimeZoneTest.java
@@ -383,6 +383,19 @@ public class TimeZoneTest extends junit.framework.TestCase {
@TestTargetNew(
level = TestLevel.COMPLETE,
notes = "",
+ method = "useDaylightTime",
+ args = {}
+ )
+ public void test_useDaylightTime() {
+ // http://code.google.com/p/android/issues/detail?id=877
+
+ TimeZone asiaTaipei = TimeZone.getTimeZone("Asia/Taipei");
+ assertFalse("Taiwan doesn't use DST", asiaTaipei.useDaylightTime());
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
method = "setID",
args = {java.lang.String.class}
)