Merge "Fix GetDirectBufferAddress for DirectByteBuffer."
diff --git a/luni/src/test/java/libcore/java/io/FileInputStreamTest.java b/luni/src/test/java/libcore/java/io/FileInputStreamTest.java
index 9591e2b..b6650ff 100644
--- a/luni/src/test/java/libcore/java/io/FileInputStreamTest.java
+++ b/luni/src/test/java/libcore/java/io/FileInputStreamTest.java
@@ -107,7 +107,7 @@
 
         // Close the second FileDescriptor and check we can't use it...
         fis2.close();
-        // TODO(pszczepaniak): Implement this funcitonality
+
         try {
             fis2.available();
             fail();
@@ -129,6 +129,7 @@
         } catch (IOException expected) {
         }
         // ...but that we can still use the first.
+        assertTrue(fis1.getFD().valid());
         assertFalse(fis1.read() == -1);
 
         // Close the first FileDescriptor and check we can't use it...
@@ -153,6 +154,9 @@
             fail();
         } catch (IOException expected) {
         }
+
+        // FD is no longer owned by any stream, should be invalidated.
+        assertFalse(fis1.getFD().valid());
     }
 
     public void testClose() throws Exception {
diff --git a/luni/src/test/java/libcore/java/io/FileOutputStreamTest.java b/luni/src/test/java/libcore/java/io/FileOutputStreamTest.java
index 12ef19b..dd600a2 100644
--- a/luni/src/test/java/libcore/java/io/FileOutputStreamTest.java
+++ b/luni/src/test/java/libcore/java/io/FileOutputStreamTest.java
@@ -57,6 +57,9 @@
             fail();
         } catch (IOException expected) {
         }
+
+        // FD is no longer owned by any stream, should be invalidated.
+        assertFalse(fos1.getFD().valid());
     }
 
     public void testClose() throws Exception {
diff --git a/ojluni/src/main/java/java/io/FileInputStream.java b/ojluni/src/main/java/java/io/FileInputStream.java
index e39ba2a..a3e8d8b 100755
--- a/ojluni/src/main/java/java/io/FileInputStream.java
+++ b/ojluni/src/main/java/java/io/FileInputStream.java
@@ -284,6 +284,10 @@
      * @exception  IOException  if an I/O error occurs.
      */
     public int read(byte b[], int off, int len) throws IOException {
+        if (closed && len > 0) {
+            throw new IOException("Stream Closed");
+        }
+
         Object traceContext = IoTrace.fileReadBegin(path);
         int bytesRead = 0;
         try {
@@ -320,6 +324,10 @@
      *             support seek, or if an I/O error occurs.
      */
     public long skip(long n) throws IOException {
+      if (closed) {
+        throw new IOException("Stream Closed");
+      }
+
       try {
         return skip0(n);
       } catch(UseManualSkipException e) {
@@ -351,7 +359,15 @@
      * @exception  IOException  if this file input stream has been closed by calling
      *             {@code close} or an I/O error occurs.
      */
-    public native int available() throws IOException;
+    public int available() throws IOException {
+        if (closed) {
+            throw new IOException("Stream Closed");
+        }
+
+        return available0();
+    }
+
+    private native int available0() throws IOException;
 
     /**
      * Closes this file input stream and releases any system resources
diff --git a/ojluni/src/main/java/java/io/FileOutputStream.java b/ojluni/src/main/java/java/io/FileOutputStream.java
index 69318ae..a09649d 100755
--- a/ojluni/src/main/java/java/io/FileOutputStream.java
+++ b/ojluni/src/main/java/java/io/FileOutputStream.java
@@ -56,7 +56,7 @@
     /**
      * The system dependent file descriptor.
      */
-    private FileDescriptor fd;
+    private final FileDescriptor fd;
 
     /**
      * The path of the referenced file (null if the stream is created with a file descriptor)
@@ -73,11 +73,6 @@
      */
     private FileChannel channel;
 
-    /**
-     * True if the current stream owns the file descriptor.
-     */
-    private boolean isOwner;
-
     private final Object closeLock = new Object();
     private volatile boolean closed = false;
     private static final ThreadLocal<Boolean> runningFinalize =
@@ -220,7 +215,6 @@
             throw new FileNotFoundException("Invalid file path");
         }
         this.fd = new FileDescriptor();
-        this.isOwner = true;
         this.append = append;
         this.path = name;
         fd.incrementAndGetUseCount();
@@ -266,7 +260,6 @@
         }
 
         this.fd = fdObj;
-        this.isOwner = isFdOwner;
         this.path = null;
         this.append = false;
 
@@ -362,6 +355,10 @@
      * @exception  IOException  if an I/O error occurs.
      */
     public void write(byte b[], int off, int len) throws IOException {
+        if (closed && len > 0) {
+            throw new IOException("Stream Closed");
+        }
+
         Object traceContext = IoTrace.fileWriteBegin(path);
         int bytesWritten = 0;
         try {
@@ -409,13 +406,15 @@
         int useCount = fd.decrementAndGetUseCount();
 
         /*
-         * The file descriptor will close with the closing of
-         * the owner thread.
+         * If FileDescriptor is still in use by another stream, the finalizer
+         * will not close it.
          */
-        if (isOwner) {
+        // Android change, make sure only last close closes FD.
+        if ((useCount <= 0)) { // || !isRunningFinalize()) {
+            /* ----- BEGIN android -----
+            close0(); */
             IoBridge.closeAndSignalBlockedThreads(fd);
-        } else {
-            fd = new FileDescriptor();
+            // ----- END android -----
         }
     }
 
diff --git a/ojluni/src/main/native/FileInputStream.c b/ojluni/src/main/native/FileInputStream.c
index bd16e0f..8d75a43 100755
--- a/ojluni/src/main/native/FileInputStream.c
+++ b/ojluni/src/main/native/FileInputStream.c
@@ -130,7 +130,7 @@
 }
 
 JNIEXPORT jint JNICALL
-FileInputStream_available(JNIEnv *env, jobject this) {
+FileInputStream_available0(JNIEnv *env, jobject this) {
     jlong ret;
     FD fd = GET_FD(this, fis_fd);
     if (fd == -1) {
@@ -156,7 +156,7 @@
   NATIVE_METHOD(FileInputStream, initIDs, "()V"),
   NATIVE_METHOD(FileInputStream, open, "(Ljava/lang/String;)V"),
   NATIVE_METHOD(FileInputStream, skip0, "(J)J"),
-  NATIVE_METHOD(FileInputStream, available, "()I"),
+  NATIVE_METHOD(FileInputStream, available0, "()I"),
   //NATIVE_METHOD(FileInputStream, read0, "()I"),
   //NATIVE_METHOD(FileInputStream, readBytes, "([BII)I"),
   //NATIVE_METHOD(FileInputStream, close0, "()V"),