Make ErrnoException a checked exception.

Bug: 4486011
Change-Id: I1877ce593d441653f75ab14884aa2d85f52652ad
diff --git a/luni/src/main/java/java/lang/ProcessManager.java b/luni/src/main/java/java/lang/ProcessManager.java
index f5afedb..c480185 100644
--- a/luni/src/main/java/java/lang/ProcessManager.java
+++ b/luni/src/main/java/java/lang/ProcessManager.java
@@ -105,7 +105,7 @@
                     waitForMoreChildren();
                     continue;
                 } else {
-                    throw errnoException;
+                    throw new AssertionError(errnoException);
                 }
             }
         }
diff --git a/luni/src/main/java/java/net/InetAddress.java b/luni/src/main/java/java/net/InetAddress.java
index a507f82..9009226 100644
--- a/luni/src/main/java/java/net/InetAddress.java
+++ b/luni/src/main/java/java/net/InetAddress.java
@@ -375,7 +375,7 @@
      *             if the address lookup fails.
      */
     public static InetAddress getLocalHost() throws UnknownHostException {
-        String host = Libcore.os.uname().nodename; // Can only throw EFAULT (which can't happen).
+        String host = Libcore.os.uname().nodename;
         return lookupHostByName(host)[0];
     }
 
diff --git a/luni/src/main/java/java/net/PlainDatagramSocketImpl.java b/luni/src/main/java/java/net/PlainDatagramSocketImpl.java
index f27db949..5d01469 100644
--- a/luni/src/main/java/java/net/PlainDatagramSocketImpl.java
+++ b/luni/src/main/java/java/net/PlainDatagramSocketImpl.java
@@ -28,6 +28,7 @@
 import java.net.SocketAddress;
 import java.net.SocketException;
 import java.net.UnknownHostException;
+import libcore.io.ErrnoException;
 import libcore.io.IoBridge;
 import libcore.io.Libcore;
 import libcore.io.StructGroupReq;
@@ -211,7 +212,11 @@
 
     @Override
     public void disconnect() {
-        Libcore.os.connect(fd, InetAddress.UNSPECIFIED, 0);
+        try {
+            Libcore.os.connect(fd, InetAddress.UNSPECIFIED, 0);
+        } catch (ErrnoException errnoException) {
+            throw new AssertionError(errnoException);
+        }
         connectedPort = -1;
         connectedAddress = null;
         isNativeConnected = false;
diff --git a/luni/src/main/java/java/nio/FileChannelImpl.java b/luni/src/main/java/java/nio/FileChannelImpl.java
index bc13efd..fc263b2 100644
--- a/luni/src/main/java/java/nio/FileChannelImpl.java
+++ b/luni/src/main/java/java/nio/FileChannelImpl.java
@@ -118,13 +118,18 @@
         flock.l_whence = (short) SEEK_SET;
         flock.l_start = position;
         flock.l_len = translateLockLength(size);
-        if (Libcore.os.fcntlFlock(fd, wait ? F_SETLKW64 : F_SETLK64, flock) == -1) {
-            // Lock acquisition failed.
-            removeLock(pendingLock);
-            return null;
-        }
 
-        return pendingLock;
+        boolean success = false;
+        try {
+            success = (Libcore.os.fcntlFlock(fd, wait ? F_SETLKW64 : F_SETLK64, flock) != -1);
+        } catch (ErrnoException errnoException) {
+            throw errnoException.rethrowAsIOException();
+        } finally {
+            if (!success) {
+                removeLock(pendingLock);
+            }
+        }
+        return success ? pendingLock : null;
     }
 
     private static long translateLockLength(long byteCount) {
diff --git a/luni/src/main/java/java/nio/SelectorImpl.java b/luni/src/main/java/java/nio/SelectorImpl.java
index dfd3270..786e05f 100644
--- a/luni/src/main/java/java/nio/SelectorImpl.java
+++ b/luni/src/main/java/java/nio/SelectorImpl.java
@@ -175,7 +175,11 @@
                         if (isBlock) {
                             begin();
                         }
-                        rc = Libcore.os.poll(pollFds.array(), (int) timeout);
+                        try {
+                            rc = Libcore.os.poll(pollFds.array(), (int) timeout);
+                        } catch (ErrnoException errnoException) {
+                            throw errnoException.rethrowAsIOException();
+                        }
                     } finally {
                         if (isBlock) {
                             end();
diff --git a/luni/src/main/java/java/nio/SocketChannelImpl.java b/luni/src/main/java/java/nio/SocketChannelImpl.java
index 9f8c690..0edb614 100644
--- a/luni/src/main/java/java/nio/SocketChannelImpl.java
+++ b/luni/src/main/java/java/nio/SocketChannelImpl.java
@@ -201,7 +201,12 @@
     }
 
     private void initLocalAddressAndPort() {
-        SocketAddress sa = Libcore.os.getsockname(fd);
+        SocketAddress sa;
+        try {
+            sa = Libcore.os.getsockname(fd);
+        } catch (ErrnoException errnoException) {
+            throw new AssertionError(errnoException);
+        }
         InetSocketAddress isa = (InetSocketAddress) sa;
         localAddress = isa.getAddress();
         localPort = isa.getPort();
diff --git a/luni/src/main/java/libcore/io/BlockGuardOs.java b/luni/src/main/java/libcore/io/BlockGuardOs.java
index e77e0bb..d664476 100644
--- a/luni/src/main/java/libcore/io/BlockGuardOs.java
+++ b/luni/src/main/java/libcore/io/BlockGuardOs.java
@@ -32,7 +32,7 @@
         super(os);
     }
 
-    private FileDescriptor tagSocket(FileDescriptor fd) {
+    private FileDescriptor tagSocket(FileDescriptor fd) throws ErrnoException {
         try {
             BlockGuard.tagSocketFd(fd);
             return fd;
diff --git a/luni/src/main/java/libcore/io/DiskLruCache.java b/luni/src/main/java/libcore/io/DiskLruCache.java
index c887541..ecc1302 100644
--- a/luni/src/main/java/libcore/io/DiskLruCache.java
+++ b/luni/src/main/java/libcore/io/DiskLruCache.java
@@ -337,9 +337,9 @@
     private static void deleteIfExists(File file) throws IOException {
         try {
             Libcore.os.remove(file.getPath());
-        } catch (ErrnoException e) {
-            if (e.errno != OsConstants.ENOENT) {
-                throw e;
+        } catch (ErrnoException errnoException) {
+            if (errnoException.errno != OsConstants.ENOENT) {
+                throw errnoException.rethrowAsIOException();
             }
         }
     }
@@ -801,4 +801,4 @@
             return new File(directory, key + "." + i + ".tmp");
         }
     }
-}
\ No newline at end of file
+}
diff --git a/luni/src/main/java/libcore/io/ErrnoException.java b/luni/src/main/java/libcore/io/ErrnoException.java
index c1d95d9..9eec566 100644
--- a/luni/src/main/java/libcore/io/ErrnoException.java
+++ b/luni/src/main/java/libcore/io/ErrnoException.java
@@ -21,11 +21,11 @@
 import libcore.io.OsConstants;
 
 /**
- * An unchecked exception thrown when {@link Os} methods fail. This exception contains the native
+ * A checked exception thrown when {@link Os} methods fail. This exception contains the native
  * errno value, for comparison against the constants in {@link OsConstants}, should sophisticated
  * callers need to adjust their behavior based on the exact failure.
  */
-public final class ErrnoException extends RuntimeException {
+public final class ErrnoException extends Exception {
     private final String functionName;
     public final int errno;
 
diff --git a/luni/src/main/java/libcore/io/ForwardingOs.java b/luni/src/main/java/libcore/io/ForwardingOs.java
index f205994..609beab 100644
--- a/luni/src/main/java/libcore/io/ForwardingOs.java
+++ b/luni/src/main/java/libcore/io/ForwardingOs.java
@@ -116,7 +116,7 @@
     public String strerror(int errno) { return os.strerror(errno); }
     public void symlink(String oldPath, String newPath) throws ErrnoException { os.symlink(oldPath, newPath); }
     public long sysconf(int name) { return os.sysconf(name); }
-    public StructUtsname uname() throws ErrnoException { return os.uname(); }
+    public StructUtsname uname() { return os.uname(); }
     public int waitpid(int pid, MutableInt status, int options) throws ErrnoException { return os.waitpid(pid, status, options); }
     public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException { return os.write(fd, buffer); }
     public int write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException { return os.write(fd, bytes, byteOffset, byteCount); }
diff --git a/luni/src/main/java/libcore/io/IoBridge.java b/luni/src/main/java/libcore/io/IoBridge.java
index c26b565..b983097 100644
--- a/luni/src/main/java/libcore/io/IoBridge.java
+++ b/luni/src/main/java/libcore/io/IoBridge.java
@@ -124,7 +124,7 @@
         }
     }
 
-    private static boolean connectErrno(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs) throws IOException {
+    private static boolean connectErrno(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs) throws ErrnoException, IOException {
         // With no timeout, just call connect(2) directly.
         if (timeoutMs == 0) {
             Libcore.os.connect(fd, inetAddress, port);
@@ -240,7 +240,7 @@
         }
     }
 
-    private static Object getSocketOptionErrno(FileDescriptor fd, int option) throws SocketException {
+    private static Object getSocketOptionErrno(FileDescriptor fd, int option) throws ErrnoException, SocketException {
         switch (option) {
         case SocketOptions.IP_MULTICAST_IF:
             // This is IPv4-only.
@@ -307,7 +307,7 @@
         }
     }
 
-    private static void setSocketOptionErrno(FileDescriptor fd, int option, Object value) throws SocketException {
+    private static void setSocketOptionErrno(FileDescriptor fd, int option, Object value) throws ErrnoException, SocketException {
         switch (option) {
         case SocketOptions.IP_MULTICAST_IF:
             throw new UnsupportedOperationException("Use IP_MULTICAST_IF2 on Android");
@@ -579,15 +579,22 @@
     }
 
     public static InetAddress getSocketLocalAddress(FileDescriptor fd) {
-        SocketAddress sa = Libcore.os.getsockname(fd);
-        InetSocketAddress isa = (InetSocketAddress) sa;
-        return isa.getAddress();
+        try {
+            SocketAddress sa = Libcore.os.getsockname(fd);
+            InetSocketAddress isa = (InetSocketAddress) sa;
+            return isa.getAddress();
+        } catch (ErrnoException errnoException) {
+            throw new AssertionError(errnoException);
+        }
     }
 
     public static int getSocketLocalPort(FileDescriptor fd) {
-        SocketAddress sa = Libcore.os.getsockname(fd);
-        InetSocketAddress isa = (InetSocketAddress) sa;
-        return isa.getPort();
+        try {
+            SocketAddress sa = Libcore.os.getsockname(fd);
+            InetSocketAddress isa = (InetSocketAddress) sa;
+            return isa.getPort();
+        } catch (ErrnoException errnoException) {
+            throw new AssertionError(errnoException);
+        }
     }
-
 }
diff --git a/luni/src/main/java/libcore/io/IoUtils.java b/luni/src/main/java/libcore/io/IoUtils.java
index 6680882..243d8d8 100644
--- a/luni/src/main/java/libcore/io/IoUtils.java
+++ b/luni/src/main/java/libcore/io/IoUtils.java
@@ -16,7 +16,6 @@
 
 package libcore.io;
 
-import java.io.Closeable;
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -44,13 +43,15 @@
     }
 
     /**
-     * Closes 'closeable', ignoring any exceptions. Does nothing if 'closeable' is null.
+     * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null.
      */
-    public static void closeQuietly(Closeable closeable) {
+    public static void closeQuietly(AutoCloseable closeable) {
         if (closeable != null) {
             try {
                 closeable.close();
-            } catch (IOException ignored) {
+            } catch (RuntimeException rethrown) {
+                throw rethrown;
+            } catch (Exception ignored) {
             }
         }
     }
diff --git a/luni/src/main/java/libcore/io/MemoryMappedFile.java b/luni/src/main/java/libcore/io/MemoryMappedFile.java
index f1fc027..1c106de 100644
--- a/luni/src/main/java/libcore/io/MemoryMappedFile.java
+++ b/luni/src/main/java/libcore/io/MemoryMappedFile.java
@@ -16,13 +16,13 @@
 
 package libcore.io;
 
-import java.io.Closeable;
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.nio.ByteOrder;
 import java.nio.NioUtils;
 import java.nio.channels.FileChannel;
+import libcore.io.ErrnoException;
 import libcore.io.Libcore;
 import libcore.io.Memory;
 import static libcore.io.OsConstants.*;
@@ -32,7 +32,7 @@
  * and either {@link #bigEndianIterator} or {@link #littleEndianIterator} to get a seekable
  * {@link BufferIterator} over the mapped data.
  */
-public final class MemoryMappedFile implements Closeable {
+public final class MemoryMappedFile implements AutoCloseable {
     private long address;
     private final long size;
 
@@ -47,7 +47,7 @@
     /**
      * Use this to mmap the whole file read-only.
      */
-    public static MemoryMappedFile mmapRO(String path) {
+    public static MemoryMappedFile mmapRO(String path) throws ErrnoException {
         FileDescriptor fd = Libcore.os.open(path, O_RDONLY, 0);
         long size = Libcore.os.fstat(fd).st_size;
         long address = Libcore.os.mmap(0L, size, PROT_READ, MAP_SHARED, fd, 0);
@@ -63,7 +63,7 @@
      * Calling this method invalidates any iterators over this {@code MemoryMappedFile}. It is an
      * error to use such an iterator after calling {@code close}.
      */
-    public synchronized void close() {
+    public synchronized void close() throws ErrnoException {
         if (address != 0) {
             Libcore.os.munmap(address, size);
             address = 0;
diff --git a/luni/src/main/java/libcore/io/Os.java b/luni/src/main/java/libcore/io/Os.java
index bd50998..07d1464 100644
--- a/luni/src/main/java/libcore/io/Os.java
+++ b/luni/src/main/java/libcore/io/Os.java
@@ -110,7 +110,7 @@
     public String strerror(int errno);
     public void symlink(String oldPath, String newPath) throws ErrnoException;
     public long sysconf(int name);
-    public StructUtsname uname() throws ErrnoException;
+    public StructUtsname uname();
     public int waitpid(int pid, MutableInt status, int options) throws ErrnoException;
     public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException;
     public int write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException;
diff --git a/luni/src/main/java/libcore/io/Posix.java b/luni/src/main/java/libcore/io/Posix.java
index f976209..d6cdd89 100644
--- a/luni/src/main/java/libcore/io/Posix.java
+++ b/luni/src/main/java/libcore/io/Posix.java
@@ -140,7 +140,7 @@
     public native String strerror(int errno);
     public native void symlink(String oldPath, String newPath) throws ErrnoException;
     public native long sysconf(int name);
-    public native StructUtsname uname() throws ErrnoException;
+    public native StructUtsname uname();
     public native int waitpid(int pid, MutableInt status, int options) throws ErrnoException;
     public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException {
         if (buffer.isDirect()) {
diff --git a/luni/src/main/java/libcore/util/ZoneInfoDB.java b/luni/src/main/java/libcore/util/ZoneInfoDB.java
index 75dcafe..69b6784 100644
--- a/luni/src/main/java/libcore/util/ZoneInfoDB.java
+++ b/luni/src/main/java/libcore/util/ZoneInfoDB.java
@@ -27,6 +27,7 @@
 import java.util.List;
 import java.util.TimeZone;
 import libcore.io.BufferIterator;
+import libcore.io.ErrnoException;
 import libcore.io.IoUtils;
 import libcore.io.MemoryMappedFile;
 
@@ -65,6 +66,15 @@
     private static final String VERSION = readVersion();
 
     /**
+     * Rather than open, read, and close the big data file each time we look up a time zone,
+     * we map the big data file during startup, and then just use the MemoryMappedFile.
+     *
+     * At the moment, this "big" data file is about 500 KiB. At some point, that will be small
+     * enough that we'll just keep the byte[] in memory.
+     */
+    private static final MemoryMappedFile ALL_ZONE_DATA = mapData();
+
+    /**
      * The 'ids' array contains time zone ids sorted alphabetically, for binary searching.
      * The other two arrays are in the same order. 'byteOffsets' gives the byte offset
      * into "zoneinfo.dat" of each time zone, and 'rawUtcOffsets' gives the time zone's
@@ -77,16 +87,8 @@
         readIndex();
     }
 
-    /**
-     * Rather than open, read, and close the big data file each time we look up a time zone,
-     * we map the big data file during startup, and then just use the MemoryMappedFile.
-     *
-     * At the moment, this "big" data file is about 500 KiB. At some point, that will be small
-     * enough that we'll just keep the byte[] in memory.
-     */
-    private static final MemoryMappedFile allZoneData = MemoryMappedFile.mmapRO(ZONE_FILE_NAME);
-
-    private ZoneInfoDB() {}
+    private ZoneInfoDB() {
+    }
 
     /**
      * Reads the file indicating the database version in use.
@@ -100,6 +102,14 @@
         }
     }
 
+    private static MemoryMappedFile mapData() {
+        try {
+            return MemoryMappedFile.mmapRO(ZONE_FILE_NAME);
+        } catch (ErrnoException errnoException) {
+            throw new AssertionError(errnoException);
+        }
+    }
+
     /**
      * Traditionally, Unix systems have one file per time zone. We have one big data file, which
      * is just a concatenation of regular time zone files. To allow random access into this big
@@ -111,17 +121,18 @@
      * All this code assumes strings are US-ASCII.
      */
     private static void readIndex() {
-        MemoryMappedFile mappedFile = MemoryMappedFile.mmapRO(INDEX_FILE_NAME);
+        MemoryMappedFile mappedFile = null;
         try {
+            mappedFile = MemoryMappedFile.mmapRO(INDEX_FILE_NAME);
             readIndex(mappedFile);
-        } catch (IOException ex) {
-            throw new RuntimeException(ex);
+        } catch (Exception ex) {
+            throw new AssertionError(ex);
         } finally {
             IoUtils.closeQuietly(mappedFile);
         }
     }
 
-    private static void readIndex(MemoryMappedFile mappedFile) throws IOException {
+    private static void readIndex(MemoryMappedFile mappedFile) throws ErrnoException, IOException {
         BufferIterator it = mappedFile.bigEndianIterator();
 
         // The database reserves 40 bytes for each id.
@@ -176,7 +187,7 @@
             return null;
         }
 
-        BufferIterator data = allZoneData.bigEndianIterator();
+        BufferIterator data = ALL_ZONE_DATA.bigEndianIterator();
         data.skip(byteOffsets[index]);
 
         // Variable names beginning tzh_ correspond to those in "tzfile.h".
diff --git a/luni/src/main/native/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp
index 28d01f1..97a9399 100644
--- a/luni/src/main/native/libcore_io_Posix.cpp
+++ b/luni/src/main/native/libcore_io_Posix.cpp
@@ -1164,8 +1164,8 @@
 
 static jobject Posix_uname(JNIEnv* env, jobject) {
     struct utsname buf;
-    if (throwIfMinusOne(env, "uname", TEMP_FAILURE_RETRY(uname(&buf))) == -1) {
-        return NULL;
+    if (TEMP_FAILURE_RETRY(uname(&buf)) == -1) {
+        return NULL; // Can't happen.
     }
     return makeStructUtsname(env, buf);
 }
diff --git a/luni/src/test/java/libcore/java/io/FileTest.java b/luni/src/test/java/libcore/java/io/FileTest.java
index df55222..d59111d 100644
--- a/luni/src/test/java/libcore/java/io/FileTest.java
+++ b/luni/src/test/java/libcore/java/io/FileTest.java
@@ -182,11 +182,11 @@
         assertEquals(target.getCanonicalPath(), linkName.getCanonicalPath());
     }
 
-    private static void ln_s(File target, File linkName) {
+    private static void ln_s(File target, File linkName) throws Exception {
         ln_s(target.toString(), linkName.toString());
     }
 
-    private static void ln_s(String target, String linkName) {
+    private static void ln_s(String target, String linkName) throws Exception {
         Libcore.os.symlink(target, linkName);
     }
 
diff --git a/support/src/test/java/tests/io/MockOs.java b/support/src/test/java/tests/io/MockOs.java
index 0cfe836..d7e284f 100644
--- a/support/src/test/java/tests/io/MockOs.java
+++ b/support/src/test/java/tests/io/MockOs.java
@@ -112,7 +112,7 @@
 
     public void enqueueFault(String methodName, final int errno) {
         getHandlers(methodName).add(new InvocationHandler() {
-            @Override public Object invoke(Object proxy, Method method, Object[] args) {
+            @Override public Object invoke(Object proxy, Method method, Object[] args) throws ErrnoException {
                 throw new ErrnoException(method.getName(), errno);
             }
         });