Automatic sources dropoff on 2020-06-10 18:32:38.095721

The change is generated with prebuilt drop tool.

Change-Id: I24cbf6ba6db262a1ae1445db1427a08fee35b3b4
diff --git a/java/net/AbstractPlainDatagramSocketImpl.java b/java/net/AbstractPlainDatagramSocketImpl.java
new file mode 100644
index 0000000..a3c738a
--- /dev/null
+++ b/java/net/AbstractPlainDatagramSocketImpl.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+
+import libcore.io.IoBridge;
+import libcore.io.IoUtils;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.security.AccessController;
+
+import dalvik.system.BlockGuard;
+import dalvik.system.CloseGuard;
+import sun.net.ResourceManager;
+
+/**
+ * Abstract datagram and multicast socket implementation base class.
+ * Note: This is not a public class, so that applets cannot call
+ * into the implementation directly and hence cannot bypass the
+ * security checks present in the DatagramSocket and MulticastSocket
+ * classes.
+ *
+ * @author Pavani Diwanji
+ */
+
+abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl
+{
+    /* timeout value for receive() */
+    int timeout = 0;
+    boolean connected = false;
+    private int trafficClass = 0;
+    protected InetAddress connectedAddress = null;
+    private int connectedPort = -1;
+
+    // Android-added: CloseGuard
+    private final CloseGuard guard = CloseGuard.get();
+
+    private static final String os = AccessController.doPrivileged(
+        new sun.security.action.GetPropertyAction("os.name")
+    );
+
+    /**
+     * flag set if the native connect() call not to be used
+     */
+    private final static boolean connectDisabled = os.contains("OS X");
+
+    // BEGIN Android-removed: Android doesn't need to load native net library
+    /**
+     * Load net library into runtime.
+     *
+    static {
+        java.security.AccessController.doPrivileged(
+            new java.security.PrivilegedAction<Void>() {
+                public Void run() {
+                    System.loadLibrary("net");
+                    return null;
+                }
+            });
+    }
+    */
+    // END Android-removed: Android doesn't need to load native net library
+
+    /**
+     * Creates a datagram socket
+     */
+    protected synchronized void create() throws SocketException {
+        ResourceManager.beforeUdpCreate();
+        fd = new FileDescriptor();
+        try {
+            datagramSocketCreate();
+        } catch (SocketException ioe) {
+            ResourceManager.afterUdpClose();
+            fd = null;
+            throw ioe;
+        }
+
+        // Android-added: CloseGuard/fdsan
+        if (fd != null && fd.valid()) {
+            guard.open("close");
+            IoUtils.setFdOwner(fd, this);
+        }
+    }
+
+    /**
+     * Binds a datagram socket to a local port.
+     */
+    protected synchronized void bind(int lport, InetAddress laddr)
+        throws SocketException {
+        bind0(lport, laddr);
+    }
+
+    protected abstract void bind0(int lport, InetAddress laddr)
+        throws SocketException;
+
+    /**
+     * Sends a datagram packet. The packet contains the data and the
+     * destination address to send the packet to.
+     * @param p the packet to be sent.
+     */
+    protected abstract void send(DatagramPacket p) throws IOException;
+
+    /**
+     * Connects a datagram socket to a remote destination. This associates the remote
+     * address with the local socket so that datagrams may only be sent to this destination
+     * and received from this destination.
+     * @param address the remote InetAddress to connect to
+     * @param port the remote port number
+     */
+    protected void connect(InetAddress address, int port) throws SocketException {
+        // Android-added: BlockGuard
+        BlockGuard.getThreadPolicy().onNetwork();
+        connect0(address, port);
+        connectedAddress = address;
+        connectedPort = port;
+        connected = true;
+    }
+
+    /**
+     * Disconnects a previously connected socket. Does nothing if the socket was
+     * not connected already.
+     */
+    protected void disconnect() {
+        disconnect0(connectedAddress.holder().getFamily());
+        connected = false;
+        connectedAddress = null;
+        connectedPort = -1;
+    }
+
+    /**
+     * Peek at the packet to see who it is from.
+     * @param i the address to populate with the sender address
+     */
+    protected abstract int peek(InetAddress i) throws IOException;
+    protected abstract int peekData(DatagramPacket p) throws IOException;
+    /**
+     * Receive the datagram packet.
+     * @param p the packet to receive into
+     */
+    protected synchronized void receive(DatagramPacket p)
+        throws IOException {
+        receive0(p);
+    }
+
+    protected abstract void receive0(DatagramPacket p)
+        throws IOException;
+
+    /**
+     * Set the TTL (time-to-live) option.
+     * @param ttl TTL to be set.
+     */
+    protected abstract void setTimeToLive(int ttl) throws IOException;
+
+    /**
+     * Get the TTL (time-to-live) option.
+     */
+    protected abstract int getTimeToLive() throws IOException;
+
+    /**
+     * Set the TTL (time-to-live) option.
+     * @param ttl TTL to be set.
+     */
+    @Deprecated
+    protected abstract void setTTL(byte ttl) throws IOException;
+
+    /**
+     * Get the TTL (time-to-live) option.
+     */
+    @Deprecated
+    protected abstract byte getTTL() throws IOException;
+
+    /**
+     * Join the multicast group.
+     * @param inetaddr multicast address to join.
+     */
+    protected void join(InetAddress inetaddr) throws IOException {
+        join(inetaddr, null);
+    }
+
+    /**
+     * Leave the multicast group.
+     * @param inetaddr multicast address to leave.
+     */
+    protected void leave(InetAddress inetaddr) throws IOException {
+        leave(inetaddr, null);
+    }
+    /**
+     * Join the multicast group.
+     * @param mcastaddr multicast address to join.
+     * @param netIf specifies the local interface to receive multicast
+     *        datagram packets
+     * @throws  IllegalArgumentException if mcastaddr is null or is a
+     *          SocketAddress subclass not supported by this socket
+     * @since 1.4
+     */
+
+    protected void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf)
+        throws IOException {
+        if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress))
+            throw new IllegalArgumentException("Unsupported address type");
+        join(((InetSocketAddress)mcastaddr).getAddress(), netIf);
+    }
+
+    protected abstract void join(InetAddress inetaddr, NetworkInterface netIf)
+        throws IOException;
+
+    /**
+     * Leave the multicast group.
+     * @param mcastaddr  multicast address to leave.
+     * @param netIf specified the local interface to leave the group at
+     * @throws  IllegalArgumentException if mcastaddr is null or is a
+     *          SocketAddress subclass not supported by this socket
+     * @since 1.4
+     */
+    protected void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf)
+        throws IOException {
+        if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress))
+            throw new IllegalArgumentException("Unsupported address type");
+        leave(((InetSocketAddress)mcastaddr).getAddress(), netIf);
+    }
+
+    protected abstract void leave(InetAddress inetaddr, NetworkInterface netIf)
+        throws IOException;
+
+    /**
+     * Close the socket.
+     */
+    protected void close() {
+        // Android-added: CloseGuard
+        guard.close();
+
+        if (fd != null) {
+            datagramSocketClose();
+            ResourceManager.afterUdpClose();
+            fd = null;
+        }
+    }
+
+    protected boolean isClosed() {
+        return (fd == null) ? true : false;
+    }
+
+    protected void finalize() {
+        // Android-added: CloseGuard
+        if (guard != null) {
+            guard.warnIfOpen();
+        }
+
+        close();
+    }
+
+    /**
+     * set a value - since we only support (setting) binary options
+     * here, o must be a Boolean
+     */
+
+     public void setOption(int optID, Object o) throws SocketException {
+         if (isClosed()) {
+             throw new SocketException("Socket Closed");
+         }
+         switch (optID) {
+            /* check type safety b4 going native.  These should never
+             * fail, since only java.Socket* has access to
+             * PlainSocketImpl.setOption().
+             */
+         case SO_TIMEOUT:
+             if (o == null || !(o instanceof Integer)) {
+                 throw new SocketException("bad argument for SO_TIMEOUT");
+             }
+             int tmp = ((Integer) o).intValue();
+             if (tmp < 0)
+                 throw new IllegalArgumentException("timeout < 0");
+             timeout = tmp;
+             return;
+         case IP_TOS:
+             if (o == null || !(o instanceof Integer)) {
+                 throw new SocketException("bad argument for IP_TOS");
+             }
+             trafficClass = ((Integer)o).intValue();
+             break;
+         case SO_REUSEADDR:
+             if (o == null || !(o instanceof Boolean)) {
+                 throw new SocketException("bad argument for SO_REUSEADDR");
+             }
+             break;
+         case SO_BROADCAST:
+             if (o == null || !(o instanceof Boolean)) {
+                 throw new SocketException("bad argument for SO_BROADCAST");
+             }
+             break;
+         case SO_BINDADDR:
+             throw new SocketException("Cannot re-bind Socket");
+         case SO_RCVBUF:
+         case SO_SNDBUF:
+             if (o == null || !(o instanceof Integer) ||
+                 ((Integer)o).intValue() < 0) {
+                 throw new SocketException("bad argument for SO_SNDBUF or " +
+                                           "SO_RCVBUF");
+             }
+             break;
+         case IP_MULTICAST_IF:
+             if (o == null || !(o instanceof InetAddress))
+                 throw new SocketException("bad argument for IP_MULTICAST_IF");
+             break;
+         case IP_MULTICAST_IF2:
+             // Android-changed: Support Integer IP_MULTICAST_IF2 values for app compat. b/26790580
+             // if (o == null || !(o instanceof NetworkInterface))
+             if (o == null || !(o instanceof Integer || o instanceof NetworkInterface))
+                 throw new SocketException("bad argument for IP_MULTICAST_IF2");
+             if (o instanceof NetworkInterface) {
+                 o = new Integer(((NetworkInterface)o).getIndex());
+             }
+             break;
+         case IP_MULTICAST_LOOP:
+             if (o == null || !(o instanceof Boolean))
+                 throw new SocketException("bad argument for IP_MULTICAST_LOOP");
+             break;
+         default:
+             throw new SocketException("invalid option: " + optID);
+         }
+         socketSetOption(optID, o);
+     }
+
+    /*
+     * get option's state - set or not
+     */
+
+    public Object getOption(int optID) throws SocketException {
+        if (isClosed()) {
+            throw new SocketException("Socket Closed");
+        }
+
+        Object result;
+
+        switch (optID) {
+            case SO_TIMEOUT:
+                result = new Integer(timeout);
+                break;
+
+            case IP_TOS:
+                result = socketGetOption(optID);
+                if ( ((Integer)result).intValue() == -1) {
+                    result = new Integer(trafficClass);
+                }
+                break;
+
+            case SO_BINDADDR:
+            case IP_MULTICAST_IF:
+            case IP_MULTICAST_IF2:
+            case SO_RCVBUF:
+            case SO_SNDBUF:
+            case IP_MULTICAST_LOOP:
+            case SO_REUSEADDR:
+            case SO_BROADCAST:
+                result = socketGetOption(optID);
+                // Android-added: Added for app compat reason. See methodgetNIFirstAddress
+                if (optID == IP_MULTICAST_IF) {
+                    return getNIFirstAddress((Integer)result);
+                }
+                break;
+
+            default:
+                throw new SocketException("invalid option: " + optID);
+        }
+
+        return result;
+    }
+
+    // BEGIN Android-added: Support Integer IP_MULTICAST_IF2 values for app compat. b/26790580
+    // Native code is changed to return the index of network interface when calling
+    // getOption(IP_MULTICAST_IF2) due to app compat reason.
+    //
+    // For getOption(IP_MULTICAST_IF), we should keep returning InetAddress instance. This method
+    // convert NetworkInterface index into InetAddress instance.
+    /** Return the first address bound to NetworkInterface with given ID.
+     * In case of niIndex == 0 or no address return anyLocalAddress
+     */
+    static InetAddress getNIFirstAddress(int niIndex) throws SocketException {
+        if (niIndex > 0) {
+            NetworkInterface networkInterface = NetworkInterface.getByIndex(niIndex);
+            Enumeration<InetAddress> addressesEnum = networkInterface.getInetAddresses();
+            if (addressesEnum.hasMoreElements()) {
+                return addressesEnum.nextElement();
+            }
+        }
+        return InetAddress.anyLocalAddress();
+    }
+    // END Android-added: Support Integer IP_MULTICAST_IF2 values for app compat. b/26790580
+
+    protected abstract void datagramSocketCreate() throws SocketException;
+    protected abstract void datagramSocketClose();
+    protected abstract void socketSetOption(int opt, Object val)
+        throws SocketException;
+    protected abstract Object socketGetOption(int opt) throws SocketException;
+
+    protected abstract void connect0(InetAddress address, int port) throws SocketException;
+    protected abstract void disconnect0(int family);
+
+    protected boolean nativeConnectDisabled() {
+        return connectDisabled;
+    }
+
+    // Android-changed: rewritten on the top of IoBridge
+    int dataAvailable() {
+        try {
+            return IoBridge.available(fd);
+        } catch (IOException e) {
+            return -1;
+        }
+    }
+}
diff --git a/java/net/AbstractPlainSocketImpl.java b/java/net/AbstractPlainSocketImpl.java
new file mode 100644
index 0000000..0500811
--- /dev/null
+++ b/java/net/AbstractPlainSocketImpl.java
@@ -0,0 +1,794 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileDescriptor;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import dalvik.system.BlockGuard;
+import dalvik.system.CloseGuard;
+import dalvik.system.SocketTagger;
+import sun.net.ConnectionResetException;
+import sun.net.NetHooks;
+import sun.net.ResourceManager;
+
+/**
+ * Default Socket Implementation. This implementation does
+ * not implement any security checks.
+ * Note this class should <b>NOT</b> be public.
+ *
+ * @author  Steven B. Byrne
+ */
+abstract class AbstractPlainSocketImpl extends SocketImpl
+{
+    /* instance variable for SO_TIMEOUT */
+    int timeout;   // timeout in millisec
+    // Android-removed: traffic class is set through socket
+    // private int trafficClass;
+
+    private boolean shut_rd = false;
+    private boolean shut_wr = false;
+
+    private SocketInputStream socketInputStream = null;
+    private SocketOutputStream socketOutputStream = null;
+
+    /* number of threads using the FileDescriptor */
+    protected int fdUseCount = 0;
+
+    /* lock when increment/decrementing fdUseCount */
+    // Android-added: @ReachabilitySensitive
+    // Marked mostly because it's used where fd is, and fd isn't declared here.
+    // This adds reachabilityFences where we would if fd were annotated.
+    @ReachabilitySensitive
+    protected final Object fdLock = new Object();
+
+    /* indicates a close is pending on the file descriptor */
+    protected boolean closePending = false;
+
+    /* indicates connection reset state */
+    private int CONNECTION_NOT_RESET = 0;
+    private int CONNECTION_RESET_PENDING = 1;
+    private int CONNECTION_RESET = 2;
+    private int resetState;
+    private final Object resetLock = new Object();
+
+   /* whether this Socket is a stream (TCP) socket or not (UDP)
+    */
+    protected boolean stream;
+
+    // BEGIN Android-removed: Android doesn't need to load native net library
+    /*
+    /**
+     * Load net library into runtime.
+     *
+    static {
+        java.security.AccessController.doPrivileged(
+            new java.security.PrivilegedAction<Void>() {
+                public Void run() {
+                    System.loadLibrary("net");
+                    return null;
+                }
+            });
+    }
+    */
+    // END Android-removed: Android doesn't need to load native net library
+
+    // Android-added: logs a warning if socket is not closed
+    @ReachabilitySensitive
+    private final CloseGuard guard = CloseGuard.get();
+
+    /**
+     * Creates a socket with a boolean that specifies whether this
+     * is a stream socket (true) or an unconnected UDP socket (false).
+     */
+    protected synchronized void create(boolean stream) throws IOException {
+        this.stream = stream;
+        if (!stream) {
+            ResourceManager.beforeUdpCreate();
+            // Android-removed: socketCreate should set fd if it succeeds
+            // fd = new FileDescriptor();
+            try {
+                socketCreate(false);
+            } catch (IOException ioe) {
+                ResourceManager.afterUdpClose();
+                // Android-removed: b/26470377 Represent closed sockets with invalid fd, not null.
+                // fd = null;
+                throw ioe;
+            }
+        } else {
+            // Android-removed: socketCreate should set fd if it succeeds
+            // fd = new FileDescriptor();
+            socketCreate(true);
+        }
+        if (socket != null)
+            socket.setCreated();
+        if (serverSocket != null)
+            serverSocket.setCreated();
+
+        // Android-added: CloseGuard
+        if (fd != null && fd.valid()) {
+            guard.open("close");
+        }
+    }
+
+    /**
+     * Creates a socket and connects it to the specified port on
+     * the specified host.
+     * @param host the specified host
+     * @param port the specified port
+     */
+    protected void connect(String host, int port)
+        throws UnknownHostException, IOException
+    {
+        boolean connected = false;
+        try {
+            InetAddress address = InetAddress.getByName(host);
+            this.port = port;
+            this.address = address;
+
+            connectToAddress(address, port, timeout);
+            connected = true;
+        } finally {
+            if (!connected) {
+                try {
+                    close();
+                } catch (IOException ioe) {
+                    /* Do nothing. If connect threw an exception then
+                       it will be passed up the call stack */
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates a socket and connects it to the specified address on
+     * the specified port.
+     * @param address the address
+     * @param port the specified port
+     */
+    protected void connect(InetAddress address, int port) throws IOException {
+        this.port = port;
+        this.address = address;
+
+        try {
+            connectToAddress(address, port, timeout);
+            return;
+        } catch (IOException e) {
+            // everything failed
+            close();
+            throw e;
+        }
+    }
+
+    /**
+     * Creates a socket and connects it to the specified address on
+     * the specified port.
+     * @param address the address
+     * @param timeout the timeout value in milliseconds, or zero for no timeout.
+     * @throws IOException if connection fails
+     * @throws  IllegalArgumentException if address is null or is a
+     *          SocketAddress subclass not supported by this socket
+     * @since 1.4
+     */
+    protected void connect(SocketAddress address, int timeout)
+            throws IOException {
+        boolean connected = false;
+        try {
+            if (address == null || !(address instanceof InetSocketAddress))
+                throw new IllegalArgumentException("unsupported address type");
+            InetSocketAddress addr = (InetSocketAddress) address;
+            if (addr.isUnresolved())
+                throw new UnknownHostException(addr.getHostName());
+            this.port = addr.getPort();
+            this.address = addr.getAddress();
+
+            connectToAddress(this.address, port, timeout);
+            connected = true;
+        } finally {
+            if (!connected) {
+                try {
+                    close();
+                } catch (IOException ioe) {
+                    /* Do nothing. If connect threw an exception then
+                       it will be passed up the call stack */
+                }
+            }
+        }
+    }
+
+    private void connectToAddress(InetAddress address, int port, int timeout) throws IOException {
+        if (address.isAnyLocalAddress()) {
+            doConnect(InetAddress.getLocalHost(), port, timeout);
+        } else {
+            doConnect(address, port, timeout);
+        }
+    }
+
+    public void setOption(int opt, Object val) throws SocketException {
+        if (isClosedOrPending()) {
+            throw new SocketException("Socket Closed");
+        }
+        // BEGIN Android-removed: Logic dealing with value type moved to socketSetOption.
+        /*
+        boolean on = true;
+        switch (opt) {
+            /* check type safety b4 going native.  These should never
+             * fail, since only java.Socket* has access to
+             * PlainSocketImpl.setOption().
+             *
+        case SO_LINGER:
+            if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean)))
+                throw new SocketException("Bad parameter for option");
+            if (val instanceof Boolean) {
+                /* true only if disabling - enabling should be Integer *
+                on = false;
+            }
+            break;
+        case SO_TIMEOUT:
+            if (val == null || (!(val instanceof Integer)))
+                throw new SocketException("Bad parameter for SO_TIMEOUT");
+            int tmp = ((Integer) val).intValue();
+            if (tmp < 0)
+                throw new IllegalArgumentException("timeout < 0");
+            timeout = tmp;
+            break;
+        case IP_TOS:
+             if (val == null || !(val instanceof Integer)) {
+                 throw new SocketException("bad argument for IP_TOS");
+             }
+             trafficClass = ((Integer)val).intValue();
+             break;
+        case SO_BINDADDR:
+            throw new SocketException("Cannot re-bind socket");
+        case TCP_NODELAY:
+            if (val == null || !(val instanceof Boolean))
+                throw new SocketException("bad parameter for TCP_NODELAY");
+            on = ((Boolean)val).booleanValue();
+            break;
+        case SO_SNDBUF:
+        case SO_RCVBUF:
+            if (val == null || !(val instanceof Integer) ||
+                !(((Integer)val).intValue() > 0)) {
+                throw new SocketException("bad parameter for SO_SNDBUF " +
+                                          "or SO_RCVBUF");
+            }
+            break;
+        case SO_KEEPALIVE:
+            if (val == null || !(val instanceof Boolean))
+                throw new SocketException("bad parameter for SO_KEEPALIVE");
+            on = ((Boolean)val).booleanValue();
+            break;
+        case SO_OOBINLINE:
+            if (val == null || !(val instanceof Boolean))
+                throw new SocketException("bad parameter for SO_OOBINLINE");
+            on = ((Boolean)val).booleanValue();
+            break;
+        case SO_REUSEADDR:
+            if (val == null || !(val instanceof Boolean))
+                throw new SocketException("bad parameter for SO_REUSEADDR");
+            on = ((Boolean)val).booleanValue();
+            break;
+        default:
+            throw new SocketException("unrecognized TCP option: " + opt);
+        }
+        socketSetOption(opt, on, val);
+        */
+        // END Android-removed: Logic dealing with value type moved to socketSetOption.
+        // Android-added: Keep track of timeout value not handled by socketSetOption
+        if (opt == SO_TIMEOUT) {
+            timeout = (Integer) val;
+        }
+        socketSetOption(opt, val);
+    }
+    public Object getOption(int opt) throws SocketException {
+        if (isClosedOrPending()) {
+            throw new SocketException("Socket Closed");
+        }
+        if (opt == SO_TIMEOUT) {
+            return new Integer(timeout);
+        }
+        // BEGIN Android-changed: Logic dealing with value type moved to socketGetOption.
+        /*
+        int ret = 0;
+        /*
+         * The native socketGetOption() knows about 3 options.
+         * The 32 bit value it returns will be interpreted according
+         * to what we're asking.  A return of -1 means it understands
+         * the option but its turned off.  It will raise a SocketException
+         * if "opt" isn't one it understands.
+         *
+
+        switch (opt) {
+        case TCP_NODELAY:
+            ret = socketGetOption(opt, null);
+            return Boolean.valueOf(ret != -1);
+        case SO_OOBINLINE:
+            ret = socketGetOption(opt, null);
+            return Boolean.valueOf(ret != -1);
+        case SO_LINGER:
+            ret = socketGetOption(opt, null);
+            return (ret == -1) ? Boolean.FALSE: (Object)(new Integer(ret));
+        case SO_REUSEADDR:
+            ret = socketGetOption(opt, null);
+            return Boolean.valueOf(ret != -1);
+        case SO_BINDADDR:
+            InetAddressContainer in = new InetAddressContainer();
+            ret = socketGetOption(opt, in);
+            return in.addr;
+        case SO_SNDBUF:
+        case SO_RCVBUF:
+            ret = socketGetOption(opt, null);
+            return new Integer(ret);
+        case IP_TOS:
+            try {
+                ret = socketGetOption(opt, null);
+                if (ret == -1) { // ipv6 tos
+                    return trafficClass;
+                } else {
+                    return ret;
+                }
+            } catch (SocketException se) {
+                // TODO - should make better effort to read TOS or TCLASS
+                return trafficClass; // ipv6 tos
+            }
+        case SO_KEEPALIVE:
+            ret = socketGetOption(opt, null);
+            return Boolean.valueOf(ret != -1);
+        // should never get here
+        default:
+            return null;
+        }
+        */
+        return socketGetOption(opt);
+        // END Android-changed: Logic dealing with value type moved to socketGetOption.
+    }
+
+    /**
+     * The workhorse of the connection operation.  Tries several times to
+     * establish a connection to the given <host, port>.  If unsuccessful,
+     * throws an IOException indicating what went wrong.
+     */
+
+    synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException {
+        synchronized (fdLock) {
+            if (!closePending && (socket == null || !socket.isBound())) {
+                NetHooks.beforeTcpConnect(fd, address, port);
+            }
+        }
+        try {
+            acquireFD();
+            try {
+                // Android-added: BlockGuard
+                BlockGuard.getThreadPolicy().onNetwork();
+                socketConnect(address, port, timeout);
+                /* socket may have been closed during poll/select */
+                synchronized (fdLock) {
+                    if (closePending) {
+                        throw new SocketException ("Socket closed");
+                    }
+                }
+                // If we have a ref. to the Socket, then sets the flags
+                // created, bound & connected to true.
+                // This is normally done in Socket.connect() but some
+                // subclasses of Socket may call impl.connect() directly!
+                if (socket != null) {
+                    socket.setBound();
+                    socket.setConnected();
+                }
+            } finally {
+                releaseFD();
+            }
+        } catch (IOException e) {
+            close();
+            throw e;
+        }
+    }
+
+    /**
+     * Binds the socket to the specified address of the specified local port.
+     * @param address the address
+     * @param lport the port
+     */
+    protected synchronized void bind(InetAddress address, int lport)
+        throws IOException
+    {
+       synchronized (fdLock) {
+            if (!closePending && (socket == null || !socket.isBound())) {
+                NetHooks.beforeTcpBind(fd, address, lport);
+            }
+        }
+        socketBind(address, lport);
+        if (socket != null)
+            socket.setBound();
+        if (serverSocket != null)
+            serverSocket.setBound();
+    }
+
+    /**
+     * Listens, for a specified amount of time, for connections.
+     * @param count the amount of time to listen for connections
+     */
+    protected synchronized void listen(int count) throws IOException {
+        socketListen(count);
+    }
+
+    /**
+     * Accepts connections.
+     * @param s the connection
+     */
+    protected void accept(SocketImpl s) throws IOException {
+        acquireFD();
+        try {
+            // Android-added: BlockGuard
+            BlockGuard.getThreadPolicy().onNetwork();
+            socketAccept(s);
+        } finally {
+            releaseFD();
+        }
+    }
+
+    /**
+     * Gets an InputStream for this socket.
+     */
+    protected synchronized InputStream getInputStream() throws IOException {
+        synchronized (fdLock) {
+            if (isClosedOrPending())
+                throw new IOException("Socket Closed");
+            if (shut_rd)
+                throw new IOException("Socket input is shutdown");
+            if (socketInputStream == null)
+                socketInputStream = new SocketInputStream(this);
+        }
+        return socketInputStream;
+    }
+
+    void setInputStream(SocketInputStream in) {
+        socketInputStream = in;
+    }
+
+    /**
+     * Gets an OutputStream for this socket.
+     */
+    protected synchronized OutputStream getOutputStream() throws IOException {
+        synchronized (fdLock) {
+            if (isClosedOrPending())
+                throw new IOException("Socket Closed");
+            if (shut_wr)
+                throw new IOException("Socket output is shutdown");
+            if (socketOutputStream == null)
+                socketOutputStream = new SocketOutputStream(this);
+        }
+        return socketOutputStream;
+    }
+
+    // Android-removed: this.fd is maintained by the concrete implementation.
+    /*
+    void setFileDescriptor(FileDescriptor fd) {
+        this.fd = fd;
+    }
+    */
+
+    void setAddress(InetAddress address) {
+        this.address = address;
+    }
+
+    void setPort(int port) {
+        this.port = port;
+    }
+
+    void setLocalPort(int localport) {
+        this.localport = localport;
+    }
+
+    /**
+     * Returns the number of bytes that can be read without blocking.
+     */
+    protected synchronized int available() throws IOException {
+        if (isClosedOrPending()) {
+            throw new IOException("Stream closed.");
+        }
+
+        /*
+         * If connection has been reset or shut down for input, then return 0
+         * to indicate there are no buffered bytes.
+         */
+        if (isConnectionReset() || shut_rd) {
+            return 0;
+        }
+
+        /*
+         * If no bytes available and we were previously notified
+         * of a connection reset then we move to the reset state.
+         *
+         * If are notified of a connection reset then check
+         * again if there are bytes buffered on the socket.
+         */
+        int n = 0;
+        try {
+            n = socketAvailable();
+            if (n == 0 && isConnectionResetPending()) {
+                setConnectionReset();
+            }
+        } catch (ConnectionResetException exc1) {
+            setConnectionResetPending();
+            try {
+                n = socketAvailable();
+                if (n == 0) {
+                    setConnectionReset();
+                }
+            } catch (ConnectionResetException exc2) {
+            }
+        }
+        return n;
+    }
+
+    /**
+     * Closes the socket.
+     */
+    protected void close() throws IOException {
+        synchronized(fdLock) {
+            if (fd != null && fd.valid()) {
+                if (!stream) {
+                    ResourceManager.afterUdpClose();
+                }
+                // Android-changed:
+                // Socket should be untagged before the preclose. After preclose,
+                // socket will dup2-ed to marker_fd, therefore, it won't describe the same file.
+                // If closingPending is true, then the socket has been preclosed.
+                //
+                // Also, close the CloseGuard when the #close is called.
+                if (!closePending) {
+                    closePending = true;
+                    guard.close();
+
+                    if (fdUseCount == 0) {
+                        /*
+                         * We close the FileDescriptor in two-steps - first the
+                         * "pre-close" which closes the socket but doesn't
+                         * release the underlying file descriptor. This operation
+                         * may be lengthy due to untransmitted data and a long
+                         * linger interval. Once the pre-close is done we do the
+                         * actual socket to release the fd.
+                         */
+                        try {
+                            socketPreClose();
+                        } finally {
+                            socketClose();
+                        }
+                        // Android-changed(http://b/26470377): Some Android code doesn't expect file
+                        // descriptor to be null. socketClose invalidates the fd by closing the fd.
+                        // fd = null;
+                        return;
+                    } else {
+                        /*
+                         * If a thread has acquired the fd and a close
+                         * isn't pending then use a deferred close.
+                         * Also decrement fdUseCount to signal the last
+                         * thread that releases the fd to close it.
+                         */
+                        fdUseCount--;
+                        socketPreClose();
+                    }
+                }
+            }
+        }
+    }
+
+    void reset() throws IOException {
+        if (fd != null && fd.valid()) {
+            socketClose();
+            // Android-changed: Notified the CloseGuard object as the fd has been released.
+            guard.close();
+        }
+        // Android-removed: b/26470377 Represent closed sockets with invalid fd, not null.
+        // fd = null;
+        super.reset();
+    }
+
+
+    /**
+     * Shutdown read-half of the socket connection;
+     */
+    protected void shutdownInput() throws IOException {
+      // Android-changed: b/26470377 Represent closed sockets with invalid fd, not null.
+      if (fd != null && fd.valid()) {
+          socketShutdown(SHUT_RD);
+          if (socketInputStream != null) {
+              socketInputStream.setEOF(true);
+          }
+          shut_rd = true;
+      }
+    }
+
+    /**
+     * Shutdown write-half of the socket connection;
+     */
+    protected void shutdownOutput() throws IOException {
+      // Android-changed: b/26470377 Represent closed sockets with invalid fd, not null.
+      if (fd != null && fd.valid()) {
+          socketShutdown(SHUT_WR);
+          shut_wr = true;
+      }
+    }
+
+    protected boolean supportsUrgentData () {
+        return true;
+    }
+
+    protected void sendUrgentData (int data) throws IOException {
+        // Android-changed: b/26470377 Represent closed sockets with invalid fd, not null.
+        if (fd == null || !fd.valid()) {
+            throw new IOException("Socket Closed");
+        }
+        socketSendUrgentData (data);
+    }
+
+    /**
+     * Cleans up if the user forgets to close it.
+     */
+    protected void finalize() throws IOException {
+        // Android-added: CloseGuard
+        if (guard != null) {
+            guard.warnIfOpen();
+        }
+
+        close();
+    }
+
+    /*
+     * "Acquires" and returns the FileDescriptor for this impl
+     *
+     * A corresponding releaseFD is required to "release" the
+     * FileDescriptor.
+     */
+    FileDescriptor acquireFD() {
+        synchronized (fdLock) {
+            fdUseCount++;
+            return fd;
+        }
+    }
+
+    /*
+     * "Release" the FileDescriptor for this impl.
+     *
+     * If the use count goes to -1 then the socket is closed.
+     */
+    void releaseFD() {
+        synchronized (fdLock) {
+            fdUseCount--;
+            if (fdUseCount == -1) {
+                if (fd != null) {
+                    try {
+                        socketClose();
+                    } catch (IOException e) {
+                        // Android-removed: b/26470377 Some Android code doesn't expect file
+                        // descriptor to be null. socketClose invalidates the fd by closing the fd.
+                        // } finally {
+                        //     fd = null;
+                    }
+                }
+            }
+        }
+    }
+
+    public boolean isConnectionReset() {
+        synchronized (resetLock) {
+            return (resetState == CONNECTION_RESET);
+        }
+    }
+
+    public boolean isConnectionResetPending() {
+        synchronized (resetLock) {
+            return (resetState == CONNECTION_RESET_PENDING);
+        }
+    }
+
+    public void setConnectionReset() {
+        synchronized (resetLock) {
+            resetState = CONNECTION_RESET;
+        }
+    }
+
+    public void setConnectionResetPending() {
+        synchronized (resetLock) {
+            if (resetState == CONNECTION_NOT_RESET) {
+                resetState = CONNECTION_RESET_PENDING;
+            }
+        }
+
+    }
+
+    /*
+     * Return true if already closed or close is pending
+     */
+    public boolean isClosedOrPending() {
+        /*
+         * Lock on fdLock to ensure that we wait if a
+         * close is in progress.
+         */
+        synchronized (fdLock) {
+            // Android-changed: b/26470377 Represent closed sockets with invalid fd, not null.
+            if (closePending || (fd == null) || !fd.valid()) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /*
+     * Return the current value of SO_TIMEOUT
+     */
+    public int getTimeout() {
+        return timeout;
+    }
+
+    /*
+     * "Pre-close" a socket by dup'ing the file descriptor - this enables
+     * the socket to be closed without releasing the file descriptor.
+     */
+    private void socketPreClose() throws IOException {
+        socketClose0(true);
+    }
+
+    /*
+     * Close the socket (and release the file descriptor).
+     */
+    protected void socketClose() throws IOException {
+        socketClose0(false);
+    }
+
+    abstract void socketCreate(boolean isServer) throws IOException;
+    abstract void socketConnect(InetAddress address, int port, int timeout)
+        throws IOException;
+    abstract void socketBind(InetAddress address, int port)
+        throws IOException;
+    abstract void socketListen(int count)
+        throws IOException;
+    abstract void socketAccept(SocketImpl s)
+        throws IOException;
+    abstract int socketAvailable()
+        throws IOException;
+    abstract void socketClose0(boolean useDeferredClose)
+        throws IOException;
+    abstract void socketShutdown(int howto)
+        throws IOException;
+
+    // Android-changed: Method signature changed, socket{Get,Set}Option work directly with Object
+    // values.
+    abstract void socketSetOption(int cmd, Object value) throws SocketException;
+    abstract Object socketGetOption(int opt) throws SocketException;
+
+    abstract void socketSendUrgentData(int data)
+        throws IOException;
+
+    public final static int SHUT_RD = 0;
+    public final static int SHUT_WR = 1;
+}
diff --git a/java/net/AddressCache.java b/java/net/AddressCache.java
new file mode 100644
index 0000000..3026923
--- /dev/null
+++ b/java/net/AddressCache.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.net;
+
+import android.compat.annotation.UnsupportedAppUsage;
+import libcore.util.BasicLruCache;
+
+/**
+ * Implements caching for {@code InetAddress}. We use a unified cache for both positive and negative
+ * cache entries.
+ *
+ * TODO: benchmark and optimize InetAddress until we get to the point where we can just rely on
+ * the C library level caching. The main thing caching at this level buys us is avoiding repeated
+ * conversions from 'struct sockaddr's to InetAddress[].
+ */
+class AddressCache {
+    /**
+     * When the cache contains more entries than this, we start dropping the oldest ones.
+     * This should be a power of two to avoid wasted space in our custom map.
+     */
+    private static final int MAX_ENTRIES = 16;
+
+    // The TTL for the Java-level cache is short, just 2s.
+    private static final long TTL_NANOS = 2 * 1000000000L;
+
+    // The actual cache.
+    @UnsupportedAppUsage
+    private final BasicLruCache<AddressCacheKey, AddressCacheEntry> cache
+            = new BasicLruCache<AddressCacheKey, AddressCacheEntry>(MAX_ENTRIES);
+
+    static class AddressCacheKey {
+        @UnsupportedAppUsage
+        private final String mHostname;
+        private final int mNetId;
+
+        AddressCacheKey(String hostname, int netId) {
+            mHostname = hostname;
+            mNetId = netId;
+        }
+
+        @Override public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (!(o instanceof AddressCacheKey)) {
+                return false;
+            }
+            AddressCacheKey lhs = (AddressCacheKey) o;
+            return mHostname.equals(lhs.mHostname) && mNetId == lhs.mNetId;
+        }
+
+        @Override public int hashCode() {
+            int result = 17;
+            result = 31 * result + mNetId;
+            result = 31 * result + mHostname.hashCode();
+            return result;
+        }
+    }
+
+    static class AddressCacheEntry {
+        // Either an InetAddress[] for a positive entry,
+        // or a String detail message for a negative entry.
+        @UnsupportedAppUsage
+        final Object value;
+
+        /**
+         * The absolute expiry time in nanoseconds. Nanoseconds from System.nanoTime is ideal
+         * because -- unlike System.currentTimeMillis -- it can never go backwards.
+         *
+         * We don't need to worry about overflow with a TTL_NANOS of 2s.
+         */
+        @UnsupportedAppUsage
+        final long expiryNanos;
+
+        @UnsupportedAppUsage
+        AddressCacheEntry(Object value) {
+            this.value = value;
+            this.expiryNanos = System.nanoTime() + TTL_NANOS;
+        }
+    }
+
+    /**
+     * Removes all entries from the cache.
+     */
+    public void clear() {
+        cache.evictAll();
+    }
+
+    /**
+     * Returns the cached InetAddress[] for 'hostname' on network 'netId'. Returns null
+     * if nothing is known about 'hostname'. Returns a String suitable for use as an
+     * UnknownHostException detail message if 'hostname' is known not to exist.
+     */
+    public Object get(String hostname, int netId) {
+        AddressCacheEntry entry = cache.get(new AddressCacheKey(hostname, netId));
+        // Do we have a valid cache entry?
+        if (entry != null && entry.expiryNanos >= System.nanoTime()) {
+            return entry.value;
+        }
+        // Either we didn't find anything, or it had expired.
+        // No need to remove expired entries: the caller will provide a replacement shortly.
+        return null;
+    }
+
+    /**
+     * Associates the given 'addresses' with 'hostname'. The association will expire after a
+     * certain length of time.
+     */
+    public void put(String hostname, int netId, InetAddress[] addresses) {
+        cache.put(new AddressCacheKey(hostname, netId), new AddressCacheEntry(addresses));
+    }
+
+    /**
+     * Records that 'hostname' is known not to have any associated addresses. (I.e. insert a
+     * negative cache entry.)
+     */
+    public void putUnknownHost(String hostname, int netId, String detailMessage) {
+        cache.put(new AddressCacheKey(hostname, netId), new AddressCacheEntry(detailMessage));
+    }
+}
diff --git a/java/net/Authenticator.java b/java/net/Authenticator.java
new file mode 100644
index 0000000..c88a600
--- /dev/null
+++ b/java/net/Authenticator.java
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * The class Authenticator represents an object that knows how to obtain
+ * authentication for a network connection.  Usually, it will do this
+ * by prompting the user for information.
+ * <p>
+ * Applications use this class by overriding {@link
+ * #getPasswordAuthentication()} in a sub-class. This method will
+ * typically use the various getXXX() accessor methods to get information
+ * about the entity requesting authentication. It must then acquire a
+ * username and password either by interacting with the user or through
+ * some other non-interactive means. The credentials are then returned
+ * as a {@link PasswordAuthentication} return value.
+ * <p>
+ * An instance of this concrete sub-class is then registered
+ * with the system by calling {@link #setDefault(Authenticator)}.
+ * When authentication is required, the system will invoke one of the
+ * requestPasswordAuthentication() methods which in turn will call the
+ * getPasswordAuthentication() method of the registered object.
+ * <p>
+ * All methods that request authentication have a default implementation
+ * that fails.
+ *
+ * @see java.net.Authenticator#setDefault(java.net.Authenticator)
+ * @see java.net.Authenticator#getPasswordAuthentication()
+ *
+ * @author  Bill Foote
+ * @since   1.2
+ */
+
+// There are no abstract methods, but to be useful the user must
+// subclass.
+public abstract
+class Authenticator {
+
+    // The system-wide authenticator object.  See setDefault().
+    private static Authenticator theAuthenticator;
+
+    private String requestingHost;
+    private InetAddress requestingSite;
+    private int requestingPort;
+    private String requestingProtocol;
+    private String requestingPrompt;
+    private String requestingScheme;
+    private URL requestingURL;
+    private RequestorType requestingAuthType;
+
+    /**
+     * The type of the entity requesting authentication.
+     *
+     * @since 1.5
+     */
+    public enum RequestorType {
+        /**
+         * Entity requesting authentication is a HTTP proxy server.
+         */
+        PROXY,
+        /**
+         * Entity requesting authentication is a HTTP origin server.
+         */
+        SERVER
+    }
+
+    private void reset() {
+        requestingHost = null;
+        requestingSite = null;
+        requestingPort = -1;
+        requestingProtocol = null;
+        requestingPrompt = null;
+        requestingScheme = null;
+        requestingURL = null;
+        requestingAuthType = RequestorType.SERVER;
+    }
+
+
+    /**
+     * Sets the authenticator that will be used by the networking code
+     * when a proxy or an HTTP server asks for authentication.
+     * <p>
+     * First, if there is a security manager, its {@code checkPermission}
+     * method is called with a
+     * {@code NetPermission("setDefaultAuthenticator")} permission.
+     * This may result in a java.lang.SecurityException.
+     *
+     * @param   a       The authenticator to be set. If a is {@code null} then
+     *                  any previously set authenticator is removed.
+     *
+     * @throws SecurityException
+     *        if a security manager exists and its
+     *        {@code checkPermission} method doesn't allow
+     *        setting the default authenticator.
+     *
+     * @see SecurityManager#checkPermission
+     * @see java.net.NetPermission
+     */
+    public synchronized static void setDefault(Authenticator a) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            NetPermission setDefaultPermission
+                = new NetPermission("setDefaultAuthenticator");
+            sm.checkPermission(setDefaultPermission);
+        }
+
+        theAuthenticator = a;
+    }
+
+    /**
+     * Ask the authenticator that has been registered with the system
+     * for a password.
+     * <p>
+     * First, if there is a security manager, its {@code checkPermission}
+     * method is called with a
+     * {@code NetPermission("requestPasswordAuthentication")} permission.
+     * This may result in a java.lang.SecurityException.
+     *
+     * @param addr The InetAddress of the site requesting authorization,
+     *             or null if not known.
+     * @param port the port for the requested connection
+     * @param protocol The protocol that's requesting the connection
+     *          ({@link java.net.Authenticator#getRequestingProtocol()})
+     * @param prompt A prompt string for the user
+     * @param scheme The authentication scheme
+     *
+     * @return The username/password, or null if one can't be gotten.
+     *
+     * @throws SecurityException
+     *        if a security manager exists and its
+     *        {@code checkPermission} method doesn't allow
+     *        the password authentication request.
+     *
+     * @see SecurityManager#checkPermission
+     * @see java.net.NetPermission
+     */
+    public static PasswordAuthentication requestPasswordAuthentication(
+                                            InetAddress addr,
+                                            int port,
+                                            String protocol,
+                                            String prompt,
+                                            String scheme) {
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            NetPermission requestPermission
+                = new NetPermission("requestPasswordAuthentication");
+            sm.checkPermission(requestPermission);
+        }
+
+        Authenticator a = theAuthenticator;
+        if (a == null) {
+            return null;
+        } else {
+            synchronized(a) {
+                a.reset();
+                a.requestingSite = addr;
+                a.requestingPort = port;
+                a.requestingProtocol = protocol;
+                a.requestingPrompt = prompt;
+                a.requestingScheme = scheme;
+                return a.getPasswordAuthentication();
+            }
+        }
+    }
+
+    /**
+     * Ask the authenticator that has been registered with the system
+     * for a password. This is the preferred method for requesting a password
+     * because the hostname can be provided in cases where the InetAddress
+     * is not available.
+     * <p>
+     * First, if there is a security manager, its {@code checkPermission}
+     * method is called with a
+     * {@code NetPermission("requestPasswordAuthentication")} permission.
+     * This may result in a java.lang.SecurityException.
+     *
+     * @param host The hostname of the site requesting authentication.
+     * @param addr The InetAddress of the site requesting authentication,
+     *             or null if not known.
+     * @param port the port for the requested connection.
+     * @param protocol The protocol that's requesting the connection
+     *          ({@link java.net.Authenticator#getRequestingProtocol()})
+     * @param prompt A prompt string for the user which identifies the authentication realm.
+     * @param scheme The authentication scheme
+     *
+     * @return The username/password, or null if one can't be gotten.
+     *
+     * @throws SecurityException
+     *        if a security manager exists and its
+     *        {@code checkPermission} method doesn't allow
+     *        the password authentication request.
+     *
+     * @see SecurityManager#checkPermission
+     * @see java.net.NetPermission
+     * @since 1.4
+     */
+    public static PasswordAuthentication requestPasswordAuthentication(
+                                            String host,
+                                            InetAddress addr,
+                                            int port,
+                                            String protocol,
+                                            String prompt,
+                                            String scheme) {
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            NetPermission requestPermission
+                = new NetPermission("requestPasswordAuthentication");
+            sm.checkPermission(requestPermission);
+        }
+
+        Authenticator a = theAuthenticator;
+        if (a == null) {
+            return null;
+        } else {
+            synchronized(a) {
+                a.reset();
+                a.requestingHost = host;
+                a.requestingSite = addr;
+                a.requestingPort = port;
+                a.requestingProtocol = protocol;
+                a.requestingPrompt = prompt;
+                a.requestingScheme = scheme;
+                return a.getPasswordAuthentication();
+            }
+        }
+    }
+
+    /**
+     * Ask the authenticator that has been registered with the system
+     * for a password.
+     * <p>
+     * First, if there is a security manager, its {@code checkPermission}
+     * method is called with a
+     * {@code NetPermission("requestPasswordAuthentication")} permission.
+     * This may result in a java.lang.SecurityException.
+     *
+     * @param host The hostname of the site requesting authentication.
+     * @param addr The InetAddress of the site requesting authorization,
+     *             or null if not known.
+     * @param port the port for the requested connection
+     * @param protocol The protocol that's requesting the connection
+     *          ({@link java.net.Authenticator#getRequestingProtocol()})
+     * @param prompt A prompt string for the user
+     * @param scheme The authentication scheme
+     * @param url The requesting URL that caused the authentication
+     * @param reqType The type (server or proxy) of the entity requesting
+     *              authentication.
+     *
+     * @return The username/password, or null if one can't be gotten.
+     *
+     * @throws SecurityException
+     *        if a security manager exists and its
+     *        {@code checkPermission} method doesn't allow
+     *        the password authentication request.
+     *
+     * @see SecurityManager#checkPermission
+     * @see java.net.NetPermission
+     *
+     * @since 1.5
+     */
+    public static PasswordAuthentication requestPasswordAuthentication(
+                                    String host,
+                                    InetAddress addr,
+                                    int port,
+                                    String protocol,
+                                    String prompt,
+                                    String scheme,
+                                    URL url,
+                                    RequestorType reqType) {
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            NetPermission requestPermission
+                = new NetPermission("requestPasswordAuthentication");
+            sm.checkPermission(requestPermission);
+        }
+
+        Authenticator a = theAuthenticator;
+        if (a == null) {
+            return null;
+        } else {
+            synchronized(a) {
+                a.reset();
+                a.requestingHost = host;
+                a.requestingSite = addr;
+                a.requestingPort = port;
+                a.requestingProtocol = protocol;
+                a.requestingPrompt = prompt;
+                a.requestingScheme = scheme;
+                a.requestingURL = url;
+                a.requestingAuthType = reqType;
+                return a.getPasswordAuthentication();
+            }
+        }
+    }
+
+    /**
+     * Gets the {@code hostname} of the
+     * site or proxy requesting authentication, or {@code null}
+     * if not available.
+     *
+     * @return the hostname of the connection requiring authentication, or null
+     *          if it's not available.
+     * @since 1.4
+     */
+    protected final String getRequestingHost() {
+        return requestingHost;
+    }
+
+    /**
+     * Gets the {@code InetAddress} of the
+     * site requesting authorization, or {@code null}
+     * if not available.
+     *
+     * @return the InetAddress of the site requesting authorization, or null
+     *          if it's not available.
+     */
+    protected final InetAddress getRequestingSite() {
+        return requestingSite;
+    }
+
+    /**
+     * Gets the port number for the requested connection.
+     * @return an {@code int} indicating the
+     * port for the requested connection.
+     */
+    protected final int getRequestingPort() {
+        return requestingPort;
+    }
+
+    /**
+     * Give the protocol that's requesting the connection.  Often this
+     * will be based on a URL, but in a future JDK it could be, for
+     * example, "SOCKS" for a password-protected SOCKS5 firewall.
+     *
+     * @return the protocol, optionally followed by "/version", where
+     *          version is a version number.
+     *
+     * @see java.net.URL#getProtocol()
+     */
+    protected final String getRequestingProtocol() {
+        return requestingProtocol;
+    }
+
+    /**
+     * Gets the prompt string given by the requestor.
+     *
+     * @return the prompt string given by the requestor (realm for
+     *          http requests)
+     */
+    protected final String getRequestingPrompt() {
+        return requestingPrompt;
+    }
+
+    /**
+     * Gets the scheme of the requestor (the HTTP scheme
+     * for an HTTP firewall, for example).
+     *
+     * @return the scheme of the requestor
+     *
+     */
+    protected final String getRequestingScheme() {
+        return requestingScheme;
+    }
+
+    /**
+     * Called when password authorization is needed.  Subclasses should
+     * override the default implementation, which returns null.
+     * @return The PasswordAuthentication collected from the
+     *          user, or null if none is provided.
+     */
+    protected PasswordAuthentication getPasswordAuthentication() {
+        return null;
+    }
+
+    /**
+     * Returns the URL that resulted in this
+     * request for authentication.
+     *
+     * @since 1.5
+     *
+     * @return the requesting URL
+     *
+     */
+    protected URL getRequestingURL () {
+        return requestingURL;
+    }
+
+    /**
+     * Returns whether the requestor is a Proxy or a Server.
+     *
+     * @since 1.5
+     *
+     * @return the authentication type of the requestor
+     *
+     */
+    protected RequestorType getRequestorType () {
+        return requestingAuthType;
+    }
+}
diff --git a/java/net/BindException.java b/java/net/BindException.java
new file mode 100644
index 0000000..9c2bb48
--- /dev/null
+++ b/java/net/BindException.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * Signals that an error occurred while attempting to bind a
+ * socket to a local address and port.  Typically, the port is
+ * in use, or the requested local address could not be assigned.
+ *
+ * @since   JDK1.1
+ */
+
+public class BindException extends SocketException {
+    private static final long serialVersionUID = -5945005768251722951L;
+
+    /**
+     * Constructs a new BindException with the specified detail
+     * message as to why the bind error occurred.
+     * A detail message is a String that gives a specific
+     * description of this error.
+     * @param msg the detail message
+     */
+    public BindException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Construct a new BindException with no detailed message.
+     */
+    public BindException() {}
+
+    // Android-added: Constructor called by IoBridge
+    /** @hide */
+    public BindException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+}
diff --git a/java/net/CacheRequest.java b/java/net/CacheRequest.java
new file mode 100644
index 0000000..a6fbbc3
--- /dev/null
+++ b/java/net/CacheRequest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * Represents channels for storing resources in the
+ * ResponseCache. Instances of such a class provide an
+ * OutputStream object which is called by protocol handlers to
+ * store the resource data into the cache, and also an abort() method
+ * which allows a cache store operation to be interrupted and
+ * abandoned. If an IOException is encountered while reading the
+ * response or writing to the cache, the current cache store operation
+ * will be aborted.
+ *
+ * @author Yingxian Wang
+ * @since 1.5
+ */
+public abstract class CacheRequest {
+
+    /**
+     * Returns an OutputStream to which the response body can be
+     * written.
+     *
+     * @return an OutputStream to which the response body can
+     *         be written
+     * @throws IOException if an I/O error occurs while
+     *         writing the response body
+     */
+    public abstract OutputStream getBody() throws IOException;
+
+    /**
+     * Aborts the attempt to cache the response. If an IOException is
+     * encountered while reading the response or writing to the cache,
+     * the current cache store operation will be abandoned.
+     */
+    public abstract void abort();
+}
diff --git a/java/net/CacheResponse.java b/java/net/CacheResponse.java
new file mode 100644
index 0000000..272b3d9
--- /dev/null
+++ b/java/net/CacheResponse.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.InputStream;
+import java.util.Map;
+import java.util.List;
+import java.io.IOException;
+
+/**
+ * Represent channels for retrieving resources from the
+ * ResponseCache. Instances of such a class provide an
+ * InputStream that returns the entity body, and also a
+ * getHeaders() method which returns the associated response headers.
+ *
+ * @author Yingxian Wang
+ * @since 1.5
+ */
+public abstract class CacheResponse {
+
+    /**
+     * Returns the response headers as a Map.
+     *
+     * @return An immutable Map from response header field names to
+     *         lists of field values. The status line has null as its
+     *         field name.
+     * @throws IOException if an I/O error occurs
+     *            while getting the response headers
+     */
+    public abstract Map<String, List<String>> getHeaders() throws IOException;
+
+    /**
+     * Returns the response body as an InputStream.
+     *
+     * @return an InputStream from which the response body can
+     *         be accessed
+     * @throws IOException if an I/O error occurs while
+     *         getting the response body
+     */
+    public abstract InputStream getBody() throws IOException;
+}
diff --git a/java/net/ConnectException.java b/java/net/ConnectException.java
new file mode 100644
index 0000000..ff58643
--- /dev/null
+++ b/java/net/ConnectException.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * Signals that an error occurred while attempting to connect a
+ * socket to a remote address and port.  Typically, the connection
+ * was refused remotely (e.g., no process is listening on the
+ * remote address/port).
+ *
+ * @since   JDK1.1
+ */
+public class ConnectException extends SocketException {
+    private static final long serialVersionUID = 3831404271622369215L;
+
+    /**
+     * Constructs a new ConnectException with the specified detail
+     * message as to why the connect error occurred.
+     * A detail message is a String that gives a specific
+     * description of this error.
+     * @param msg the detail message
+     */
+    public ConnectException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Construct a new ConnectException with no detailed message.
+     */
+    public ConnectException() {}
+
+    // Android-added: Constructor called by IoBridge
+    /** @hide */
+    public ConnectException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+}
diff --git a/java/net/ContentHandler.java b/java/net/ContentHandler.java
new file mode 100644
index 0000000..c658585
--- /dev/null
+++ b/java/net/ContentHandler.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * The abstract class {@code ContentHandler} is the superclass
+ * of all classes that read an {@code Object} from a
+ * {@code URLConnection}.
+ * <p>
+ * An application does not generally call the
+ * {@code getContent} method in this class directly. Instead, an
+ * application calls the {@code getContent} method in class
+ * {@code URL} or in {@code URLConnection}.
+ * The application's content handler factory (an instance of a class that
+ * implements the interface {@code ContentHandlerFactory} set
+ * up by a call to {@code setContentHandler}) is
+ * called with a {@code String} giving the MIME type of the
+ * object being received on the socket. The factory returns an
+ * instance of a subclass of {@code ContentHandler}, and its
+ * {@code getContent} method is called to create the object.
+ * <p>
+ * If no content handler could be found, URLConnection will
+ * look for a content handler in a user-defineable set of places.
+ * By default it looks in sun.net.www.content, but users can define a
+ * vertical-bar delimited set of class prefixes to search through in
+ * addition by defining the java.content.handler.pkgs property.
+ * The class name must be of the form:
+ * <pre>
+ *     {package-prefix}.{major}.{minor}
+ * e.g.
+ *     YoyoDyne.experimental.text.plain
+ * </pre>
+ * If the loading of the content handler class would be performed by
+ * a classloader that is outside of the delegation chain of the caller,
+ * the JVM will need the RuntimePermission "getClassLoader".
+ *
+ * @author  James Gosling
+ * @see     java.net.ContentHandler#getContent(java.net.URLConnection)
+ * @see     java.net.ContentHandlerFactory
+ * @see     java.net.URL#getContent()
+ * @see     java.net.URLConnection
+ * @see     java.net.URLConnection#getContent()
+ * @see     java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
+ * @since   JDK1.0
+ */
+abstract public class ContentHandler {
+    /**
+     * Given a URL connect stream positioned at the beginning of the
+     * representation of an object, this method reads that stream and
+     * creates an object from it.
+     *
+     * @param      urlc   a URL connection.
+     * @return     the object read by the {@code ContentHandler}.
+     * @exception  IOException  if an I/O error occurs while reading the object.
+     */
+    abstract public Object getContent(URLConnection urlc) throws IOException;
+
+    /**
+     * Given a URL connect stream positioned at the beginning of the
+     * representation of an object, this method reads that stream and
+     * creates an object that matches one of the types specified.
+     *
+     * The default implementation of this method should call getContent()
+     * and screen the return type for a match of the suggested types.
+     *
+     * @param      urlc   a URL connection.
+     * @param      classes      an array of types requested
+     * @return     the object read by the {@code ContentHandler} that is
+     *                 the first match of the suggested types.
+     *                 null if none of the requested  are supported.
+     * @exception  IOException  if an I/O error occurs while reading the object.
+     * @since 1.3
+     */
+    @SuppressWarnings("rawtypes")
+    public Object getContent(URLConnection urlc, Class[] classes) throws IOException {
+        Object obj = getContent(urlc);
+
+        for (int i = 0; i < classes.length; i++) {
+          if (classes[i].isInstance(obj)) {
+                return obj;
+          }
+        }
+        return null;
+    }
+
+}
diff --git a/java/net/ContentHandlerFactory.java b/java/net/ContentHandlerFactory.java
new file mode 100644
index 0000000..64112e3
--- /dev/null
+++ b/java/net/ContentHandlerFactory.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * This interface defines a factory for content handlers. An
+ * implementation of this interface should map a MIME type into an
+ * instance of {@code ContentHandler}.
+ * <p>
+ * This interface is used by the {@code URLStreamHandler} class
+ * to create a {@code ContentHandler} for a MIME type.
+ *
+ * @author  James Gosling
+ * @see     java.net.ContentHandler
+ * @see     java.net.URLStreamHandler
+ * @since   JDK1.0
+ */
+public interface ContentHandlerFactory {
+    /**
+     * Creates a new {@code ContentHandler} to read an object from
+     * a {@code URLStreamHandler}.
+     *
+     * @param   mimetype   the MIME type for which a content handler is desired.
+
+     * @return  a new {@code ContentHandler} to read an object from a
+     *          {@code URLStreamHandler}.
+     * @see     java.net.ContentHandler
+     * @see     java.net.URLStreamHandler
+     */
+    ContentHandler createContentHandler(String mimetype);
+}
diff --git a/java/net/CookieHandler.java b/java/net/CookieHandler.java
new file mode 100644
index 0000000..ef91d00
--- /dev/null
+++ b/java/net/CookieHandler.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.util.Map;
+import java.util.List;
+import java.io.IOException;
+import sun.security.util.SecurityConstants;
+
+/**
+ * A CookieHandler object provides a callback mechanism to hook up a
+ * HTTP state management policy implementation into the HTTP protocol
+ * handler. The HTTP state management mechanism specifies a way to
+ * create a stateful session with HTTP requests and responses.
+ *
+ * <p>A system-wide CookieHandler that to used by the HTTP protocol
+ * handler can be registered by doing a
+ * CookieHandler.setDefault(CookieHandler). The currently registered
+ * CookieHandler can be retrieved by calling
+ * CookieHandler.getDefault().
+ *
+ * For more information on HTTP state management, see <a
+ * href="http://www.ietf.org/rfc/rfc2965.txt"><i>RFC&nbsp;2965: HTTP
+ * State Management Mechanism</i></a>
+ *
+ * @author Yingxian Wang
+ * @since 1.5
+ */
+public abstract class CookieHandler {
+    /**
+     * The system-wide cookie handler that will apply cookies to the
+     * request headers and manage cookies from the response headers.
+     *
+     * @see setDefault(CookieHandler)
+     * @see getDefault()
+     */
+    private static CookieHandler cookieHandler;
+
+    /**
+     * Gets the system-wide cookie handler.
+     *
+     * @return the system-wide cookie handler; A null return means
+     *        there is no system-wide cookie handler currently set.
+     * @throws SecurityException
+     *       If a security manager has been installed and it denies
+     * {@link NetPermission}{@code ("getCookieHandler")}
+     * @see #setDefault(CookieHandler)
+     */
+    public synchronized static CookieHandler getDefault() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(SecurityConstants.GET_COOKIEHANDLER_PERMISSION);
+        }
+        return cookieHandler;
+    }
+
+    /**
+     * Sets (or unsets) the system-wide cookie handler.
+     *
+     * Note: non-standard http protocol handlers may ignore this setting.
+     *
+     * @param cHandler The HTTP cookie handler, or
+     *       {@code null} to unset.
+     * @throws SecurityException
+     *       If a security manager has been installed and it denies
+     * {@link NetPermission}{@code ("setCookieHandler")}
+     * @see #getDefault()
+     */
+    public synchronized static void setDefault(CookieHandler cHandler) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(SecurityConstants.SET_COOKIEHANDLER_PERMISSION);
+        }
+        cookieHandler = cHandler;
+    }
+
+    /**
+     * Gets all the applicable cookies from a cookie cache for the
+     * specified uri in the request header.
+     *
+     * <P>The {@code URI} passed as an argument specifies the intended use for
+     * the cookies. In particular the scheme should reflect whether the cookies
+     * will be sent over http, https or used in another context like javascript.
+     * The host part should reflect either the destination of the cookies or
+     * their origin in the case of javascript.</P>
+     * <P>It is up to the implementation to take into account the {@code URI} and
+     * the cookies attributes and security settings to determine which ones
+     * should be returned.</P>
+     *
+     * <P>HTTP protocol implementers should make sure that this method is
+     * called after all request headers related to choosing cookies
+     * are added, and before the request is sent.</P>
+     *
+     * @param uri a {@code URI} representing the intended use for the
+     *            cookies
+     * @param requestHeaders - a Map from request header
+     *            field names to lists of field values representing
+     *            the current request headers
+     * @return an immutable map from state management headers, with
+     *            field names "Cookie" or "Cookie2" to a list of
+     *            cookies containing state information
+     *
+     * @throws IOException if an I/O error occurs
+     * @throws IllegalArgumentException if either argument is null
+     * @see #put(URI, Map)
+     */
+    public abstract Map<String, List<String>>
+        get(URI uri, Map<String, List<String>> requestHeaders)
+        throws IOException;
+
+    /**
+     * Sets all the applicable cookies, examples are response header
+     * fields that are named Set-Cookie2, present in the response
+     * headers into a cookie cache.
+     *
+     * @param uri a {@code URI} where the cookies come from
+     * @param responseHeaders an immutable map from field names to
+     *            lists of field values representing the response
+     *            header fields returned
+     * @throws  IOException if an I/O error occurs
+     * @throws  IllegalArgumentException if either argument is null
+     * @see #get(URI, Map)
+     */
+    public abstract void
+        put(URI uri, Map<String, List<String>> responseHeaders)
+        throws IOException;
+}
diff --git a/java/net/CookieManager.java b/java/net/CookieManager.java
new file mode 100644
index 0000000..dfd3b86
--- /dev/null
+++ b/java/net/CookieManager.java
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.util.Map;
+import java.util.List;
+import java.util.Collections;
+import java.util.Comparator;
+import java.io.IOException;
+import sun.util.logging.PlatformLogger;
+
+/**
+ * CookieManager provides a concrete implementation of {@link CookieHandler},
+ * which separates the storage of cookies from the policy surrounding accepting
+ * and rejecting cookies. A CookieManager is initialized with a {@link CookieStore}
+ * which manages storage, and a {@link CookiePolicy} object, which makes
+ * policy decisions on cookie acceptance/rejection.
+ *
+ * <p> The HTTP cookie management in java.net package looks like:
+ * <blockquote>
+ * <pre>{@code
+ *                  use
+ * CookieHandler <------- HttpURLConnection
+ *       ^
+ *       | impl
+ *       |         use
+ * CookieManager -------> CookiePolicy
+ *             |   use
+ *             |--------> HttpCookie
+ *             |              ^
+ *             |              | use
+ *             |   use        |
+ *             |--------> CookieStore
+ *                            ^
+ *                            | impl
+ *                            |
+ *                  Internal in-memory implementation
+ * }</pre>
+ * <ul>
+ *   <li>
+ *     CookieHandler is at the core of cookie management. User can call
+ *     CookieHandler.setDefault to set a concrete CookieHanlder implementation
+ *     to be used.
+ *   </li>
+ *   <li>
+ *     CookiePolicy.shouldAccept will be called by CookieManager.put to see whether
+ *     or not one cookie should be accepted and put into cookie store. User can use
+ *     any of three pre-defined CookiePolicy, namely ACCEPT_ALL, ACCEPT_NONE and
+ *     ACCEPT_ORIGINAL_SERVER, or user can define his own CookiePolicy implementation
+ *     and tell CookieManager to use it.
+ *   </li>
+ *   <li>
+ *     CookieStore is the place where any accepted HTTP cookie is stored in.
+ *     If not specified when created, a CookieManager instance will use an internal
+ *     in-memory implementation. Or user can implements one and tell CookieManager
+ *     to use it.
+ *   </li>
+ *   <li>
+ *     Currently, only CookieStore.add(URI, HttpCookie) and CookieStore.get(URI)
+ *     are used by CookieManager. Others are for completeness and might be needed
+ *     by a more sophisticated CookieStore implementation, e.g. a NetscapeCookieSotre.
+ *   </li>
+ * </ul>
+ * </blockquote>
+ *
+ * <p>There're various ways user can hook up his own HTTP cookie management behavior, e.g.
+ * <blockquote>
+ * <ul>
+ *   <li>Use CookieHandler.setDefault to set a brand new {@link CookieHandler} implementation
+ *   <li>Let CookieManager be the default {@link CookieHandler} implementation,
+ *       but implement user's own {@link CookieStore} and {@link CookiePolicy}
+ *       and tell default CookieManager to use them:
+ *     <blockquote><pre>
+ *       // this should be done at the beginning of an HTTP session
+ *       CookieHandler.setDefault(new CookieManager(new MyCookieStore(), new MyCookiePolicy()));
+ *     </pre></blockquote>
+ *   <li>Let CookieManager be the default {@link CookieHandler} implementation, but
+ *       use customized {@link CookiePolicy}:
+ *     <blockquote><pre>
+ *       // this should be done at the beginning of an HTTP session
+ *       CookieHandler.setDefault(new CookieManager());
+ *       // this can be done at any point of an HTTP session
+ *       ((CookieManager)CookieHandler.getDefault()).setCookiePolicy(new MyCookiePolicy());
+ *     </pre></blockquote>
+ * </ul>
+ * </blockquote>
+ *
+ * <p>The implementation conforms to <a href="http://www.ietf.org/rfc/rfc2965.txt">RFC 2965</a>, section 3.3.
+ *
+ * @see CookiePolicy
+ * @author Edward Wang
+ * @since 1.6
+ */
+public class CookieManager extends CookieHandler
+{
+    /* ---------------- Fields -------------- */
+
+    private CookiePolicy policyCallback;
+
+
+    private CookieStore cookieJar = null;
+
+
+    /* ---------------- Ctors -------------- */
+
+    /**
+     * Create a new cookie manager.
+     *
+     * <p>This constructor will create new cookie manager with default
+     * cookie store and accept policy. The effect is same as
+     * {@code CookieManager(null, null)}.
+     */
+    public CookieManager() {
+        this(null, null);
+    }
+
+
+    /**
+     * Create a new cookie manager with specified cookie store and cookie policy.
+     *
+     * @param store     a {@code CookieStore} to be used by cookie manager.
+     *                  if {@code null}, cookie manager will use a default one,
+     *                  which is an in-memory CookieStore implementation.
+     * @param cookiePolicy      a {@code CookiePolicy} instance
+     *                          to be used by cookie manager as policy callback.
+     *                          if {@code null}, ACCEPT_ORIGINAL_SERVER will
+     *                          be used.
+     */
+    public CookieManager(CookieStore store,
+                         CookiePolicy cookiePolicy)
+    {
+        // use default cookie policy if not specify one
+        policyCallback = (cookiePolicy == null) ? CookiePolicy.ACCEPT_ORIGINAL_SERVER
+                                                : cookiePolicy;
+
+        // if not specify CookieStore to use, use default one
+        if (store == null) {
+            cookieJar = new InMemoryCookieStore();
+        } else {
+            cookieJar = store;
+        }
+    }
+
+
+    /* ---------------- Public operations -------------- */
+
+    /**
+     * To set the cookie policy of this cookie manager.
+     *
+     * <p> A instance of {@code CookieManager} will have
+     * cookie policy ACCEPT_ORIGINAL_SERVER by default. Users always
+     * can call this method to set another cookie policy.
+     *
+     * @param cookiePolicy      the cookie policy. Can be {@code null}, which
+     *                          has no effects on current cookie policy.
+     */
+    public void setCookiePolicy(CookiePolicy cookiePolicy) {
+        if (cookiePolicy != null) policyCallback = cookiePolicy;
+    }
+
+
+    /**
+     * To retrieve current cookie store.
+     *
+     * @return  the cookie store currently used by cookie manager.
+     */
+    public CookieStore getCookieStore() {
+        return cookieJar;
+    }
+
+
+    public Map<String, List<String>>
+        get(URI uri, Map<String, List<String>> requestHeaders)
+        throws IOException
+    {
+        // pre-condition check
+        if (uri == null || requestHeaders == null) {
+            throw new IllegalArgumentException("Argument is null");
+        }
+
+        Map<String, List<String>> cookieMap =
+                        new java.util.HashMap<String, List<String>>();
+        // if there's no default CookieStore, no way for us to get any cookie
+        if (cookieJar == null)
+            return Collections.unmodifiableMap(cookieMap);
+
+        boolean secureLink = "https".equalsIgnoreCase(uri.getScheme());
+        List<HttpCookie> cookies = new java.util.ArrayList<HttpCookie>();
+        // BEGIN Android-removed: The logic of converting null path is moved into pathMatches.
+        /*
+        String path = uri.getPath();
+        if (path == null || path.isEmpty()) {
+            path = "/";
+        }
+        */
+        // END Android-removed: The logic of converting null path is moved into pathMatches.
+        for (HttpCookie cookie : cookieJar.get(uri)) {
+            // apply path-matches rule (RFC 2965 sec. 3.3.4)
+            // and check for the possible "secure" tag (i.e. don't send
+            // 'secure' cookies over unsecure links)
+            if (pathMatches(uri, cookie) &&
+                    (secureLink || !cookie.getSecure())) {
+                // BEGIN Android-removed: App compat: b/25897688 InMemoryCookieStore ignores scheme.
+                /*
+                if (cookie.isHttpOnly()) {
+                    String s = uri.getScheme();
+                    if (!"http".equalsIgnoreCase(s) && !"https".equalsIgnoreCase(s)) {
+                        continue;
+                    }
+                }
+                */
+                // END Android-removed: App compat: b/25897688 InMemoryCookieStore ignores scheme.
+
+                // Let's check the authorize port list if it exists
+                String ports = cookie.getPortlist();
+                if (ports != null && !ports.isEmpty()) {
+                    int port = uri.getPort();
+                    if (port == -1) {
+                        port = "https".equals(uri.getScheme()) ? 443 : 80;
+                    }
+                    if (isInPortList(ports, port)) {
+                        cookies.add(cookie);
+                    }
+                } else {
+                    cookies.add(cookie);
+                }
+            }
+        }
+        // Android-added: b/25897688 A fix to return empty map if cookies list is empty
+        if (cookies.isEmpty()) {
+            return Collections.emptyMap();
+        }
+
+        // apply sort rule (RFC 2965 sec. 3.3.4)
+        List<String> cookieHeader = sortByPath(cookies);
+
+        cookieMap.put("Cookie", cookieHeader);
+        return Collections.unmodifiableMap(cookieMap);
+    }
+
+    public void
+        put(URI uri, Map<String, List<String>> responseHeaders)
+        throws IOException
+    {
+        // pre-condition check
+        if (uri == null || responseHeaders == null) {
+            throw new IllegalArgumentException("Argument is null");
+        }
+
+
+        // if there's no default CookieStore, no need to remember any cookie
+        if (cookieJar == null)
+            return;
+
+    PlatformLogger logger = PlatformLogger.getLogger("java.net.CookieManager");
+        for (String headerKey : responseHeaders.keySet()) {
+            // RFC 2965 3.2.2, key must be 'Set-Cookie2'
+            // we also accept 'Set-Cookie' here for backward compatibility
+            if (headerKey == null
+                || !(headerKey.equalsIgnoreCase("Set-Cookie2")
+                     || headerKey.equalsIgnoreCase("Set-Cookie")
+                    )
+                )
+            {
+                continue;
+            }
+
+            for (String headerValue : responseHeaders.get(headerKey)) {
+                try {
+                    List<HttpCookie> cookies;
+                    try {
+                        cookies = HttpCookie.parse(headerValue);
+                    } catch (IllegalArgumentException e) {
+                        // Bogus header, make an empty list and log the error
+                        cookies = java.util.Collections.emptyList();
+                        if (logger.isLoggable(PlatformLogger.Level.SEVERE)) {
+                            logger.severe("Invalid cookie for " + uri + ": " + headerValue);
+                        }
+                    }
+                    for (HttpCookie cookie : cookies) {
+                        if (cookie.getPath() == null) {
+                            // If no path is specified, then by default
+                            // the path is the directory of the page/doc
+                            String path = uri.getPath();
+                            if (!path.endsWith("/")) {
+                                int i = path.lastIndexOf("/");
+                                if (i > 0) {
+                                    path = path.substring(0, i + 1);
+                                } else {
+                                    path = "/";
+                                }
+                            }
+                            cookie.setPath(path);
+                        // Android-added: b/25763487 A fix to verify cookie URI before removal
+                        } else {
+                            // Validate existing path
+                            if (!pathMatches(uri, cookie)) {
+                                continue;
+                            }
+                        }
+
+                        // As per RFC 2965, section 3.3.1:
+                        // Domain  Defaults to the effective request-host.  (Note that because
+                        // there is no dot at the beginning of effective request-host,
+                        // the default Domain can only domain-match itself.)
+                        if (cookie.getDomain() == null) {
+                            String host = uri.getHost();
+                            if (host != null && !host.contains("."))
+                                host += ".local";
+                            cookie.setDomain(host);
+                        }
+                        String ports = cookie.getPortlist();
+                        if (ports != null) {
+                            int port = uri.getPort();
+                            if (port == -1) {
+                                port = "https".equals(uri.getScheme()) ? 443 : 80;
+                            }
+                            if (ports.isEmpty()) {
+                                // Empty port list means this should be restricted
+                                // to the incoming URI port
+                                cookie.setPortlist("" + port );
+                                if (shouldAcceptInternal(uri, cookie)) {
+                                    cookieJar.add(uri, cookie);
+                                }
+                            } else {
+                                // Only store cookies with a port list
+                                // IF the URI port is in that list, as per
+                                // RFC 2965 section 3.3.2
+                                if (isInPortList(ports, port) &&
+                                        shouldAcceptInternal(uri, cookie)) {
+                                    cookieJar.add(uri, cookie);
+                                }
+                            }
+                        } else {
+                            if (shouldAcceptInternal(uri, cookie)) {
+                                cookieJar.add(uri, cookie);
+                            }
+                        }
+                    }
+                } catch (IllegalArgumentException e) {
+                    // invalid set-cookie header string
+                    // no-op
+                }
+            }
+        }
+    }
+
+
+    /* ---------------- Private operations -------------- */
+
+    // to determine whether or not accept this cookie
+    private boolean shouldAcceptInternal(URI uri, HttpCookie cookie) {
+        try {
+            return policyCallback.shouldAccept(uri, cookie);
+        } catch (Exception ignored) { // pretect against malicious callback
+            return false;
+        }
+    }
+
+
+    static private boolean isInPortList(String lst, int port) {
+        int i = lst.indexOf(",");
+        int val = -1;
+        while (i > 0) {
+            try {
+                val = Integer.parseInt(lst.substring(0, i));
+                if (val == port) {
+                    return true;
+                }
+            } catch (NumberFormatException numberFormatException) {
+            }
+            lst = lst.substring(i+1);
+            i = lst.indexOf(",");
+        }
+        if (!lst.isEmpty()) {
+            try {
+                val = Integer.parseInt(lst);
+                if (val == port) {
+                    return true;
+                }
+            } catch (NumberFormatException numberFormatException) {
+            }
+        }
+        return false;
+    }
+
+    // Android-changed: b/25763487 Cookie path matching logic in OpenJDK was wrong
+    /**
+     * Return true iff. the path from {@code cookie} matches the path from {@code uri}.
+     */
+    private static boolean pathMatches(URI uri, HttpCookie cookie) {
+        return normalizePath(uri.getPath()).startsWith(normalizePath(cookie.getPath()));
+    }
+
+    private static String normalizePath(String path) {
+        if (path == null) {
+            path = "";
+        }
+
+        if (!path.endsWith("/")) {
+            path = path + "/";
+        }
+
+        return path;
+    }
+
+
+    /*
+     * sort cookies with respect to their path: those with more specific Path attributes
+     * precede those with less specific, as defined in RFC 2965 sec. 3.3.4
+     */
+    private List<String> sortByPath(List<HttpCookie> cookies) {
+        Collections.sort(cookies, new CookiePathComparator());
+
+        // BEGIN Android-changed: Netscape cookie spec and RFC 2965 have different format
+        // of Cookie header; RFC 2965 requires a leading $Version="1" string while Netscape does not
+        // The workaround here is to add a $Version="1" string in advance
+        final StringBuilder result = new StringBuilder();
+        int minVersion = 1;
+        for (HttpCookie cookie : cookies) {
+            if (cookie.getVersion() < minVersion) {
+                minVersion = cookie.getVersion();
+            }
+        }
+
+        if (minVersion == 1) {
+            result.append("$Version=\"1\"; ");
+        }
+
+        for (int i = 0; i < cookies.size(); ++i) {
+            if (i != 0) {
+                result.append("; ");
+            }
+
+            result.append(cookies.get(i).toString());
+        }
+
+        List<String> cookieHeader = new java.util.ArrayList<String>();
+        cookieHeader.add(result.toString());
+        // END Android-changed: Netscape cookie spec and RFC 2965 have different format
+        return cookieHeader;
+    }
+
+
+    static class CookiePathComparator implements Comparator<HttpCookie> {
+        public int compare(HttpCookie c1, HttpCookie c2) {
+            if (c1 == c2) return 0;
+            if (c1 == null) return -1;
+            if (c2 == null) return 1;
+
+            // path rule only applies to the cookies with same name
+            if (!c1.getName().equals(c2.getName())) return 0;
+
+            // Android-changed: normalize before comparison
+            final String c1Path = normalizePath(c1.getPath());
+            final String c2Path = normalizePath(c2.getPath());
+
+            // those with more specific Path attributes precede those with less specific
+            if (c1Path.startsWith(c2Path))
+                return -1;
+            else if (c2Path.startsWith(c1Path))
+                return 1;
+            else
+                return 0;
+        }
+    }
+}
diff --git a/java/net/CookiePolicy.java b/java/net/CookiePolicy.java
new file mode 100644
index 0000000..8094835
--- /dev/null
+++ b/java/net/CookiePolicy.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * CookiePolicy implementations decide which cookies should be accepted
+ * and which should be rejected. Three pre-defined policy implementations
+ * are provided, namely ACCEPT_ALL, ACCEPT_NONE and ACCEPT_ORIGINAL_SERVER.
+ *
+ * <p>See RFC 2965 sec. 3.3 and 7 for more detail.
+ *
+ * @author Edward Wang
+ * @since 1.6
+ */
+public interface CookiePolicy {
+    /**
+     * One pre-defined policy which accepts all cookies.
+     */
+    public static final CookiePolicy ACCEPT_ALL = new CookiePolicy(){
+        public boolean shouldAccept(URI uri, HttpCookie cookie) {
+            return true;
+        }
+    };
+
+    /**
+     * One pre-defined policy which accepts no cookies.
+     */
+    public static final CookiePolicy ACCEPT_NONE = new CookiePolicy(){
+        public boolean shouldAccept(URI uri, HttpCookie cookie) {
+            return false;
+        }
+    };
+
+    /**
+     * One pre-defined policy which only accepts cookies from original server.
+     */
+    public static final CookiePolicy ACCEPT_ORIGINAL_SERVER  = new CookiePolicy(){
+        public boolean shouldAccept(URI uri, HttpCookie cookie) {
+            if (uri == null || cookie == null)
+                return false;
+            return HttpCookie.domainMatches(cookie.getDomain(), uri.getHost());
+        }
+    };
+
+
+    /**
+     * Will be called to see whether or not this cookie should be accepted.
+     *
+     * @param uri       the URI to consult accept policy with
+     * @param cookie    the HttpCookie object in question
+     * @return          {@code true} if this cookie should be accepted;
+     *                  otherwise, {@code false}
+     */
+    public boolean shouldAccept(URI uri, HttpCookie cookie);
+}
diff --git a/java/net/CookieStore.java b/java/net/CookieStore.java
new file mode 100644
index 0000000..105cc66
--- /dev/null
+++ b/java/net/CookieStore.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A CookieStore object represents a storage for cookie. Can store and retrieve
+ * cookies.
+ *
+ * <p>{@link CookieManager} will call {@code CookieStore.add} to save cookies
+ * for every incoming HTTP response, and call {@code CookieStore.get} to
+ * retrieve cookie for every outgoing HTTP request. A CookieStore
+ * is responsible for removing HttpCookie instances which have expired.
+ *
+ * @author Edward Wang
+ * @since 1.6
+ */
+public interface CookieStore {
+    /**
+     * Adds one HTTP cookie to the store. This is called for every
+     * incoming HTTP response.
+     *
+     * <p>A cookie to store may or may not be associated with an URI. If it
+     * is not associated with an URI, the cookie's domain and path attribute
+     * will indicate where it comes from. If it is associated with an URI and
+     * its domain and path attribute are not specified, given URI will indicate
+     * where this cookie comes from.
+     *
+     * <p>If a cookie corresponding to the given URI already exists,
+     * then it is replaced with the new one.
+     *
+     * @param uri       the uri this cookie associated with.
+     *                  if {@code null}, this cookie will not be associated
+     *                  with an URI
+     * @param cookie    the cookie to store
+     *
+     * @throws NullPointerException if {@code cookie} is {@code null}
+     *
+     * @see #get
+     *
+     */
+    public void add(URI uri, HttpCookie cookie);
+
+
+    /**
+     * Retrieve cookies associated with given URI, or whose domain matches the
+     * given URI. Only cookies that have not expired are returned.
+     * This is called for every outgoing HTTP request.
+     *
+     * @return          an immutable list of HttpCookie,
+     *                  return empty list if no cookies match the given URI
+     *
+     * @param uri       the uri associated with the cookies to be returned
+     *
+     * @throws NullPointerException if {@code uri} is {@code null}
+     *
+     * @see #add
+     *
+     */
+    public List<HttpCookie> get(URI uri);
+
+
+    /**
+     * Get all not-expired cookies in cookie store.
+     *
+     * @return          an immutable list of http cookies;
+     *                  return empty list if there's no http cookie in store
+     */
+    public List<HttpCookie> getCookies();
+
+
+    /**
+     * Get all URIs which identify the cookies in this cookie store.
+     *
+     * @return          an immutable list of URIs;
+     *                  return empty list if no cookie in this cookie store
+     *                  is associated with an URI
+     */
+    public List<URI> getURIs();
+
+
+    /**
+     * Remove a cookie from store.
+     *
+     * @param uri       the uri this cookie associated with.
+     *                  if {@code null}, the cookie to be removed is not associated
+     *                  with an URI when added; if not {@code null}, the cookie
+     *                  to be removed is associated with the given URI when added.
+     * @param cookie    the cookie to remove
+     *
+     * @return          {@code true} if this store contained the specified cookie
+     *
+     * @throws NullPointerException if {@code cookie} is {@code null}
+     */
+    public boolean remove(URI uri, HttpCookie cookie);
+
+
+    /**
+     * Remove all cookies in this cookie store.
+     *
+     * @return          {@code true} if this store changed as a result of the call
+     */
+    public boolean removeAll();
+}
diff --git a/java/net/DatagramPacket.java b/java/net/DatagramPacket.java
new file mode 100644
index 0000000..c1bd692
--- /dev/null
+++ b/java/net/DatagramPacket.java
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * This class represents a datagram packet.
+ * <p>
+ * Datagram packets are used to implement a connectionless packet
+ * delivery service. Each message is routed from one machine to
+ * another based solely on information contained within that packet.
+ * Multiple packets sent from one machine to another might be routed
+ * differently, and might arrive in any order. Packet delivery is
+ * not guaranteed.
+ *
+ * @author  Pavani Diwanji
+ * @author  Benjamin Renaud
+ * @since   JDK1.0
+ */
+public final
+class DatagramPacket {
+
+    // BEGIN Android-removed: Android doesn't need to load native net library.
+    /**
+     * Perform class initialization
+     *
+    static {
+        java.security.AccessController.doPrivileged(
+            new java.security.PrivilegedAction<Void>() {
+                public Void run() {
+                    System.loadLibrary("net");
+                    return null;
+                }
+            });
+        init();
+    }
+    */
+    // END Android-removed: Android doesn't need to load native net library.
+
+    /*
+     * The fields of this class are package-private since DatagramSocketImpl
+     * classes needs to access them.
+     */
+    byte[] buf;
+    int offset;
+    int length;
+    int bufLength;
+    InetAddress address;
+    int port;
+
+    /**
+     * Constructs a {@code DatagramPacket} for receiving packets of
+     * length {@code length}, specifying an offset into the buffer.
+     * <p>
+     * The {@code length} argument must be less than or equal to
+     * {@code buf.length}.
+     *
+     * @param   buf      buffer for holding the incoming datagram.
+     * @param   offset   the offset for the buffer
+     * @param   length   the number of bytes to read.
+     *
+     * @since 1.2
+     */
+    public DatagramPacket(byte buf[], int offset, int length) {
+        setData(buf, offset, length);
+        this.address = null;
+        this.port = -1;
+    }
+
+    /**
+     * Constructs a {@code DatagramPacket} for receiving packets of
+     * length {@code length}.
+     * <p>
+     * The {@code length} argument must be less than or equal to
+     * {@code buf.length}.
+     *
+     * @param   buf      buffer for holding the incoming datagram.
+     * @param   length   the number of bytes to read.
+     */
+    public DatagramPacket(byte buf[], int length) {
+        this (buf, 0, length);
+    }
+
+    /**
+     * Constructs a datagram packet for sending packets of length
+     * {@code length} with offset {@code ioffset}to the
+     * specified port number on the specified host. The
+     * {@code length} argument must be less than or equal to
+     * {@code buf.length}.
+     *
+     * @param   buf      the packet data.
+     * @param   offset   the packet data offset.
+     * @param   length   the packet data length.
+     * @param   address  the destination address.
+     * @param   port     the destination port number.
+     * @see java.net.InetAddress
+     *
+     * @since 1.2
+     */
+    public DatagramPacket(byte buf[], int offset, int length,
+                          InetAddress address, int port) {
+        setData(buf, offset, length);
+        setAddress(address);
+        setPort(port);
+    }
+
+    // Android-changed: Added Android-specific notes regarding the exception signature change.
+    /**
+     * Constructs a datagram packet for sending packets of length
+     * {@code length} with offset {@code ioffset}to the
+     * specified port number on the specified host. The
+     * {@code length} argument must be less than or equal to
+     * {@code buf.length}.
+     *
+     * <p>
+     * <em>Android note</em>: Up to and including API 25 this method declared that a SocketException
+     * can be thrown, although the exception is never thrown. Code compiled against a newer SDK does
+     * not need to catch the exception and will be binary compatible with older versions of Android.
+     *
+     * @param   buf      the packet data.
+     * @param   offset   the packet data offset.
+     * @param   length   the packet data length.
+     * @param   address  the destination socket address.
+     * @throws  IllegalArgumentException if address type is not supported
+     * @see java.net.InetAddress
+     *
+     * @since 1.4
+     */
+    public DatagramPacket(byte buf[], int offset, int length, SocketAddress address) {
+        setData(buf, offset, length);
+        setSocketAddress(address);
+    }
+
+    // Android-changed: Added Android-specific notes regarding the exception signature change.
+    /**
+     * Constructs a datagram packet for sending packets of length
+     * {@code length} to the specified port number on the specified
+     * host. The {@code length} argument must be less than or equal
+     * to {@code buf.length}.
+     *
+     * <p>
+     * <em>Android note</em>: Up to and including API 25 this method declared that a SocketException
+     * can be thrown, although the exception is never thrown. Code compiled against a newer SDK does
+     * not need to catch the exception and will be binary compatible with older versions of Android.
+     *
+     * @param   buf      the packet data.
+     * @param   length   the packet length.
+     * @param   address  the destination address.
+     * @param   port     the destination port number.
+     * @see     java.net.InetAddress
+     */
+    public DatagramPacket(byte buf[], int length,
+                          InetAddress address, int port) {
+        this(buf, 0, length, address, port);
+    }
+
+    /**
+     * Constructs a datagram packet for sending packets of length
+     * {@code length} to the specified port number on the specified
+     * host. The {@code length} argument must be less than or equal
+     * to {@code buf.length}.
+     *
+     * @param   buf      the packet data.
+     * @param   length   the packet length.
+     * @param   address  the destination address.
+     * @throws  IllegalArgumentException if address type is not supported
+     * @since 1.4
+     * @see     java.net.InetAddress
+     */
+    public DatagramPacket(byte buf[], int length, SocketAddress address) {
+        this(buf, 0, length, address);
+    }
+
+    /**
+     * Returns the IP address of the machine to which this datagram is being
+     * sent or from which the datagram was received.
+     *
+     * @return  the IP address of the machine to which this datagram is being
+     *          sent or from which the datagram was received.
+     * @see     java.net.InetAddress
+     * @see #setAddress(java.net.InetAddress)
+     */
+    public synchronized InetAddress getAddress() {
+        return address;
+    }
+
+    /**
+     * Returns the port number on the remote host to which this datagram is
+     * being sent or from which the datagram was received.
+     *
+     * @return  the port number on the remote host to which this datagram is
+     *          being sent or from which the datagram was received.
+     * @see #setPort(int)
+     */
+    public synchronized int getPort() {
+        return port;
+    }
+
+    /**
+     * Returns the data buffer. The data received or the data to be sent
+     * starts from the {@code offset} in the buffer,
+     * and runs for {@code length} long.
+     *
+     * @return  the buffer used to receive or  send data
+     * @see #setData(byte[], int, int)
+     */
+    public synchronized byte[] getData() {
+        return buf;
+    }
+
+    /**
+     * Returns the offset of the data to be sent or the offset of the
+     * data received.
+     *
+     * @return  the offset of the data to be sent or the offset of the
+     *          data received.
+     *
+     * @since 1.2
+     */
+    public synchronized int getOffset() {
+        return offset;
+    }
+
+    /**
+     * Returns the length of the data to be sent or the length of the
+     * data received.
+     *
+     * @return  the length of the data to be sent or the length of the
+     *          data received.
+     * @see #setLength(int)
+     */
+    public synchronized int getLength() {
+        return length;
+    }
+
+    /**
+     * Set the data buffer for this packet. This sets the
+     * data, length and offset of the packet.
+     *
+     * @param buf the buffer to set for this packet
+     *
+     * @param offset the offset into the data
+     *
+     * @param length the length of the data
+     *       and/or the length of the buffer used to receive data
+     *
+     * @exception NullPointerException if the argument is null
+     *
+     * @see #getData
+     * @see #getOffset
+     * @see #getLength
+     *
+     * @since 1.2
+     */
+    public synchronized void setData(byte[] buf, int offset, int length) {
+        /* this will check to see if buf is null */
+        if (length < 0 || offset < 0 ||
+            (length + offset) < 0 ||
+            ((length + offset) > buf.length)) {
+            throw new IllegalArgumentException("illegal length or offset");
+        }
+        this.buf = buf;
+        this.length = length;
+        this.bufLength = length;
+        this.offset = offset;
+    }
+
+    /**
+     * Sets the IP address of the machine to which this datagram
+     * is being sent.
+     * @param iaddr the {@code InetAddress}
+     * @since   JDK1.1
+     * @see #getAddress()
+     */
+    public synchronized void setAddress(InetAddress iaddr) {
+        address = iaddr;
+    }
+
+    // BEGIN Android-changed
+    /**
+     * Sets 'length' without changing 'userSuppliedLength', after receiving a packet.
+     * @hide for IoBridge
+     */
+    public void setReceivedLength(int length) {
+        this.length = length;
+    }
+    // END Android-changed
+
+    /**
+     * Sets the port number on the remote host to which this datagram
+     * is being sent.
+     * @param iport the port number
+     * @since   JDK1.1
+     * @see #getPort()
+     */
+    public synchronized void setPort(int iport) {
+        if (iport < 0 || iport > 0xFFFF) {
+            throw new IllegalArgumentException("Port out of range:"+ iport);
+        }
+        port = iport;
+    }
+
+    /**
+     * Sets the SocketAddress (usually IP address + port number) of the remote
+     * host to which this datagram is being sent.
+     *
+     * @param address the {@code SocketAddress}
+     * @throws  IllegalArgumentException if address is null or is a
+     *          SocketAddress subclass not supported by this socket
+     *
+     * @since 1.4
+     * @see #getSocketAddress
+     */
+    public synchronized void setSocketAddress(SocketAddress address) {
+        if (address == null || !(address instanceof InetSocketAddress))
+            throw new IllegalArgumentException("unsupported address type");
+        InetSocketAddress addr = (InetSocketAddress) address;
+        if (addr.isUnresolved())
+            throw new IllegalArgumentException("unresolved address");
+        setAddress(addr.getAddress());
+        setPort(addr.getPort());
+    }
+
+    /**
+     * Gets the SocketAddress (usually IP address + port number) of the remote
+     * host that this packet is being sent to or is coming from.
+     *
+     * @return the {@code SocketAddress}
+     * @since 1.4
+     * @see #setSocketAddress
+     */
+    public synchronized SocketAddress getSocketAddress() {
+        return new InetSocketAddress(getAddress(), getPort());
+    }
+
+    /**
+     * Set the data buffer for this packet. With the offset of
+     * this DatagramPacket set to 0, and the length set to
+     * the length of {@code buf}.
+     *
+     * @param buf the buffer to set for this packet.
+     *
+     * @exception NullPointerException if the argument is null.
+     *
+     * @see #getLength
+     * @see #getData
+     *
+     * @since JDK1.1
+     */
+    public synchronized void setData(byte[] buf) {
+        if (buf == null) {
+            throw new NullPointerException("null packet buffer");
+        }
+        this.buf = buf;
+        this.offset = 0;
+        this.length = buf.length;
+        this.bufLength = buf.length;
+    }
+
+    /**
+     * Set the length for this packet. The length of the packet is
+     * the number of bytes from the packet's data buffer that will be
+     * sent, or the number of bytes of the packet's data buffer that
+     * will be used for receiving data. The length must be lesser or
+     * equal to the offset plus the length of the packet's buffer.
+     *
+     * @param length the length to set for this packet.
+     *
+     * @exception IllegalArgumentException if the length is negative
+     * of if the length is greater than the packet's data buffer
+     * length.
+     *
+     * @see #getLength
+     * @see #setData
+     *
+     * @since JDK1.1
+     */
+    public synchronized void setLength(int length) {
+        if ((length + offset) > buf.length || length < 0 ||
+            (length + offset) < 0) {
+            throw new IllegalArgumentException("illegal length");
+        }
+        this.length = length;
+        this.bufLength = this.length;
+    }
+
+    // Android-removed: JNI has been removed
+    // /**
+    //  * Perform class load-time initializations.
+    //  */
+    // private native static void init();
+}
diff --git a/java/net/DatagramSocket.annotated.java b/java/net/DatagramSocket.annotated.java
new file mode 100644
index 0000000..b462769
--- /dev/null
+++ b/java/net/DatagramSocket.annotated.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.net;
+
+import java.nio.channels.DatagramChannel;
+import java.io.IOException;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class DatagramSocket implements java.io.Closeable {
+
+public DatagramSocket() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+protected DatagramSocket(java.net.DatagramSocketImpl impl) { throw new RuntimeException("Stub!"); }
+
+public DatagramSocket(java.net.SocketAddress bindaddr) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public DatagramSocket(int port) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public DatagramSocket(int port, java.net.InetAddress laddr) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void bind(java.net.SocketAddress addr) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public void connect(java.net.InetAddress address, int port) { throw new RuntimeException("Stub!"); }
+
+public void connect(java.net.SocketAddress addr) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public void disconnect() { throw new RuntimeException("Stub!"); }
+
+public boolean isBound() { throw new RuntimeException("Stub!"); }
+
+public boolean isConnected() { throw new RuntimeException("Stub!"); }
+
+public java.net.InetAddress getInetAddress() { throw new RuntimeException("Stub!"); }
+
+public int getPort() { throw new RuntimeException("Stub!"); }
+
+public java.net.SocketAddress getRemoteSocketAddress() { throw new RuntimeException("Stub!"); }
+
+public java.net.SocketAddress getLocalSocketAddress() { throw new RuntimeException("Stub!"); }
+
+public void send(java.net.DatagramPacket p) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public synchronized void receive(java.net.DatagramPacket p) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public java.net.InetAddress getLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public int getLocalPort() { throw new RuntimeException("Stub!"); }
+
+public synchronized void setSoTimeout(int timeout) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized int getSoTimeout() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void setSendBufferSize(int size) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized int getSendBufferSize() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void setReceiveBufferSize(int size) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized int getReceiveBufferSize() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void setReuseAddress(boolean on) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean getReuseAddress() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void setBroadcast(boolean on) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean getBroadcast() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void setTrafficClass(int tc) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized int getTrafficClass() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public void close() { throw new RuntimeException("Stub!"); }
+
+public boolean isClosed() { throw new RuntimeException("Stub!"); }
+
+public java.nio.channels.DatagramChannel getChannel() { throw new RuntimeException("Stub!"); }
+
+public static synchronized void setDatagramSocketImplFactory(java.net.DatagramSocketImplFactory fac) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
[email protected]
+public java.io.FileDescriptor getFileDescriptor$() { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/net/DatagramSocket.java b/java/net/DatagramSocket.java
new file mode 100644
index 0000000..3e3faf7
--- /dev/null
+++ b/java/net/DatagramSocket.java
@@ -0,0 +1,1358 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import static android.system.OsConstants.SOL_SOCKET;
+import static android.system.OsConstants.SO_BINDTODEVICE;
+
+import android.system.ErrnoException;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.nio.channels.DatagramChannel;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import libcore.io.Libcore;
+
+/**
+ * This class represents a socket for sending and receiving datagram packets.
+ *
+ * <p>A datagram socket is the sending or receiving point for a packet
+ * delivery service. Each packet sent or received on a datagram socket
+ * is individually addressed and routed. Multiple packets sent from
+ * one machine to another may be routed differently, and may arrive in
+ * any order.
+ *
+ * <p> Where possible, a newly constructed {@code DatagramSocket} has the
+ * {@link SocketOptions#SO_BROADCAST SO_BROADCAST} socket option enabled so as
+ * to allow the transmission of broadcast datagrams. In order to receive
+ * broadcast packets a DatagramSocket should be bound to the wildcard address.
+ * In some implementations, broadcast packets may also be received when
+ * a DatagramSocket is bound to a more specific address.
+ * <p>
+ * Example:
+ * {@code
+ *              DatagramSocket s = new DatagramSocket(null);
+ *              s.bind(new InetSocketAddress(8888));
+ * }
+ * Which is equivalent to:
+ * {@code
+ *              DatagramSocket s = new DatagramSocket(8888);
+ * }
+ * Both cases will create a DatagramSocket able to receive broadcasts on
+ * UDP port 8888.
+ *
+ * @author  Pavani Diwanji
+ * @see     java.net.DatagramPacket
+ * @see     java.nio.channels.DatagramChannel
+ * @since JDK1.0
+ */
+public
+class DatagramSocket implements java.io.Closeable {
+    /**
+     * Various states of this socket.
+     */
+    private boolean created = false;
+    private boolean bound = false;
+    private boolean closed = false;
+    private Object closeLock = new Object();
+
+    /*
+     * The implementation of this DatagramSocket.
+     */
+    DatagramSocketImpl impl;
+
+    /**
+     * Are we using an older DatagramSocketImpl?
+     */
+    boolean oldImpl = false;
+
+    /**
+     * Set when a socket is ST_CONNECTED until we are certain
+     * that any packets which might have been received prior
+     * to calling connect() but not read by the application
+     * have been read. During this time we check the source
+     * address of all packets received to be sure they are from
+     * the connected destination. Other packets are read but
+     * silently dropped.
+     */
+    private boolean explicitFilter = false;
+    private int bytesLeftToFilter;
+    /*
+     * Connection state:
+     * ST_NOT_CONNECTED = socket not connected
+     * ST_CONNECTED = socket connected
+     * ST_CONNECTED_NO_IMPL = socket connected but not at impl level
+     */
+    static final int ST_NOT_CONNECTED = 0;
+    static final int ST_CONNECTED = 1;
+    static final int ST_CONNECTED_NO_IMPL = 2;
+
+    int connectState = ST_NOT_CONNECTED;
+
+    /*
+     * Connected address & port
+     */
+    InetAddress connectedAddress = null;
+    int connectedPort = -1;
+
+    // Android-added: Store pending exception from connect
+    private SocketException pendingConnectException;
+
+    /**
+     * Connects this socket to a remote socket address (IP address + port number).
+     * Binds socket if not already bound.
+     * <p>
+     * @param   address The remote address.
+     * @param   port    The remote port
+     * @throws  SocketException if binding the socket fails.
+     */
+    private synchronized void connectInternal(InetAddress address, int port) throws SocketException {
+        if (port < 0 || port > 0xFFFF) {
+            throw new IllegalArgumentException("connect: " + port);
+        }
+        if (address == null) {
+            throw new IllegalArgumentException("connect: null address");
+        }
+        checkAddress (address, "connect");
+        if (isClosed())
+            return;
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            if (address.isMulticastAddress()) {
+                security.checkMulticast(address);
+            } else {
+                security.checkConnect(address.getHostAddress(), port);
+                security.checkAccept(address.getHostAddress(), port);
+            }
+        }
+
+        if (!isBound())
+          bind(new InetSocketAddress(0));
+
+        // Android-changed: This section now throws any SocketException generated by connect()
+        // to enable it to be recorded as the pendingConnectException. It has been enclosed in a
+        // try-finally to ensure connectedAddress and connectedPort are set when the exception
+        // is thrown.
+        try {
+            // old impls do not support connect/disconnect
+            // Android-changed: Added special handling for AbstractPlainDatagramSocketImpl in
+            // the condition below.
+            if (oldImpl || (impl instanceof AbstractPlainDatagramSocketImpl &&
+                    ((AbstractPlainDatagramSocketImpl)impl).nativeConnectDisabled())) {
+                connectState = ST_CONNECTED_NO_IMPL;
+            } else {
+                try {
+                    getImpl().connect(address, port);
+
+                    // socket is now connected by the impl
+                    connectState = ST_CONNECTED;
+
+                    // Do we need to filter some packets?
+                    int avail = getImpl().dataAvailable();
+                    if (avail == -1) {
+                        throw new SocketException();
+                    }
+                    explicitFilter = avail > 0;
+                    if (explicitFilter) {
+                        bytesLeftToFilter = getReceiveBufferSize();
+                    }
+                } catch (SocketException se) {
+                    // connection will be emulated by DatagramSocket
+                    connectState = ST_CONNECTED_NO_IMPL;
+                    // Android-changed: Propagate the SocketException so connect() can store it.
+                    throw se;
+                }
+           }
+        } finally {
+            connectedAddress = address;
+            connectedPort = port;
+        }
+    }
+
+
+    /**
+     * Constructs a datagram socket and binds it to any available port
+     * on the local host machine.  The socket will be bound to the
+     * {@link InetAddress#isAnyLocalAddress wildcard} address,
+     * an IP address chosen by the kernel.
+     *
+     * <p>If there is a security manager,
+     * its {@code checkListen} method is first called
+     * with 0 as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @exception  SocketException  if the socket could not be opened,
+     *               or the socket could not bind to the specified local port.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkListen} method doesn't allow the operation.
+     *
+     * @see SecurityManager#checkListen
+     */
+    public DatagramSocket() throws SocketException {
+        this(new InetSocketAddress(0));
+    }
+
+    /**
+     * Creates an unbound datagram socket with the specified
+     * DatagramSocketImpl.
+     *
+     * @param impl an instance of a <B>DatagramSocketImpl</B>
+     *        the subclass wishes to use on the DatagramSocket.
+     * @since   1.4
+     */
+    protected DatagramSocket(DatagramSocketImpl impl) {
+        if (impl == null)
+            throw new NullPointerException();
+        this.impl = impl;
+        checkOldImpl();
+    }
+
+    /**
+     * Creates a datagram socket, bound to the specified local
+     * socket address.
+     * <p>
+     * If, if the address is {@code null}, creates an unbound socket.
+     *
+     * <p>If there is a security manager,
+     * its {@code checkListen} method is first called
+     * with the port from the socket address
+     * as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param bindaddr local socket address to bind, or {@code null}
+     *                 for an unbound socket.
+     *
+     * @exception  SocketException  if the socket could not be opened,
+     *               or the socket could not bind to the specified local port.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkListen} method doesn't allow the operation.
+     *
+     * @see SecurityManager#checkListen
+     * @since   1.4
+     */
+    public DatagramSocket(SocketAddress bindaddr) throws SocketException {
+        // create a datagram socket.
+        createImpl();
+        if (bindaddr != null) {
+            try {
+                bind(bindaddr);
+            } finally {
+                if (!isBound())
+                    close();
+            }
+        }
+    }
+
+    /**
+     * Constructs a datagram socket and binds it to the specified port
+     * on the local host machine.  The socket will be bound to the
+     * {@link InetAddress#isAnyLocalAddress wildcard} address,
+     * an IP address chosen by the kernel.
+     *
+     * <p>If there is a security manager,
+     * its {@code checkListen} method is first called
+     * with the {@code port} argument
+     * as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param      port port to use.
+     * @exception  SocketException  if the socket could not be opened,
+     *               or the socket could not bind to the specified local port.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkListen} method doesn't allow the operation.
+     *
+     * @see SecurityManager#checkListen
+     */
+    public DatagramSocket(int port) throws SocketException {
+        this(port, null);
+    }
+
+    /**
+     * Creates a datagram socket, bound to the specified local
+     * address.  The local port must be between 0 and 65535 inclusive.
+     * If the IP address is 0.0.0.0, the socket will be bound to the
+     * {@link InetAddress#isAnyLocalAddress wildcard} address,
+     * an IP address chosen by the kernel.
+     *
+     * <p>If there is a security manager,
+     * its {@code checkListen} method is first called
+     * with the {@code port} argument
+     * as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param port local port to use
+     * @param laddr local address to bind
+     *
+     * @exception  SocketException  if the socket could not be opened,
+     *               or the socket could not bind to the specified local port.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkListen} method doesn't allow the operation.
+     *
+     * @see SecurityManager#checkListen
+     * @since   JDK1.1
+     */
+    public DatagramSocket(int port, InetAddress laddr) throws SocketException {
+        this(new InetSocketAddress(laddr, port));
+    }
+
+    private void checkOldImpl() {
+        if (impl == null)
+            return;
+        // DatagramSocketImpl.peekdata() is a protected method, therefore we need to use
+        // getDeclaredMethod, therefore we need permission to access the member
+        try {
+            AccessController.doPrivileged(
+                new PrivilegedExceptionAction<Void>() {
+                    public Void run() throws NoSuchMethodException {
+                        Class<?>[] cl = new Class<?>[1];
+                        cl[0] = DatagramPacket.class;
+                        impl.getClass().getDeclaredMethod("peekData", cl);
+                        return null;
+                    }
+                });
+        } catch (java.security.PrivilegedActionException e) {
+            oldImpl = true;
+        }
+    }
+
+    static Class<?> implClass = null;
+
+    void createImpl() throws SocketException {
+        if (impl == null) {
+            if (factory != null) {
+                impl = factory.createDatagramSocketImpl();
+                checkOldImpl();
+            } else {
+                boolean isMulticast = (this instanceof MulticastSocket) ? true : false;
+                impl = DefaultDatagramSocketImplFactory.createDatagramSocketImpl(isMulticast);
+
+                checkOldImpl();
+            }
+        }
+        // creates a udp socket
+        impl.create();
+        impl.setDatagramSocket(this);
+        created = true;
+    }
+
+    /**
+     * Get the {@code DatagramSocketImpl} attached to this socket,
+     * creating it if necessary.
+     *
+     * @return  the {@code DatagramSocketImpl} attached to that
+     *          DatagramSocket
+     * @throws SocketException if creation fails.
+     * @since 1.4
+     */
+    DatagramSocketImpl getImpl() throws SocketException {
+        if (!created)
+            createImpl();
+        return impl;
+    }
+
+    /**
+     * Binds this DatagramSocket to a specific address and port.
+     * <p>
+     * If the address is {@code null}, then the system will pick up
+     * an ephemeral port and a valid local address to bind the socket.
+     *<p>
+     * @param   addr The address and port to bind to.
+     * @throws  SocketException if any error happens during the bind, or if the
+     *          socket is already bound.
+     * @throws  SecurityException  if a security manager exists and its
+     *             {@code checkListen} method doesn't allow the operation.
+     * @throws IllegalArgumentException if addr is a SocketAddress subclass
+     *         not supported by this socket.
+     * @since 1.4
+     */
+    public synchronized void bind(SocketAddress addr) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (isBound())
+            throw new SocketException("already bound");
+        if (addr == null)
+            addr = new InetSocketAddress(0);
+        if (!(addr instanceof InetSocketAddress))
+            throw new IllegalArgumentException("Unsupported address type!");
+        InetSocketAddress epoint = (InetSocketAddress) addr;
+        if (epoint.isUnresolved())
+            throw new SocketException("Unresolved address");
+        InetAddress iaddr = epoint.getAddress();
+        int port = epoint.getPort();
+        checkAddress(iaddr, "bind");
+        SecurityManager sec = System.getSecurityManager();
+        if (sec != null) {
+            sec.checkListen(port);
+        }
+        try {
+            getImpl().bind(port, iaddr);
+        } catch (SocketException e) {
+            getImpl().close();
+            throw e;
+        }
+        bound = true;
+    }
+
+    void checkAddress (InetAddress addr, String op) {
+        if (addr == null) {
+            return;
+        }
+        if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) {
+            throw new IllegalArgumentException(op + ": invalid address type");
+        }
+    }
+
+    /**
+     * Connects the socket to a remote address for this socket. When a
+     * socket is connected to a remote address, packets may only be
+     * sent to or received from that address. By default a datagram
+     * socket is not connected.
+     *
+     * <p>If the remote destination to which the socket is connected does not
+     * exist, or is otherwise unreachable, and if an ICMP destination unreachable
+     * packet has been received for that address, then a subsequent call to
+     * send or receive may throw a PortUnreachableException. Note, there is no
+     * guarantee that the exception will be thrown.
+     *
+     * <p> If a security manager has been installed then it is invoked to check
+     * access to the remote address. Specifically, if the given {@code address}
+     * is a {@link InetAddress#isMulticastAddress multicast address},
+     * the security manager's {@link
+     * java.lang.SecurityManager#checkMulticast(InetAddress)
+     * checkMulticast} method is invoked with the given {@code address}.
+     * Otherwise, the security manager's {@link
+     * java.lang.SecurityManager#checkConnect(String,int) checkConnect}
+     * and {@link java.lang.SecurityManager#checkAccept checkAccept} methods
+     * are invoked, with the given {@code address} and {@code port}, to
+     * verify that datagrams are permitted to be sent and received
+     * respectively.
+     *
+     * <p> When a socket is connected, {@link #receive receive} and
+     * {@link #send send} <b>will not perform any security checks</b>
+     * on incoming and outgoing packets, other than matching the packet's
+     * and the socket's address and port. On a send operation, if the
+     * packet's address is set and the packet's address and the socket's
+     * address do not match, an {@code IllegalArgumentException} will be
+     * thrown. A socket connected to a multicast address may only be used
+     * to send packets.
+     *
+     * @param address the remote address for the socket
+     *
+     * @param port the remote port for the socket.
+     *
+     * @throws IllegalArgumentException
+     *         if the address is null, or the port is out of range.
+     *
+     * @throws SecurityException
+     *         if a security manager has been installed and it does
+     *         not permit access to the given remote address
+     *
+     * @see #disconnect
+     */
+    public void connect(InetAddress address, int port) {
+        try {
+            connectInternal(address, port);
+        } catch (SocketException se) {
+            // Android-changed: this method can't throw checked SocketException. Throw it later
+            // throw new Error("connect failed", se);
+            // TODO: or just use SneakyThrow? There's a clear API bug here.
+            pendingConnectException = se;
+        }
+    }
+
+    /**
+     * Connects this socket to a remote socket address (IP address + port number).
+     *
+     * <p> If given an {@link InetSocketAddress InetSocketAddress}, this method
+     * behaves as if invoking {@link #connect(InetAddress,int) connect(InetAddress,int)}
+     * with the the given socket addresses IP address and port number.
+     *
+     * @param   addr    The remote address.
+     *
+     * @throws  SocketException
+     *          if the connect fails
+     *
+     * @throws IllegalArgumentException
+     *         if {@code addr} is {@code null}, or {@code addr} is a SocketAddress
+     *         subclass not supported by this socket
+     *
+     * @throws SecurityException
+     *         if a security manager has been installed and it does
+     *         not permit access to the given remote address
+     *
+     * @since 1.4
+     */
+    public void connect(SocketAddress addr) throws SocketException {
+        if (addr == null)
+            throw new IllegalArgumentException("Address can't be null");
+        if (!(addr instanceof InetSocketAddress))
+            throw new IllegalArgumentException("Unsupported address type");
+        InetSocketAddress epoint = (InetSocketAddress) addr;
+        if (epoint.isUnresolved())
+            throw new SocketException("Unresolved address");
+        connectInternal(epoint.getAddress(), epoint.getPort());
+    }
+
+    /**
+     * Disconnects the socket. If the socket is closed or not connected,
+     * then this method has no effect.
+     *
+     * @see #connect
+     */
+    public void disconnect() {
+        synchronized (this) {
+            if (isClosed())
+                return;
+            if (connectState == ST_CONNECTED) {
+                impl.disconnect ();
+            }
+            connectedAddress = null;
+            connectedPort = -1;
+            connectState = ST_NOT_CONNECTED;
+            explicitFilter = false;
+        }
+    }
+
+    /**
+     * Returns the binding state of the socket.
+     * <p>
+     * If the socket was bound prior to being {@link #close closed},
+     * then this method will continue to return {@code true}
+     * after the socket is closed.
+     *
+     * @return true if the socket successfully bound to an address
+     * @since 1.4
+     */
+    public boolean isBound() {
+        return bound;
+    }
+
+    /**
+     * Returns the connection state of the socket.
+     * <p>
+     * If the socket was connected prior to being {@link #close closed},
+     * then this method will continue to return {@code true}
+     * after the socket is closed.
+     *
+     * @return true if the socket successfully connected to a server
+     * @since 1.4
+     */
+    public boolean isConnected() {
+        return connectState != ST_NOT_CONNECTED;
+    }
+
+    /**
+     * Returns the address to which this socket is connected. Returns
+     * {@code null} if the socket is not connected.
+     * <p>
+     * If the socket was connected prior to being {@link #close closed},
+     * then this method will continue to return the connected address
+     * after the socket is closed.
+     *
+     * @return the address to which this socket is connected.
+     */
+    public InetAddress getInetAddress() {
+        return connectedAddress;
+    }
+
+    /**
+     * Returns the port number to which this socket is connected.
+     * Returns {@code -1} if the socket is not connected.
+     * <p>
+     * If the socket was connected prior to being {@link #close closed},
+     * then this method will continue to return the connected port number
+     * after the socket is closed.
+     *
+     * @return the port number to which this socket is connected.
+     */
+    public int getPort() {
+        return connectedPort;
+    }
+
+    /**
+     * Returns the address of the endpoint this socket is connected to, or
+     * {@code null} if it is unconnected.
+     * <p>
+     * If the socket was connected prior to being {@link #close closed},
+     * then this method will continue to return the connected address
+     * after the socket is closed.
+     *
+     * @return a {@code SocketAddress} representing the remote
+     *         endpoint of this socket, or {@code null} if it is
+     *         not connected yet.
+     * @see #getInetAddress()
+     * @see #getPort()
+     * @see #connect(SocketAddress)
+     * @since 1.4
+     */
+    public SocketAddress getRemoteSocketAddress() {
+        if (!isConnected())
+            return null;
+        return new InetSocketAddress(getInetAddress(), getPort());
+    }
+
+    /**
+     * Returns the address of the endpoint this socket is bound to.
+     *
+     * @return a {@code SocketAddress} representing the local endpoint of this
+     *         socket, or {@code null} if it is closed or not bound yet.
+     * @see #getLocalAddress()
+     * @see #getLocalPort()
+     * @see #bind(SocketAddress)
+     * @since 1.4
+     */
+
+    public SocketAddress getLocalSocketAddress() {
+        if (isClosed())
+            return null;
+        if (!isBound())
+            return null;
+        return new InetSocketAddress(getLocalAddress(), getLocalPort());
+    }
+
+    /**
+     * Sends a datagram packet from this socket. The
+     * {@code DatagramPacket} includes information indicating the
+     * data to be sent, its length, the IP address of the remote host,
+     * and the port number on the remote host.
+     *
+     * <p>If there is a security manager, and the socket is not currently
+     * connected to a remote address, this method first performs some
+     * security checks. First, if {@code p.getAddress().isMulticastAddress()}
+     * is true, this method calls the
+     * security manager's {@code checkMulticast} method
+     * with {@code p.getAddress()} as its argument.
+     * If the evaluation of that expression is false,
+     * this method instead calls the security manager's
+     * {@code checkConnect} method with arguments
+     * {@code p.getAddress().getHostAddress()} and
+     * {@code p.getPort()}. Each call to a security manager method
+     * could result in a SecurityException if the operation is not allowed.
+     *
+     * @param      p   the {@code DatagramPacket} to be sent.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkMulticast} or {@code checkConnect}
+     *             method doesn't allow the send.
+     * @exception  PortUnreachableException may be thrown if the socket is connected
+     *             to a currently unreachable destination. Note, there is no
+     *             guarantee that the exception will be thrown.
+     * @exception  java.nio.channels.IllegalBlockingModeException
+     *             if this socket has an associated channel,
+     *             and the channel is in non-blocking mode.
+     * @exception  IllegalArgumentException if the socket is connected,
+     *             and connected address and packet address differ.
+     *
+     * @see        java.net.DatagramPacket
+     * @see        SecurityManager#checkMulticast(InetAddress)
+     * @see        SecurityManager#checkConnect
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public void send(DatagramPacket p) throws IOException  {
+        InetAddress packetAddress = null;
+        synchronized (p) {
+            // BEGIN Android-changed
+            if (pendingConnectException != null) {
+                throw new SocketException("Pending connect failure", pendingConnectException);
+            }
+            // END Android-changed
+            if (isClosed())
+                throw new SocketException("Socket is closed");
+            checkAddress (p.getAddress(), "send");
+            if (connectState == ST_NOT_CONNECTED) {
+                // check the address is ok wiht the security manager on every send.
+                SecurityManager security = System.getSecurityManager();
+
+                // The reason you want to synchronize on datagram packet
+                // is because you don't want an applet to change the address
+                // while you are trying to send the packet for example
+                // after the security check but before the send.
+                if (security != null) {
+                    if (p.getAddress().isMulticastAddress()) {
+                        security.checkMulticast(p.getAddress());
+                    } else {
+                        security.checkConnect(p.getAddress().getHostAddress(),
+                                              p.getPort());
+                    }
+                }
+            } else {
+                // we're connected
+                packetAddress = p.getAddress();
+                if (packetAddress == null) {
+                    p.setAddress(connectedAddress);
+                    p.setPort(connectedPort);
+                } else if ((!packetAddress.equals(connectedAddress)) ||
+                           p.getPort() != connectedPort) {
+                    throw new IllegalArgumentException("connected address " +
+                                                       "and packet address" +
+                                                       " differ");
+                }
+            }
+            // Check whether the socket is bound
+            if (!isBound())
+                bind(new InetSocketAddress(0));
+            // call the  method to send
+            getImpl().send(p);
+        }
+    }
+
+    /**
+     * Receives a datagram packet from this socket. When this method
+     * returns, the {@code DatagramPacket}'s buffer is filled with
+     * the data received. The datagram packet also contains the sender's
+     * IP address, and the port number on the sender's machine.
+     * <p>
+     * This method blocks until a datagram is received. The
+     * {@code length} field of the datagram packet object contains
+     * the length of the received message. If the message is longer than
+     * the packet's length, the message is truncated.
+     * <p>
+     * If there is a security manager, a packet cannot be received if the
+     * security manager's {@code checkAccept} method
+     * does not allow it.
+     *
+     * @param      p   the {@code DatagramPacket} into which to place
+     *                 the incoming data.
+     * @exception  IOException  if an I/O error occurs.
+     * @exception  SocketTimeoutException  if setSoTimeout was previously called
+     *                 and the timeout has expired.
+     * @exception  PortUnreachableException may be thrown if the socket is connected
+     *             to a currently unreachable destination. Note, there is no guarantee that the
+     *             exception will be thrown.
+     * @exception  java.nio.channels.IllegalBlockingModeException
+     *             if this socket has an associated channel,
+     *             and the channel is in non-blocking mode.
+     * @see        java.net.DatagramPacket
+     * @see        java.net.DatagramSocket
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public synchronized void receive(DatagramPacket p) throws IOException {
+        synchronized (p) {
+            if (!isBound())
+                bind(new InetSocketAddress(0));
+
+            // BEGIN Android-changed
+            if (pendingConnectException != null) {
+                throw new SocketException("Pending connect failure", pendingConnectException);
+            }
+            // END Android-changed
+
+            if (connectState == ST_NOT_CONNECTED) {
+                // check the address is ok with the security manager before every recv.
+                SecurityManager security = System.getSecurityManager();
+                if (security != null) {
+                    while(true) {
+                        String peekAd = null;
+                        int peekPort = 0;
+                        // peek at the packet to see who it is from.
+                        if (!oldImpl) {
+                            // We can use the new peekData() API
+                            DatagramPacket peekPacket = new DatagramPacket(new byte[1], 1);
+                            peekPort = getImpl().peekData(peekPacket);
+                            peekAd = peekPacket.getAddress().getHostAddress();
+                        } else {
+                            InetAddress adr = new InetAddress();
+                            peekPort = getImpl().peek(adr);
+                            peekAd = adr.getHostAddress();
+                        }
+                        try {
+                            security.checkAccept(peekAd, peekPort);
+                            // security check succeeded - so now break
+                            // and recv the packet.
+                            break;
+                        } catch (SecurityException se) {
+                            // Throw away the offending packet by consuming
+                            // it in a tmp buffer.
+                            DatagramPacket tmp = new DatagramPacket(new byte[1], 1);
+                            getImpl().receive(tmp);
+
+                            // silently discard the offending packet
+                            // and continue: unknown/malicious
+                            // entities on nets should not make
+                            // runtime throw security exception and
+                            // disrupt the applet by sending random
+                            // datagram packets.
+                            continue;
+                        }
+                    } // end of while
+                }
+            }
+            DatagramPacket tmp = null;
+            if ((connectState == ST_CONNECTED_NO_IMPL) || explicitFilter) {
+                // We have to do the filtering the old fashioned way since
+                // the native impl doesn't support connect or the connect
+                // via the impl failed, or .. "explicitFilter" may be set when
+                // a socket is connected via the impl, for a period of time
+                // when packets from other sources might be queued on socket.
+                boolean stop = false;
+                while (!stop) {
+                    InetAddress peekAddress = null;
+                    int peekPort = -1;
+                    // peek at the packet to see who it is from.
+                    if (!oldImpl) {
+                        // We can use the new peekData() API
+                        DatagramPacket peekPacket = new DatagramPacket(new byte[1], 1);
+                        peekPort = getImpl().peekData(peekPacket);
+                        peekAddress = peekPacket.getAddress();
+                    } else {
+                        // this api only works for IPv4
+                        peekAddress = new InetAddress();
+                        peekPort = getImpl().peek(peekAddress);
+                    }
+                    if ((!connectedAddress.equals(peekAddress)) ||
+                        (connectedPort != peekPort)) {
+                        // throw the packet away and silently continue
+                        tmp = new DatagramPacket(
+                                                new byte[1024], 1024);
+                        getImpl().receive(tmp);
+                        if (explicitFilter) {
+                            if (checkFiltering(tmp)) {
+                                stop = true;
+                            }
+                        }
+                    } else {
+                        stop = true;
+                    }
+                }
+            }
+            // If the security check succeeds, or the datagram is
+            // connected then receive the packet
+            getImpl().receive(p);
+            if (explicitFilter && tmp == null) {
+                // packet was not filtered, account for it here
+                checkFiltering(p);
+            }
+        }
+    }
+
+    private boolean checkFiltering(DatagramPacket p) throws SocketException {
+        bytesLeftToFilter -= p.getLength();
+        if (bytesLeftToFilter <= 0 || getImpl().dataAvailable() <= 0) {
+            explicitFilter = false;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Gets the local address to which the socket is bound.
+     *
+     * <p>If there is a security manager, its
+     * {@code checkConnect} method is first called
+     * with the host address and {@code -1}
+     * as its arguments to see if the operation is allowed.
+     *
+     * @see SecurityManager#checkConnect
+     * @return  the local address to which the socket is bound,
+     *          {@code null} if the socket is closed, or
+     *          an {@code InetAddress} representing
+     *          {@link InetAddress#isAnyLocalAddress wildcard}
+     *          address if either the socket is not bound, or
+     *          the security manager {@code checkConnect}
+     *          method does not allow the operation
+     * @since   1.1
+     */
+    public InetAddress getLocalAddress() {
+        if (isClosed())
+            return null;
+        InetAddress in = null;
+        try {
+            in = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);
+            if (in.isAnyLocalAddress()) {
+                in = InetAddress.anyLocalAddress();
+            }
+            SecurityManager s = System.getSecurityManager();
+            if (s != null) {
+                s.checkConnect(in.getHostAddress(), -1);
+            }
+        } catch (Exception e) {
+            in = InetAddress.anyLocalAddress(); // "0.0.0.0"
+        }
+        return in;
+    }
+
+    /**
+     * Returns the port number on the local host to which this socket
+     * is bound.
+     *
+     * @return  the port number on the local host to which this socket is bound,
+                {@code -1} if the socket is closed, or
+                {@code 0} if it is not bound yet.
+     */
+    public int getLocalPort() {
+        if (isClosed())
+            return -1;
+        try {
+            return getImpl().getLocalPort();
+        } catch (Exception e) {
+            return 0;
+        }
+    }
+
+    /** Enable/disable SO_TIMEOUT with the specified timeout, in
+     *  milliseconds. With this option set to a non-zero timeout,
+     *  a call to receive() for this DatagramSocket
+     *  will block for only this amount of time.  If the timeout expires,
+     *  a <B>java.net.SocketTimeoutException</B> is raised, though the
+     *  DatagramSocket is still valid.  The option <B>must</B> be enabled
+     *  prior to entering the blocking operation to have effect.  The
+     *  timeout must be {@code > 0}.
+     *  A timeout of zero is interpreted as an infinite timeout.
+     *
+     * @param timeout the specified timeout in milliseconds.
+     * @throws SocketException if there is an error in the underlying protocol, such as an UDP error.
+     * @since   JDK1.1
+     * @see #getSoTimeout()
+     */
+    public synchronized void setSoTimeout(int timeout) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
+    }
+
+    /**
+     * Retrieve setting for SO_TIMEOUT.  0 returns implies that the
+     * option is disabled (i.e., timeout of infinity).
+     *
+     * @return the setting for SO_TIMEOUT
+     * @throws SocketException if there is an error in the underlying protocol, such as an UDP error.
+     * @since   JDK1.1
+     * @see #setSoTimeout(int)
+     */
+    public synchronized int getSoTimeout() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (getImpl() == null)
+            return 0;
+        Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
+        /* extra type safety */
+        if (o instanceof Integer) {
+            return ((Integer) o).intValue();
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Sets the SO_SNDBUF option to the specified value for this
+     * {@code DatagramSocket}. The SO_SNDBUF option is used by the
+     * network implementation as a hint to size the underlying
+     * network I/O buffers. The SO_SNDBUF setting may also be used
+     * by the network implementation to determine the maximum size
+     * of the packet that can be sent on this socket.
+     * <p>
+     * As SO_SNDBUF is a hint, applications that want to verify
+     * what size the buffer is should call {@link #getSendBufferSize()}.
+     * <p>
+     * Increasing the buffer size may allow multiple outgoing packets
+     * to be queued by the network implementation when the send rate
+     * is high.
+     * <p>
+     * Note: If {@link #send(DatagramPacket)} is used to send a
+     * {@code DatagramPacket} that is larger than the setting
+     * of SO_SNDBUF then it is implementation specific if the
+     * packet is sent or discarded.
+     *
+     * @param size the size to which to set the send buffer
+     * size. This value must be greater than 0.
+     *
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as an UDP error.
+     * @exception IllegalArgumentException if the value is 0 or is
+     * negative.
+     * @see #getSendBufferSize()
+     */
+    public synchronized void setSendBufferSize(int size)
+    throws SocketException{
+        if (!(size > 0)) {
+            throw new IllegalArgumentException("negative send size");
+        }
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_SNDBUF, new Integer(size));
+    }
+
+    /**
+     * Get value of the SO_SNDBUF option for this {@code DatagramSocket}, that is the
+     * buffer size used by the platform for output on this {@code DatagramSocket}.
+     *
+     * @return the value of the SO_SNDBUF option for this {@code DatagramSocket}
+     * @exception SocketException if there is an error in
+     * the underlying protocol, such as an UDP error.
+     * @see #setSendBufferSize
+     */
+    public synchronized int getSendBufferSize() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        int result = 0;
+        Object o = getImpl().getOption(SocketOptions.SO_SNDBUF);
+        if (o instanceof Integer) {
+            result = ((Integer)o).intValue();
+        }
+        return result;
+    }
+
+    /**
+     * Sets the SO_RCVBUF option to the specified value for this
+     * {@code DatagramSocket}. The SO_RCVBUF option is used by the
+     * the network implementation as a hint to size the underlying
+     * network I/O buffers. The SO_RCVBUF setting may also be used
+     * by the network implementation to determine the maximum size
+     * of the packet that can be received on this socket.
+     * <p>
+     * Because SO_RCVBUF is a hint, applications that want to
+     * verify what size the buffers were set to should call
+     * {@link #getReceiveBufferSize()}.
+     * <p>
+     * Increasing SO_RCVBUF may allow the network implementation
+     * to buffer multiple packets when packets arrive faster than
+     * are being received using {@link #receive(DatagramPacket)}.
+     * <p>
+     * Note: It is implementation specific if a packet larger
+     * than SO_RCVBUF can be received.
+     *
+     * @param size the size to which to set the receive buffer
+     * size. This value must be greater than 0.
+     *
+     * @exception SocketException if there is an error in
+     * the underlying protocol, such as an UDP error.
+     * @exception IllegalArgumentException if the value is 0 or is
+     * negative.
+     * @see #getReceiveBufferSize()
+     */
+    public synchronized void setReceiveBufferSize(int size)
+    throws SocketException{
+        if (size <= 0) {
+            throw new IllegalArgumentException("invalid receive size");
+        }
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size));
+    }
+
+    /**
+     * Get value of the SO_RCVBUF option for this {@code DatagramSocket}, that is the
+     * buffer size used by the platform for input on this {@code DatagramSocket}.
+     *
+     * @return the value of the SO_RCVBUF option for this {@code DatagramSocket}
+     * @exception SocketException if there is an error in the underlying protocol, such as an UDP error.
+     * @see #setReceiveBufferSize(int)
+     */
+    public synchronized int getReceiveBufferSize()
+    throws SocketException{
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        int result = 0;
+        Object o = getImpl().getOption(SocketOptions.SO_RCVBUF);
+        if (o instanceof Integer) {
+            result = ((Integer)o).intValue();
+        }
+        return result;
+    }
+
+    /**
+     * Enable/disable the SO_REUSEADDR socket option.
+     * <p>
+     * For UDP sockets it may be necessary to bind more than one
+     * socket to the same socket address. This is typically for the
+     * purpose of receiving multicast packets
+     * (See {@link java.net.MulticastSocket}). The
+     * {@code SO_REUSEADDR} socket option allows multiple
+     * sockets to be bound to the same socket address if the
+     * {@code SO_REUSEADDR} socket option is enabled prior
+     * to binding the socket using {@link #bind(SocketAddress)}.
+     * <p>
+     * Note: This functionality is not supported by all existing platforms,
+     * so it is implementation specific whether this option will be ignored
+     * or not. However, if it is not supported then
+     * {@link #getReuseAddress()} will always return {@code false}.
+     * <p>
+     * When a {@code DatagramSocket} is created the initial setting
+     * of {@code SO_REUSEADDR} is disabled.
+     * <p>
+     * The behaviour when {@code SO_REUSEADDR} is enabled or
+     * disabled after a socket is bound (See {@link #isBound()})
+     * is not defined.
+     *
+     * @param on  whether to enable or disable the
+     * @exception SocketException if an error occurs enabling or
+     *            disabling the {@code SO_RESUEADDR} socket option,
+     *            or the socket is closed.
+     * @since 1.4
+     * @see #getReuseAddress()
+     * @see #bind(SocketAddress)
+     * @see #isBound()
+     * @see #isClosed()
+     */
+    public synchronized void setReuseAddress(boolean on) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        // Integer instead of Boolean for compatibility with older DatagramSocketImpl
+        if (oldImpl)
+            getImpl().setOption(SocketOptions.SO_REUSEADDR, new Integer(on?-1:0));
+        else
+            getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on));
+    }
+
+    /**
+     * Tests if SO_REUSEADDR is enabled.
+     *
+     * @return a {@code boolean} indicating whether or not SO_REUSEADDR is enabled.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as an UDP error.
+     * @since   1.4
+     * @see #setReuseAddress(boolean)
+     */
+    public synchronized boolean getReuseAddress() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        Object o = getImpl().getOption(SocketOptions.SO_REUSEADDR);
+        return ((Boolean)o).booleanValue();
+    }
+
+    /**
+     * Enable/disable SO_BROADCAST.
+     *
+     * <p> Some operating systems may require that the Java virtual machine be
+     * started with implementation specific privileges to enable this option or
+     * send broadcast datagrams.
+     *
+     * @param  on
+     *         whether or not to have broadcast turned on.
+     *
+     * @throws  SocketException
+     *          if there is an error in the underlying protocol, such as an UDP
+     *          error.
+     *
+     * @since 1.4
+     * @see #getBroadcast()
+     */
+    public synchronized void setBroadcast(boolean on) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_BROADCAST, Boolean.valueOf(on));
+    }
+
+    /**
+     * Tests if SO_BROADCAST is enabled.
+     * @return a {@code boolean} indicating whether or not SO_BROADCAST is enabled.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as an UDP error.
+     * @since 1.4
+     * @see #setBroadcast(boolean)
+     */
+    public synchronized boolean getBroadcast() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        return ((Boolean)(getImpl().getOption(SocketOptions.SO_BROADCAST))).booleanValue();
+    }
+
+    /**
+     * Sets traffic class or type-of-service octet in the IP
+     * datagram header for datagrams sent from this DatagramSocket.
+     * As the underlying network implementation may ignore this
+     * value applications should consider it a hint.
+     *
+     * <P> The tc <B>must</B> be in the range {@code 0 <= tc <=
+     * 255} or an IllegalArgumentException will be thrown.
+     * <p>Notes:
+     * <p>For Internet Protocol v4 the value consists of an
+     * {@code integer}, the least significant 8 bits of which
+     * represent the value of the TOS octet in IP packets sent by
+     * the socket.
+     * RFC 1349 defines the TOS values as follows:
+     *
+     * <UL>
+     * <LI><CODE>IPTOS_LOWCOST (0x02)</CODE></LI>
+     * <LI><CODE>IPTOS_RELIABILITY (0x04)</CODE></LI>
+     * <LI><CODE>IPTOS_THROUGHPUT (0x08)</CODE></LI>
+     * <LI><CODE>IPTOS_LOWDELAY (0x10)</CODE></LI>
+     * </UL>
+     * The last low order bit is always ignored as this
+     * corresponds to the MBZ (must be zero) bit.
+     * <p>
+     * Setting bits in the precedence field may result in a
+     * SocketException indicating that the operation is not
+     * permitted.
+     * <p>
+     * for Internet Protocol v6 {@code tc} is the value that
+     * would be placed into the sin6_flowinfo field of the IP header.
+     *
+     * @param tc        an {@code int} value for the bitset.
+     * @throws SocketException if there is an error setting the
+     * traffic class or type-of-service
+     * @since 1.4
+     * @see #getTrafficClass
+     */
+    public synchronized void setTrafficClass(int tc) throws SocketException {
+        if (tc < 0 || tc > 255)
+            throw new IllegalArgumentException("tc is not in range 0 -- 255");
+
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        try {
+            getImpl().setOption(SocketOptions.IP_TOS, tc);
+        } catch (SocketException se) {
+            // not supported if socket already connected
+            // Solaris returns error in such cases
+            if(!isConnected())
+                throw se;
+        }
+    }
+
+    /**
+     * Gets traffic class or type-of-service in the IP datagram
+     * header for packets sent from this DatagramSocket.
+     * <p>
+     * As the underlying network implementation may ignore the
+     * traffic class or type-of-service set using {@link #setTrafficClass(int)}
+     * this method may return a different value than was previously
+     * set using the {@link #setTrafficClass(int)} method on this
+     * DatagramSocket.
+     *
+     * @return the traffic class or type-of-service already set
+     * @throws SocketException if there is an error obtaining the
+     * traffic class or type-of-service value.
+     * @since 1.4
+     * @see #setTrafficClass(int)
+     */
+    public synchronized int getTrafficClass() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        return ((Integer)(getImpl().getOption(SocketOptions.IP_TOS))).intValue();
+    }
+
+    /**
+     * Closes this datagram socket.
+     * <p>
+     * Any thread currently blocked in {@link #receive} upon this socket
+     * will throw a {@link SocketException}.
+     *
+     * <p> If this socket has an associated channel then the channel is closed
+     * as well.
+     *
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public void close() {
+        synchronized(closeLock) {
+            if (isClosed())
+                return;
+            impl.close();
+            closed = true;
+        }
+    }
+
+    /**
+     * Returns whether the socket is closed or not.
+     *
+     * @return true if the socket has been closed
+     * @since 1.4
+     */
+    public boolean isClosed() {
+        synchronized(closeLock) {
+            return closed;
+        }
+    }
+
+    /**
+     * Returns the unique {@link java.nio.channels.DatagramChannel} object
+     * associated with this datagram socket, if any.
+     *
+     * <p> A datagram socket will have a channel if, and only if, the channel
+     * itself was created via the {@link java.nio.channels.DatagramChannel#open
+     * DatagramChannel.open} method.
+     *
+     * @return  the datagram channel associated with this datagram socket,
+     *          or {@code null} if this socket was not created for a channel
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public DatagramChannel getChannel() {
+        return null;
+    }
+
+    /**
+     * User defined factory for all datagram sockets.
+     */
+    static DatagramSocketImplFactory factory;
+
+    /**
+     * Sets the datagram socket implementation factory for the
+     * application. The factory can be specified only once.
+     * <p>
+     * When an application creates a new datagram socket, the socket
+     * implementation factory's {@code createDatagramSocketImpl} method is
+     * called to create the actual datagram socket implementation.
+     * <p>
+     * Passing {@code null} to the method is a no-op unless the factory
+     * was already set.
+     *
+     * <p>If there is a security manager, this method first calls
+     * the security manager's {@code checkSetFactory} method
+     * to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param      fac   the desired factory.
+     * @exception  IOException  if an I/O error occurs when setting the
+     *              datagram socket factory.
+     * @exception  SocketException  if the factory is already defined.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkSetFactory} method doesn't allow the
+     operation.
+     * @see
+     java.net.DatagramSocketImplFactory#createDatagramSocketImpl()
+     * @see       SecurityManager#checkSetFactory
+     * @since 1.3
+     */
+    public static synchronized void
+    setDatagramSocketImplFactory(DatagramSocketImplFactory fac)
+       throws IOException
+    {
+        if (factory != null) {
+            throw new SocketException("factory already defined");
+        }
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkSetFactory();
+        }
+        factory = fac;
+    }
+
+    // Android-added: for testing and internal use.
+    /**
+     * @hide internal use only
+     */
+    public FileDescriptor getFileDescriptor$() {
+        return impl.fd;
+    }
+
+}
diff --git a/java/net/DatagramSocketImpl.java b/java/net/DatagramSocketImpl.java
new file mode 100644
index 0000000..537edfe
--- /dev/null
+++ b/java/net/DatagramSocketImpl.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+
+/**
+ * Abstract datagram and multicast socket implementation base class.
+ * @author Pavani Diwanji
+ * @since  JDK1.1
+ */
+
+public abstract class DatagramSocketImpl implements SocketOptions {
+
+    /**
+     * The local port number.
+     */
+    protected int localPort;
+
+    /**
+     * The file descriptor object.
+     */
+    protected FileDescriptor fd;
+
+    int dataAvailable() {
+        // default impl returns zero, which disables the calling
+        // functionality
+        return 0;
+    }
+
+    /**
+     * The DatagramSocket or MulticastSocket
+     * that owns this impl
+     */
+    DatagramSocket socket;
+
+    void setDatagramSocket(DatagramSocket socket) {
+        this.socket = socket;
+    }
+
+    DatagramSocket getDatagramSocket() {
+        return socket;
+    }
+
+    /**
+     * Creates a datagram socket.
+     * @exception SocketException if there is an error in the
+     * underlying protocol, such as a TCP error.
+     */
+    protected abstract void create() throws SocketException;
+
+    /**
+     * Binds a datagram socket to a local port and address.
+     * @param lport the local port
+     * @param laddr the local address
+     * @exception SocketException if there is an error in the
+     * underlying protocol, such as a TCP error.
+     */
+    protected abstract void bind(int lport, InetAddress laddr) throws SocketException;
+
+    /**
+     * Sends a datagram packet. The packet contains the data and the
+     * destination address to send the packet to.
+     * @param p the packet to be sent.
+     * @exception IOException if an I/O exception occurs while sending the
+     * datagram packet.
+     * @exception  PortUnreachableException may be thrown if the socket is connected
+     * to a currently unreachable destination. Note, there is no guarantee that
+     * the exception will be thrown.
+     */
+    protected abstract void send(DatagramPacket p) throws IOException;
+
+    /**
+     * Connects a datagram socket to a remote destination. This associates the remote
+     * address with the local socket so that datagrams may only be sent to this destination
+     * and received from this destination. This may be overridden to call a native
+     * system connect.
+     *
+     * <p>If the remote destination to which the socket is connected does not
+     * exist, or is otherwise unreachable, and if an ICMP destination unreachable
+     * packet has been received for that address, then a subsequent call to
+     * send or receive may throw a PortUnreachableException.
+     * Note, there is no guarantee that the exception will be thrown.
+     * @param address the remote InetAddress to connect to
+     * @param port the remote port number
+     * @exception   SocketException may be thrown if the socket cannot be
+     * connected to the remote destination
+     * @since 1.4
+     */
+    protected void connect(InetAddress address, int port) throws SocketException {}
+
+    /**
+     * Disconnects a datagram socket from its remote destination.
+     * @since 1.4
+     */
+    protected void disconnect() {}
+
+    /**
+     * Peek at the packet to see who it is from. Updates the specified {@code InetAddress}
+     * to the address which the packet came from.
+     * @param i an InetAddress object
+     * @return the port number which the packet came from.
+     * @exception IOException if an I/O exception occurs
+     * @exception  PortUnreachableException may be thrown if the socket is connected
+     *       to a currently unreachable destination. Note, there is no guarantee that the
+     *       exception will be thrown.
+     */
+    protected abstract int peek(InetAddress i) throws IOException;
+
+    /**
+     * Peek at the packet to see who it is from. The data is copied into the specified
+     * {@code DatagramPacket}. The data is returned,
+     * but not consumed, so that a subsequent peekData/receive operation
+     * will see the same data.
+     * @param p the Packet Received.
+     * @return the port number which the packet came from.
+     * @exception IOException if an I/O exception occurs
+     * @exception  PortUnreachableException may be thrown if the socket is connected
+     *       to a currently unreachable destination. Note, there is no guarantee that the
+     *       exception will be thrown.
+     * @since 1.4
+     */
+    protected abstract int peekData(DatagramPacket p) throws IOException;
+    /**
+     * Receive the datagram packet.
+     * @param p the Packet Received.
+     * @exception IOException if an I/O exception occurs
+     * while receiving the datagram packet.
+     * @exception  PortUnreachableException may be thrown if the socket is connected
+     *       to a currently unreachable destination. Note, there is no guarantee that the
+     *       exception will be thrown.
+     */
+    protected abstract void receive(DatagramPacket p) throws IOException;
+
+    /**
+     * Set the TTL (time-to-live) option.
+     * @param ttl a byte specifying the TTL value
+     *
+     * @deprecated use setTimeToLive instead.
+     * @exception IOException if an I/O exception occurs while setting
+     * the time-to-live option.
+     * @see #getTTL()
+     */
+    @Deprecated
+    protected abstract void setTTL(byte ttl) throws IOException;
+
+    /**
+     * Retrieve the TTL (time-to-live) option.
+     *
+     * @exception IOException if an I/O exception occurs
+     * while retrieving the time-to-live option
+     * @deprecated use getTimeToLive instead.
+     * @return a byte representing the TTL value
+     * @see #setTTL(byte)
+     */
+    @Deprecated
+    protected abstract byte getTTL() throws IOException;
+
+    /**
+     * Set the TTL (time-to-live) option.
+     * @param ttl an {@code int} specifying the time-to-live value
+     * @exception IOException if an I/O exception occurs
+     * while setting the time-to-live option.
+     * @see #getTimeToLive()
+     */
+    protected abstract void setTimeToLive(int ttl) throws IOException;
+
+    /**
+     * Retrieve the TTL (time-to-live) option.
+     * @exception IOException if an I/O exception occurs
+     * while retrieving the time-to-live option
+     * @return an {@code int} representing the time-to-live value
+     * @see #setTimeToLive(int)
+     */
+    protected abstract int getTimeToLive() throws IOException;
+
+    /**
+     * Join the multicast group.
+     * @param inetaddr multicast address to join.
+     * @exception IOException if an I/O exception occurs
+     * while joining the multicast group.
+     */
+    protected abstract void join(InetAddress inetaddr) throws IOException;
+
+    /**
+     * Leave the multicast group.
+     * @param inetaddr multicast address to leave.
+     * @exception IOException if an I/O exception occurs
+     * while leaving the multicast group.
+     */
+    protected abstract void leave(InetAddress inetaddr) throws IOException;
+
+    /**
+     * Join the multicast group.
+     * @param mcastaddr address to join.
+     * @param netIf specifies the local interface to receive multicast
+     *        datagram packets
+     * @throws IOException if an I/O exception occurs while joining
+     * the multicast group
+     * @since 1.4
+     */
+    protected abstract void joinGroup(SocketAddress mcastaddr,
+                                      NetworkInterface netIf)
+        throws IOException;
+
+    /**
+     * Leave the multicast group.
+     * @param mcastaddr address to leave.
+     * @param netIf specified the local interface to leave the group at
+     * @throws IOException if an I/O exception occurs while leaving
+     * the multicast group
+     * @since 1.4
+     */
+    protected abstract void leaveGroup(SocketAddress mcastaddr,
+                                       NetworkInterface netIf)
+        throws IOException;
+
+    /**
+     * Close the socket.
+     */
+    protected abstract void close();
+
+    /**
+     * Gets the local port.
+     * @return an {@code int} representing the local port value
+     */
+    protected int getLocalPort() {
+        return localPort;
+    }
+
+    <T> void setOption(SocketOption<T> name, T value) throws IOException {
+        if (name == StandardSocketOptions.SO_SNDBUF) {
+            setOption(SocketOptions.SO_SNDBUF, value);
+        } else if (name == StandardSocketOptions.SO_RCVBUF) {
+            setOption(SocketOptions.SO_RCVBUF, value);
+        } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+            setOption(SocketOptions.SO_REUSEADDR, value);
+        } else if (name == StandardSocketOptions.IP_TOS) {
+            setOption(SocketOptions.IP_TOS, value);
+        } else if (name == StandardSocketOptions.IP_MULTICAST_IF &&
+            (getDatagramSocket() instanceof MulticastSocket)) {
+            setOption(SocketOptions.IP_MULTICAST_IF2, value);
+        } else if (name == StandardSocketOptions.IP_MULTICAST_TTL &&
+            (getDatagramSocket() instanceof MulticastSocket)) {
+            if (! (value instanceof Integer)) {
+                throw new IllegalArgumentException("not an integer");
+            }
+            setTimeToLive((Integer)value);
+        } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP &&
+            (getDatagramSocket() instanceof MulticastSocket)) {
+            setOption(SocketOptions.IP_MULTICAST_LOOP, value);
+        } else {
+            throw new UnsupportedOperationException("unsupported option");
+        }
+    }
+
+    <T> T getOption(SocketOption<T> name) throws IOException {
+        if (name == StandardSocketOptions.SO_SNDBUF) {
+            return (T) getOption(SocketOptions.SO_SNDBUF);
+        } else if (name == StandardSocketOptions.SO_RCVBUF) {
+            return (T) getOption(SocketOptions.SO_RCVBUF);
+        } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+            return (T) getOption(SocketOptions.SO_REUSEADDR);
+        } else if (name == StandardSocketOptions.IP_TOS) {
+            return (T) getOption(SocketOptions.IP_TOS);
+        } else if (name == StandardSocketOptions.IP_MULTICAST_IF &&
+            (getDatagramSocket() instanceof MulticastSocket)) {
+            return (T) getOption(SocketOptions.IP_MULTICAST_IF2);
+        } else if (name == StandardSocketOptions.IP_MULTICAST_TTL &&
+            (getDatagramSocket() instanceof MulticastSocket)) {
+            Integer ttl = getTimeToLive();
+            return (T)ttl;
+        } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP &&
+            (getDatagramSocket() instanceof MulticastSocket)) {
+            return (T) getOption(SocketOptions.IP_MULTICAST_LOOP);
+        } else {
+            throw new UnsupportedOperationException("unsupported option");
+        }
+    }
+
+    /**
+     * Gets the datagram socket file descriptor.
+     * @return a {@code FileDescriptor} object representing the datagram socket
+     * file descriptor
+     */
+    protected FileDescriptor getFileDescriptor() {
+        return fd;
+    }
+}
diff --git a/java/net/DatagramSocketImplFactory.java b/java/net/DatagramSocketImplFactory.java
new file mode 100644
index 0000000..4d89196
--- /dev/null
+++ b/java/net/DatagramSocketImplFactory.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * This interface defines a factory for datagram socket implementations. It
+ * is used by the classes {@code DatagramSocket} to create actual socket
+ * implementations.
+ *
+ * @author  Yingxian Wang
+ * @see     java.net.DatagramSocket
+ * @since   1.3
+ */
+public
+interface DatagramSocketImplFactory {
+    /**
+     * Creates a new {@code DatagramSocketImpl} instance.
+     *
+     * @return  a new instance of {@code DatagramSocketImpl}.
+     * @see     java.net.DatagramSocketImpl
+     */
+    DatagramSocketImpl createDatagramSocketImpl();
+}
diff --git a/java/net/DefaultDatagramSocketImplFactory.java b/java/net/DefaultDatagramSocketImplFactory.java
new file mode 100644
index 0000000..ad62c58
--- /dev/null
+++ b/java/net/DefaultDatagramSocketImplFactory.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2007,2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+
+import java.security.AccessController;
+
+/**
+ * This class defines a factory for creating DatagramSocketImpls. It defaults
+ * to creating plain DatagramSocketImpls, but may create other DatagramSocketImpls
+ * by setting the impl.prefix system property.
+ *
+ * @author Chris Hegarty
+ */
+
+class DefaultDatagramSocketImplFactory {
+    static Class<?> prefixImplClass = null;
+
+    static {
+        String prefix = null;
+        try {
+            prefix = AccessController.doPrivileged(
+                new sun.security.action.GetPropertyAction("impl.prefix", null));
+            if (prefix != null)
+                prefixImplClass = Class.forName("java.net."+prefix+"DatagramSocketImpl");
+        } catch (Exception e) {
+            System.err.println("Can't find class: java.net." +
+                                prefix +
+                                "DatagramSocketImpl: check impl.prefix property");
+            //prefixImplClass = null;
+        }
+    }
+
+    /**
+     * Creates a new <code>DatagramSocketImpl</code> instance.
+     *
+     * @param   isMulticast     true if this impl if for a MutlicastSocket
+     * @return  a new instance of a <code>DatagramSocketImpl</code>.
+     */
+    static DatagramSocketImpl createDatagramSocketImpl(boolean isMulticast /*unused on unix*/)
+        throws SocketException {
+        if (prefixImplClass != null) {
+            try {
+                return (DatagramSocketImpl)prefixImplClass.newInstance();
+            } catch (Exception e) {
+                throw new SocketException("can't instantiate DatagramSocketImpl");
+            }
+        } else {
+            return new java.net.PlainDatagramSocketImpl();
+        }
+    }
+}
diff --git a/java/net/DefaultFileNameMap.java b/java/net/DefaultFileNameMap.java
new file mode 100644
index 0000000..da67d14
--- /dev/null
+++ b/java/net/DefaultFileNameMap.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.net;
+
+import libcore.content.type.MimeMap;
+
+/**
+ * Implements {@link FileNameMap} in terms of {@link MimeMap}.
+ */
+class DefaultFileNameMap implements FileNameMap {
+
+    public String getContentTypeFor(String filename) {
+        int fragmentIndex = filename.indexOf('#');
+        if (fragmentIndex >= 0) {
+            filename = filename.substring(0, fragmentIndex);
+        }
+        if (filename.endsWith("/")) { // a directory
+            return "text/html";
+        }
+
+        int slashIndex = filename.lastIndexOf('/');
+        if (slashIndex >= 0) {
+            filename = filename.substring(slashIndex);
+        }
+
+        MimeMap mimeMap = MimeMap.getDefault();
+        int dotIndex = -1;
+        do {
+            String ext = filename.substring(dotIndex + 1);
+            String result = mimeMap.guessMimeTypeFromExtension(ext);
+            if ((result != null) &&
+                    // Compat behavior: If there's a '/', then extension must not be the
+                    // whole string. http://b/144977800
+                    (slashIndex < 0 || dotIndex >= 0)) {
+                return result;
+            }
+            dotIndex = filename.indexOf('.', dotIndex + 1);
+        } while (dotIndex >= 0);
+        return null;
+    }
+}
diff --git a/java/net/DefaultInterface.java b/java/net/DefaultInterface.java
new file mode 100644
index 0000000..0c31cb6
--- /dev/null
+++ b/java/net/DefaultInterface.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * Choose a network interface to be the default for
+ * outgoing IPv6 traffic that does not specify a scope_id (and which needs one).
+ *
+ * Platforms that do not require a default interface may return null
+ * which is what this implementation does.
+ */
+
+class DefaultInterface {
+
+    static NetworkInterface getDefault() {
+        return null;
+    }
+}
diff --git a/java/net/FileNameMap.java b/java/net/FileNameMap.java
new file mode 100644
index 0000000..393b5aa
--- /dev/null
+++ b/java/net/FileNameMap.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * A simple interface which provides a mechanism to map
+ * between a file name and a MIME type string.
+ *
+ * @author  Steven B. Byrne
+ * @since   JDK1.1
+ */
+public interface FileNameMap {
+
+    /**
+     * Gets the MIME type for the specified file name.
+     * @param fileName the specified file name
+     * @return a {@code String} indicating the MIME
+     * type for the specified file name.
+     */
+    public String getContentTypeFor(String fileName);
+}
diff --git a/java/net/HttpCookie.java b/java/net/HttpCookie.java
new file mode 100644
index 0000000..3ff33c7
--- /dev/null
+++ b/java/net/HttpCookie.java
@@ -0,0 +1,1213 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.TimeZone;
+import libcore.net.http.HttpDate;
+
+/**
+ * An HttpCookie object represents an HTTP cookie, which carries state
+ * information between server and user agent. Cookie is widely adopted
+ * to create stateful sessions.
+ *
+ * <p> There are 3 HTTP cookie specifications:
+ * <blockquote>
+ *   Netscape draft<br>
+ *   RFC 2109 - <a href="http://www.ietf.org/rfc/rfc2109.txt">
+ * <i>http://www.ietf.org/rfc/rfc2109.txt</i></a><br>
+ *   RFC 2965 - <a href="http://www.ietf.org/rfc/rfc2965.txt">
+ * <i>http://www.ietf.org/rfc/rfc2965.txt</i></a>
+ * </blockquote>
+ *
+ * <p> HttpCookie class can accept all these 3 forms of syntax.
+ *
+ * @author Edward Wang
+ * @since 1.6
+ */
+public final class HttpCookie implements Cloneable {
+    // BEGIN Android-added: Reserved name can't be HttpCookie name
+    private static final Set<String> RESERVED_NAMES = new HashSet<String>();
+
+    static {
+        RESERVED_NAMES.add("comment");    //           RFC 2109  RFC 2965  RFC 6265
+        RESERVED_NAMES.add("commenturl"); //                     RFC 2965  RFC 6265
+        RESERVED_NAMES.add("discard");    //                     RFC 2965  RFC 6265
+        RESERVED_NAMES.add("domain");     // Netscape  RFC 2109  RFC 2965  RFC 6265
+        RESERVED_NAMES.add("expires");    // Netscape
+        RESERVED_NAMES.add("httponly");   //                               RFC 6265
+        RESERVED_NAMES.add("max-age");    //           RFC 2109  RFC 2965  RFC 6265
+        RESERVED_NAMES.add("path");       // Netscape  RFC 2109  RFC 2965  RFC 6265
+        RESERVED_NAMES.add("port");       //                     RFC 2965  RFC 6265
+        RESERVED_NAMES.add("secure");     // Netscape  RFC 2109  RFC 2965  RFC 6265
+        RESERVED_NAMES.add("version");    //           RFC 2109  RFC 2965  RFC 6265
+    }
+    // END Android-added: Reserved name can't be HttpCookie name
+
+    // ---------------- Fields --------------
+
+    // The value of the cookie itself.
+    private final String name;  // NAME= ... "$Name" style is reserved
+    private String value;       // value of NAME
+
+    // Attributes encoded in the header's cookie fields.
+    private String comment;     // Comment=VALUE ... describes cookie's use
+    private String commentURL;  // CommentURL="http URL" ... describes cookie's use
+    private boolean toDiscard;  // Discard ... discard cookie unconditionally
+    private String domain;      // Domain=VALUE ... domain that sees cookie
+    private long maxAge = MAX_AGE_UNSPECIFIED;  // Max-Age=VALUE ... cookies auto-expire
+    private String path;        // Path=VALUE ... URLs that see the cookie
+    private String portlist;    // Port[="portlist"] ... the port cookie may be returned to
+    private boolean secure;     // Secure ... e.g. use SSL
+    private boolean httpOnly;   // HttpOnly ... i.e. not accessible to scripts
+    private int version = 1;    // Version=1 ... RFC 2965 style
+
+    // The original header this cookie was consructed from, if it was
+    // constructed by parsing a header, otherwise null.
+    private final String header;
+
+    //
+    // Android-changed: Fixed units, s/seconds/milliseconds/, in comment below.
+    // Hold the creation time (in milliseconds) of the http cookie for later
+    // expiration calculation
+    private final long whenCreated;
+
+    // Since the positive and zero max-age have their meanings,
+    // this value serves as a hint as 'not specify max-age'
+    private final static long MAX_AGE_UNSPECIFIED = -1;
+
+    // BEGIN Android-removed: Use libcore.net.http.HttpDate for parsing.
+    // date formats used by Netscape's cookie draft
+    // as well as formats seen on various sites
+    /*
+    private final static String[] COOKIE_DATE_FORMATS = {
+        "EEE',' dd-MMM-yyyy HH:mm:ss 'GMT'",
+        "EEE',' dd MMM yyyy HH:mm:ss 'GMT'",
+        "EEE MMM dd yyyy HH:mm:ss 'GMT'Z",
+        "EEE',' dd-MMM-yy HH:mm:ss 'GMT'",
+        "EEE',' dd MMM yy HH:mm:ss 'GMT'",
+        "EEE MMM dd yy HH:mm:ss 'GMT'Z"
+    };
+    */
+    // END Android-removed: Use libcore.net.http.HttpDate for parsing.
+
+    // constant strings represent set-cookie header token
+    private final static String SET_COOKIE = "set-cookie:";
+    private final static String SET_COOKIE2 = "set-cookie2:";
+
+    // ---------------- Ctors --------------
+
+    /**
+     * Constructs a cookie with a specified name and value.
+     *
+     * <p> The name must conform to RFC 2965. That means it can contain
+     * only ASCII alphanumeric characters and cannot contain commas,
+     * semicolons, or white space or begin with a $ character. The cookie's
+     * name cannot be changed after creation.
+     *
+     * <p> The value can be anything the server chooses to send. Its
+     * value is probably of interest only to the server. The cookie's
+     * value can be changed after creation with the
+     * {@code setValue} method.
+     *
+     * <p> By default, cookies are created according to the RFC 2965
+     * cookie specification. The version can be changed with the
+     * {@code setVersion} method.
+     *
+     *
+     * @param  name
+     *         a {@code String} specifying the name of the cookie
+     *
+     * @param  value
+     *         a {@code String} specifying the value of the cookie
+     *
+     * @throws  IllegalArgumentException
+     *          if the cookie name contains illegal characters
+     * @throws  NullPointerException
+     *          if {@code name} is {@code null}
+     *
+     * @see #setValue
+     * @see #setVersion
+     */
+    public HttpCookie(String name, String value) {
+        this(name, value, null /*header*/);
+    }
+
+    private HttpCookie(String name, String value, String header) {
+        name = name.trim();
+        if (name.length() == 0 || !isToken(name) || name.charAt(0) == '$') {
+            throw new IllegalArgumentException("Illegal cookie name");
+        }
+
+        this.name = name;
+        this.value = value;
+        toDiscard = false;
+        secure = false;
+
+        whenCreated = System.currentTimeMillis();
+        portlist = null;
+        this.header = header;
+    }
+
+    /**
+     * Constructs cookies from set-cookie or set-cookie2 header string.
+     * RFC 2965 section 3.2.2 set-cookie2 syntax indicates that one header line
+     * may contain more than one cookie definitions, so this is a static
+     * utility method instead of another constructor.
+     *
+     * @param  header
+     *         a {@code String} specifying the set-cookie header. The header
+     *         should start with "set-cookie", or "set-cookie2" token; or it
+     *         should have no leading token at all.
+     *
+     * @return  a List of cookie parsed from header line string
+     *
+     * @throws  IllegalArgumentException
+     *          if header string violates the cookie specification's syntax or
+     *          the cookie name contains illegal characters.
+     * @throws  NullPointerException
+     *          if the header string is {@code null}
+     */
+    public static List<HttpCookie> parse(String header) {
+        return parse(header, false);
+    }
+
+    // Private version of parse() that will store the original header used to
+    // create the cookie, in the cookie itself. This can be useful for filtering
+    // Set-Cookie[2] headers, using the internal parsing logic defined in this
+    // class.
+    private static List<HttpCookie> parse(String header, boolean retainHeader) {
+
+        int version = guessCookieVersion(header);
+
+        // if header start with set-cookie or set-cookie2, strip it off
+        if (startsWithIgnoreCase(header, SET_COOKIE2)) {
+            header = header.substring(SET_COOKIE2.length());
+        } else if (startsWithIgnoreCase(header, SET_COOKIE)) {
+            header = header.substring(SET_COOKIE.length());
+        }
+
+        List<HttpCookie> cookies = new java.util.ArrayList<>();
+        // The Netscape cookie may have a comma in its expires attribute, while
+        // the comma is the delimiter in rfc 2965/2109 cookie header string.
+        // so the parse logic is slightly different
+        if (version == 0) {
+            // Netscape draft cookie
+            HttpCookie cookie = parseInternal(header, retainHeader);
+            cookie.setVersion(0);
+            cookies.add(cookie);
+        } else {
+            // rfc2965/2109 cookie
+            // if header string contains more than one cookie,
+            // it'll separate them with comma
+            List<String> cookieStrings = splitMultiCookies(header);
+            for (String cookieStr : cookieStrings) {
+                HttpCookie cookie = parseInternal(cookieStr, retainHeader);
+                cookie.setVersion(1);
+                cookies.add(cookie);
+            }
+        }
+
+        return cookies;
+    }
+
+    // ---------------- Public operations --------------
+
+    /**
+     * Reports whether this HTTP cookie has expired or not.
+     *
+     * @return  {@code true} to indicate this HTTP cookie has expired;
+     *          otherwise, {@code false}
+     */
+    public boolean hasExpired() {
+        if (maxAge == 0) return true;
+
+        // if not specify max-age, this cookie should be
+        // discarded when user agent is to be closed, but
+        // it is not expired.
+        if (maxAge == MAX_AGE_UNSPECIFIED) return false;
+
+        long deltaSecond = (System.currentTimeMillis() - whenCreated) / 1000;
+        if (deltaSecond > maxAge)
+            return true;
+        else
+            return false;
+    }
+
+    /**
+     * Specifies a comment that describes a cookie's purpose.
+     * The comment is useful if the browser presents the cookie
+     * to the user. Comments are not supported by Netscape Version 0 cookies.
+     *
+     * @param  purpose
+     *         a {@code String} specifying the comment to display to the user
+     *
+     * @see  #getComment
+     */
+    public void setComment(String purpose) {
+        comment = purpose;
+    }
+
+    /**
+     * Returns the comment describing the purpose of this cookie, or
+     * {@code null} if the cookie has no comment.
+     *
+     * @return  a {@code String} containing the comment, or {@code null} if none
+     *
+     * @see  #setComment
+     */
+    public String getComment() {
+        return comment;
+    }
+
+    /**
+     * Specifies a comment URL that describes a cookie's purpose.
+     * The comment URL is useful if the browser presents the cookie
+     * to the user. Comment URL is RFC 2965 only.
+     *
+     * @param  purpose
+     *         a {@code String} specifying the comment URL to display to the user
+     *
+     * @see  #getCommentURL
+     */
+    public void setCommentURL(String purpose) {
+        commentURL = purpose;
+    }
+
+    /**
+     * Returns the comment URL describing the purpose of this cookie, or
+     * {@code null} if the cookie has no comment URL.
+     *
+     * @return  a {@code String} containing the comment URL, or {@code null}
+     *          if none
+     *
+     * @see  #setCommentURL
+     */
+    public String getCommentURL() {
+        return commentURL;
+    }
+
+    /**
+     * Specify whether user agent should discard the cookie unconditionally.
+     * This is RFC 2965 only attribute.
+     *
+     * @param  discard
+     *         {@code true} indicates to discard cookie unconditionally
+     *
+     * @see  #getDiscard
+     */
+    public void setDiscard(boolean discard) {
+        toDiscard = discard;
+    }
+
+    /**
+     * Returns the discard attribute of the cookie
+     *
+     * @return  a {@code boolean} to represent this cookie's discard attribute
+     *
+     * @see  #setDiscard
+     */
+    public boolean getDiscard() {
+        return toDiscard;
+    }
+
+    /**
+     * Specify the portlist of the cookie, which restricts the port(s)
+     * to which a cookie may be sent back in a Cookie header.
+     *
+     * @param  ports
+     *         a {@code String} specify the port list, which is comma separated
+     *         series of digits
+     *
+     * @see  #getPortlist
+     */
+    public void setPortlist(String ports) {
+        portlist = ports;
+    }
+
+    /**
+     * Returns the port list attribute of the cookie
+     *
+     * @return  a {@code String} contains the port list or {@code null} if none
+     *
+     * @see  #setPortlist
+     */
+    public String getPortlist() {
+        return portlist;
+    }
+
+    /**
+     * Specifies the domain within which this cookie should be presented.
+     *
+     * <p> The form of the domain name is specified by RFC 2965. A domain
+     * name begins with a dot ({@code .foo.com}) and means that
+     * the cookie is visible to servers in a specified Domain Name System
+     * (DNS) zone (for example, {@code www.foo.com}, but not
+     * {@code a.b.foo.com}). By default, cookies are only returned
+     * to the server that sent them.
+     *
+     * @param  pattern
+     *         a {@code String} containing the domain name within which this
+     *         cookie is visible; form is according to RFC 2965
+     *
+     * @see  #getDomain
+     */
+    public void setDomain(String pattern) {
+        if (pattern != null)
+            domain = pattern.toLowerCase();
+        else
+            domain = pattern;
+    }
+
+    /**
+     * Returns the domain name set for this cookie. The form of the domain name
+     * is set by RFC 2965.
+     *
+     * @return  a {@code String} containing the domain name
+     *
+     * @see  #setDomain
+     */
+    public String getDomain() {
+        return domain;
+    }
+
+    /**
+     * Sets the maximum age of the cookie in seconds.
+     *
+     * <p> A positive value indicates that the cookie will expire
+     * after that many seconds have passed. Note that the value is
+     * the <i>maximum</i> age when the cookie will expire, not the cookie's
+     * current age.
+     *
+     * <p> A negative value means that the cookie is not stored persistently
+     * and will be deleted when the Web browser exits. A zero value causes the
+     * cookie to be deleted.
+     *
+     * @param  expiry
+     *         an integer specifying the maximum age of the cookie in seconds;
+     *         if zero, the cookie should be discarded immediately; otherwise,
+     *         the cookie's max age is unspecified.
+     *
+     * @see  #getMaxAge
+     */
+    public void setMaxAge(long expiry) {
+        maxAge = expiry;
+    }
+
+    /**
+     * Returns the maximum age of the cookie, specified in seconds. By default,
+     * {@code -1} indicating the cookie will persist until browser shutdown.
+     *
+     * @return  an integer specifying the maximum age of the cookie in seconds
+     *
+     * @see  #setMaxAge
+     */
+    public long getMaxAge() {
+        return maxAge;
+    }
+
+    /**
+     * Specifies a path for the cookie to which the client should return
+     * the cookie.
+     *
+     * <p> The cookie is visible to all the pages in the directory
+     * you specify, and all the pages in that directory's subdirectories.
+     * A cookie's path must include the servlet that set the cookie,
+     * for example, <i>/catalog</i>, which makes the cookie
+     * visible to all directories on the server under <i>/catalog</i>.
+     *
+     * <p> Consult RFC 2965 (available on the Internet) for more
+     * information on setting path names for cookies.
+     *
+     * @param  uri
+     *         a {@code String} specifying a path
+     *
+     * @see  #getPath
+     */
+    public void setPath(String uri) {
+        path = uri;
+    }
+
+    /**
+     * Returns the path on the server to which the browser returns this cookie.
+     * The cookie is visible to all subpaths on the server.
+     *
+     * @return  a {@code String} specifying a path that contains a servlet name,
+     *          for example, <i>/catalog</i>
+     *
+     * @see  #setPath
+     */
+    public String getPath() {
+        return path;
+    }
+
+    /**
+     * Indicates whether the cookie should only be sent using a secure protocol,
+     * such as HTTPS or SSL.
+     *
+     * <p> The default value is {@code false}.
+     *
+     * @param  flag
+     *         If {@code true}, the cookie can only be sent over a secure
+     *         protocol like HTTPS. If {@code false}, it can be sent over
+     *         any protocol.
+     *
+     * @see  #getSecure
+     */
+    public void setSecure(boolean flag) {
+        secure = flag;
+    }
+
+    /**
+     * Returns {@code true} if sending this cookie should be restricted to a
+     * secure protocol, or {@code false} if the it can be sent using any
+     * protocol.
+     *
+     * @return  {@code false} if the cookie can be sent over any standard
+     *          protocol; otherwise, {@code true}
+     *
+     * @see  #setSecure
+     */
+    public boolean getSecure() {
+        return secure;
+    }
+
+    /**
+     * Returns the name of the cookie. The name cannot be changed after
+     * creation.
+     *
+     * @return  a {@code String} specifying the cookie's name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Assigns a new value to a cookie after the cookie is created.
+     * If you use a binary value, you may want to use BASE64 encoding.
+     *
+     * <p> With Version 0 cookies, values should not contain white space,
+     * brackets, parentheses, equals signs, commas, double quotes, slashes,
+     * question marks, at signs, colons, and semicolons. Empty values may not
+     * behave the same way on all browsers.
+     *
+     * @param  newValue
+     *         a {@code String} specifying the new value
+     *
+     * @see  #getValue
+     */
+    public void setValue(String newValue) {
+        value = newValue;
+    }
+
+    /**
+     * Returns the value of the cookie.
+     *
+     * @return  a {@code String} containing the cookie's present value
+     *
+     * @see  #setValue
+     */
+    public String getValue() {
+        return value;
+    }
+
+    /**
+     * Returns the version of the protocol this cookie complies with. Version 1
+     * complies with RFC 2965/2109, and version 0 complies with the original
+     * cookie specification drafted by Netscape. Cookies provided by a browser
+     * use and identify the browser's cookie version.
+     *
+     * @return  0 if the cookie complies with the original Netscape
+     *          specification; 1 if the cookie complies with RFC 2965/2109
+     *
+     * @see  #setVersion
+     */
+    public int getVersion() {
+        return version;
+    }
+
+    /**
+     * Sets the version of the cookie protocol this cookie complies
+     * with. Version 0 complies with the original Netscape cookie
+     * specification. Version 1 complies with RFC 2965/2109.
+     *
+     * @param  v
+     *         0 if the cookie should comply with the original Netscape
+     *         specification; 1 if the cookie should comply with RFC 2965/2109
+     *
+     * @throws  IllegalArgumentException
+     *          if {@code v} is neither 0 nor 1
+     *
+     * @see  #getVersion
+     */
+    public void setVersion(int v) {
+        if (v != 0 && v != 1) {
+            throw new IllegalArgumentException("cookie version should be 0 or 1");
+        }
+
+        version = v;
+    }
+
+    /**
+     * Returns {@code true} if this cookie contains the <i>HttpOnly</i>
+     * attribute. This means that the cookie should not be accessible to
+     * scripting engines, like javascript.
+     *
+     * @return  {@code true} if this cookie should be considered HTTPOnly
+     *
+     * @see  #setHttpOnly(boolean)
+     */
+    public boolean isHttpOnly() {
+        return httpOnly;
+    }
+
+    /**
+     * Indicates whether the cookie should be considered HTTP Only. If set to
+     * {@code true} it means the cookie should not be accessible to scripting
+     * engines like javascript.
+     *
+     * @param  httpOnly
+     *         if {@code true} make the cookie HTTP only, i.e. only visible as
+     *         part of an HTTP request.
+     *
+     * @see  #isHttpOnly()
+     */
+    public void setHttpOnly(boolean httpOnly) {
+        this.httpOnly = httpOnly;
+    }
+
+    /**
+     * The utility method to check whether a host name is in a domain or not.
+     *
+     * <p> This concept is described in the cookie specification.
+     * To understand the concept, some terminologies need to be defined first:
+     * <blockquote>
+     * effective host name = hostname if host name contains dot<br>
+     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;or = hostname.local if not
+     * </blockquote>
+     * <p>Host A's name domain-matches host B's if:
+     * <blockquote><ul>
+     *   <li>their host name strings string-compare equal; or</li>
+     *   <li>A is a HDN string and has the form NB, where N is a non-empty
+     *   name string, B has the form .B', and B' is a HDN string.  (So,
+     *   x.y.com domain-matches .Y.com but not Y.com.)</li>
+     * </ul></blockquote>
+     *
+     * <p>A host isn't in a domain (RFC 2965 sec. 3.3.2) if:
+     * <blockquote><ul>
+     *   <li>The value for the Domain attribute contains no embedded dots,
+     *   and the value is not .local.</li>
+     *   <li>The effective host name that derives from the request-host does
+     *   not domain-match the Domain attribute.</li>
+     *   <li>The request-host is a HDN (not IP address) and has the form HD,
+     *   where D is the value of the Domain attribute, and H is a string
+     *   that contains one or more dots.</li>
+     * </ul></blockquote>
+     *
+     * <p>Examples:
+     * <blockquote><ul>
+     *   <li>A Set-Cookie2 from request-host y.x.foo.com for Domain=.foo.com
+     *   would be rejected, because H is y.x and contains a dot.</li>
+     *   <li>A Set-Cookie2 from request-host x.foo.com for Domain=.foo.com
+     *   would be accepted.</li>
+     *   <li>A Set-Cookie2 with Domain=.com or Domain=.com., will always be
+     *   rejected, because there is no embedded dot.</li>
+     *   <li>A Set-Cookie2 from request-host example for Domain=.local will
+     *   be accepted, because the effective host name for the request-
+     *   host is example.local, and example.local domain-matches .local.</li>
+     * </ul></blockquote>
+     *
+     * @param  domain
+     *         the domain name to check host name with
+     *
+     * @param  host
+     *         the host name in question
+     *
+     * @return  {@code true} if they domain-matches; {@code false} if not
+     */
+    public static boolean domainMatches(String domain, String host) {
+        if (domain == null || host == null)
+            return false;
+
+        // if there's no embedded dot in domain and domain is not .local
+        boolean isLocalDomain = ".local".equalsIgnoreCase(domain);
+        int embeddedDotInDomain = domain.indexOf('.');
+        if (embeddedDotInDomain == 0)
+            embeddedDotInDomain = domain.indexOf('.', 1);
+        if (!isLocalDomain
+            && (embeddedDotInDomain == -1 ||
+                embeddedDotInDomain == domain.length() - 1))
+            return false;
+
+        // if the host name contains no dot and the domain name
+        // is .local or host.local
+        int firstDotInHost = host.indexOf('.');
+        if (firstDotInHost == -1 &&
+            (isLocalDomain ||
+             domain.equalsIgnoreCase(host + ".local"))) {
+            return true;
+        }
+
+        int domainLength = domain.length();
+        int lengthDiff = host.length() - domainLength;
+        if (lengthDiff == 0) {
+            // if the host name and the domain name are just string-compare euqal
+            return host.equalsIgnoreCase(domain);
+        }
+        else if (lengthDiff > 0) {
+            // need to check H & D component
+            String H = host.substring(0, lengthDiff);
+            String D = host.substring(lengthDiff);
+
+            // BEGIN Android-changed: App compat reason
+            // 1) Disregard RFC 2965 sec. 3.3.2, the "The request-host is a HDN..."
+            // 2) match "foo.local" for domain ".local".
+            // return (H.indexOf('.') == -1 && D.equalsIgnoreCase(domain));
+            return D.equalsIgnoreCase(domain) && ((domain.startsWith(".") && isFullyQualifiedDomainName(domain, 1))
+                || isLocalDomain);
+            // END Android-changed: App compat reason
+        }
+        else if (lengthDiff == -1) {
+            // if domain is actually .host
+            return (domain.charAt(0) == '.' &&
+                        host.equalsIgnoreCase(domain.substring(1)));
+        }
+
+        return false;
+    }
+
+    // BEGIN Android-added: App compat reason
+    private static boolean isFullyQualifiedDomainName(String s, int firstCharacter) {
+        int dotPosition = s.indexOf('.', firstCharacter + 1);
+        return dotPosition != -1 && dotPosition < s.length() - 1;
+    }
+    // END Android-added: App compat reason
+
+    /**
+     * Constructs a cookie header string representation of this cookie,
+     * which is in the format defined by corresponding cookie specification,
+     * but without the leading "Cookie:" token.
+     *
+     * @return  a string form of the cookie. The string has the defined format
+     */
+    @Override
+    public String toString() {
+        if (getVersion() > 0) {
+            return toRFC2965HeaderString();
+        } else {
+            return toNetscapeHeaderString();
+        }
+    }
+
+    /**
+     * Test the equality of two HTTP cookies.
+     *
+     * <p> The result is {@code true} only if two cookies come from same domain
+     * (case-insensitive), have same name (case-insensitive), and have same path
+     * (case-sensitive).
+     *
+     * @return  {@code true} if two HTTP cookies equal to each other;
+     *          otherwise, {@code false}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this)
+            return true;
+        if (!(obj instanceof HttpCookie))
+            return false;
+        HttpCookie other = (HttpCookie)obj;
+
+        // One http cookie equals to another cookie (RFC 2965 sec. 3.3.3) if:
+        //   1. they come from same domain (case-insensitive),
+        //   2. have same name (case-insensitive),
+        //   3. and have same path (case-sensitive).
+        return equalsIgnoreCase(getName(), other.getName()) &&
+               equalsIgnoreCase(getDomain(), other.getDomain()) &&
+               Objects.equals(getPath(), other.getPath());
+    }
+
+    /**
+     * Returns the hash code of this HTTP cookie. The result is the sum of
+     * hash code value of three significant components of this cookie: name,
+     * domain, and path. That is, the hash code is the value of the expression:
+     * <blockquote>
+     * getName().toLowerCase().hashCode()<br>
+     * + getDomain().toLowerCase().hashCode()<br>
+     * + getPath().hashCode()
+     * </blockquote>
+     *
+     * @return  this HTTP cookie's hash code
+     */
+    @Override
+    public int hashCode() {
+        int h1 = name.toLowerCase().hashCode();
+        int h2 = (domain!=null) ? domain.toLowerCase().hashCode() : 0;
+        int h3 = (path!=null) ? path.hashCode() : 0;
+
+        return h1 + h2 + h3;
+    }
+
+    /**
+     * Create and return a copy of this object.
+     *
+     * @return  a clone of this HTTP cookie
+     */
+    @Override
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    // ---------------- Private operations --------------
+
+    // Note -- disabled for now to allow full Netscape compatibility
+    // from RFC 2068, token special case characters
+    //
+    // private static final String tspecials = "()<>@,;:\\\"/[]?={} \t";
+    // Android-changed: App compat reason. Disallow "=\t" as token
+    // private static final String tspecials = ",; ";  // deliberately includes space
+    private static final String tspecials = ",;= \t";
+
+    /*
+     * Tests a string and returns true if the string counts as a token.
+     *
+     * @param  value
+     *         the {@code String} to be tested
+     *
+     * @return  {@code true} if the {@code String} is a token;
+     *          {@code false} if it is not
+     */
+    private static boolean isToken(String value) {
+        // Android-added: Reserved name can't be a token
+        if (RESERVED_NAMES.contains(value.toLowerCase(Locale.US))) {
+            return false;
+        }
+
+        int len = value.length();
+
+        for (int i = 0; i < len; i++) {
+            char c = value.charAt(i);
+
+            if (c < 0x20 || c >= 0x7f || tspecials.indexOf(c) != -1)
+                return false;
+        }
+        return true;
+    }
+
+    /*
+     * Parse header string to cookie object.
+     *
+     * @param  header
+     *         header string; should contain only one NAME=VALUE pair
+     *
+     * @return  an HttpCookie being extracted
+     *
+     * @throws  IllegalArgumentException
+     *          if header string violates the cookie specification
+     */
+    private static HttpCookie parseInternal(String header,
+                                            boolean retainHeader)
+    {
+        HttpCookie cookie = null;
+        String namevaluePair = null;
+
+        StringTokenizer tokenizer = new StringTokenizer(header, ";");
+
+        // there should always have at least on name-value pair;
+        // it's cookie's name
+        try {
+            namevaluePair = tokenizer.nextToken();
+            int index = namevaluePair.indexOf('=');
+            if (index != -1) {
+                String name = namevaluePair.substring(0, index).trim();
+                String value = namevaluePair.substring(index + 1).trim();
+                if (retainHeader)
+                    cookie = new HttpCookie(name,
+                                            stripOffSurroundingQuote(value),
+                                            header);
+                else
+                    cookie = new HttpCookie(name,
+                                            stripOffSurroundingQuote(value));
+            } else {
+                // no "=" in name-value pair; it's an error
+                throw new IllegalArgumentException("Invalid cookie name-value pair");
+            }
+        } catch (NoSuchElementException ignored) {
+            throw new IllegalArgumentException("Empty cookie header string");
+        }
+
+        // remaining name-value pairs are cookie's attributes
+        while (tokenizer.hasMoreTokens()) {
+            namevaluePair = tokenizer.nextToken();
+            int index = namevaluePair.indexOf('=');
+            String name, value;
+            if (index != -1) {
+                name = namevaluePair.substring(0, index).trim();
+                value = namevaluePair.substring(index + 1).trim();
+            } else {
+                name = namevaluePair.trim();
+                value = null;
+            }
+
+            // assign attribute to cookie
+            assignAttribute(cookie, name, value);
+        }
+
+        return cookie;
+    }
+
+    /*
+     * assign cookie attribute value to attribute name;
+     * use a map to simulate method dispatch
+     */
+    static interface CookieAttributeAssignor {
+            public void assign(HttpCookie cookie,
+                               String attrName,
+                               String attrValue);
+    }
+    static final java.util.Map<String, CookieAttributeAssignor> assignors =
+            new java.util.HashMap<>();
+    static {
+        assignors.put("comment", new CookieAttributeAssignor() {
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    if (cookie.getComment() == null)
+                        cookie.setComment(attrValue);
+                }
+            });
+        assignors.put("commenturl", new CookieAttributeAssignor() {
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    if (cookie.getCommentURL() == null)
+                        cookie.setCommentURL(attrValue);
+                }
+            });
+        assignors.put("discard", new CookieAttributeAssignor() {
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    cookie.setDiscard(true);
+                }
+            });
+        assignors.put("domain", new CookieAttributeAssignor(){
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    if (cookie.getDomain() == null)
+                        cookie.setDomain(attrValue);
+                }
+            });
+        assignors.put("max-age", new CookieAttributeAssignor(){
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    try {
+                        long maxage = Long.parseLong(attrValue);
+                        if (cookie.getMaxAge() == MAX_AGE_UNSPECIFIED)
+                            cookie.setMaxAge(maxage);
+                    } catch (NumberFormatException ignored) {
+                        throw new IllegalArgumentException(
+                                "Illegal cookie max-age attribute");
+                    }
+                }
+            });
+        assignors.put("path", new CookieAttributeAssignor(){
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    if (cookie.getPath() == null)
+                        cookie.setPath(attrValue);
+                }
+            });
+        assignors.put("port", new CookieAttributeAssignor(){
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    if (cookie.getPortlist() == null)
+                        cookie.setPortlist(attrValue == null ? "" : attrValue);
+                }
+            });
+        assignors.put("secure", new CookieAttributeAssignor(){
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    cookie.setSecure(true);
+                }
+            });
+        assignors.put("httponly", new CookieAttributeAssignor(){
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    cookie.setHttpOnly(true);
+                }
+            });
+        assignors.put("version", new CookieAttributeAssignor(){
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    try {
+                        int version = Integer.parseInt(attrValue);
+                        cookie.setVersion(version);
+                    } catch (NumberFormatException ignored) {
+                        // Just ignore bogus version, it will default to 0 or 1
+                    }
+                }
+            });
+        assignors.put("expires", new CookieAttributeAssignor(){ // Netscape only
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    if (cookie.getMaxAge() == MAX_AGE_UNSPECIFIED) {
+                        // BEGIN Android-changed: Use HttpDate for date parsing.
+                        // it accepts broader set of date formats.
+                        // cookie.setMaxAge(cookie.expiryDate2DeltaSeconds(attrValue));
+                        // Android-changed: Altered max age calculation to avoid setting
+                        // it to MAX_AGE_UNSPECIFIED (-1) if "expires" is one second in past.
+                        Date date = HttpDate.parse(attrValue);
+                        long maxAgeInSeconds = 0;
+                        if (date != null) {
+                            maxAgeInSeconds = (date.getTime() - cookie.whenCreated) / 1000;
+                            // Avoid MAX_AGE_UNSPECIFIED
+                            if (maxAgeInSeconds == MAX_AGE_UNSPECIFIED) {
+                                maxAgeInSeconds = 0;
+                            }
+                        }
+                        cookie.setMaxAge(maxAgeInSeconds);
+                        // END Android-changed: Use HttpDate for date parsing.
+                    }
+                }
+            });
+    }
+    private static void assignAttribute(HttpCookie cookie,
+                                        String attrName,
+                                        String attrValue)
+    {
+        // strip off the surrounding "-sign if there's any
+        attrValue = stripOffSurroundingQuote(attrValue);
+
+        CookieAttributeAssignor assignor = assignors.get(attrName.toLowerCase());
+        if (assignor != null) {
+            assignor.assign(cookie, attrName, attrValue);
+        } else {
+            // Ignore the attribute as per RFC 2965
+        }
+    }
+
+    // BEGIN Android-removed: Android doesn't use JavaNetHttpCookieAccess
+    /*
+    static {
+        sun.misc.SharedSecrets.setJavaNetHttpCookieAccess(
+            new sun.misc.JavaNetHttpCookieAccess() {
+                public List<HttpCookie> parse(String header) {
+                    return HttpCookie.parse(header, true);
+                }
+
+                public String header(HttpCookie cookie) {
+                    return cookie.header;
+                }
+            }
+        );
+    }
+    */
+    // END Android-removed: Android doesn't use JavaNetHttpCookieAccess
+
+    /*
+     * Returns the original header this cookie was consructed from, if it was
+     * constructed by parsing a header, otherwise null.
+     */
+    private String header() {
+        return header;
+    }
+
+    /*
+     * Constructs a string representation of this cookie. The string format is
+     * as Netscape spec, but without leading "Cookie:" token.
+     */
+    private String toNetscapeHeaderString() {
+        return getName() + "=" + getValue();
+    }
+
+    /*
+     * Constructs a string representation of this cookie. The string format is
+     * as RFC 2965/2109, but without leading "Cookie:" token.
+     */
+    private String toRFC2965HeaderString() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(getName()).append("=\"").append(getValue()).append('"');
+        if (getPath() != null)
+            sb.append(";$Path=\"").append(getPath()).append('"');
+        if (getDomain() != null)
+            sb.append(";$Domain=\"").append(getDomain()).append('"');
+        if (getPortlist() != null)
+            sb.append(";$Port=\"").append(getPortlist()).append('"');
+
+        return sb.toString();
+    }
+
+    static final TimeZone GMT = TimeZone.getTimeZone("GMT");
+
+    // BEGIN Android-removed: not used.
+    /*
+     * @param  dateString
+     *         a date string in one of the formats defined in Netscape cookie spec
+     *
+     * @return  delta seconds between this cookie's creation time and the time
+     *          specified by dateString
+     *
+    private long expiryDate2DeltaSeconds(String dateString) {
+        Calendar cal = new GregorianCalendar(GMT);
+        for (int i = 0; i < COOKIE_DATE_FORMATS.length; i++) {
+            SimpleDateFormat df = new SimpleDateFormat(COOKIE_DATE_FORMATS[i],
+                                                       Locale.US);
+            cal.set(1970, 0, 1, 0, 0, 0);
+            df.setTimeZone(GMT);
+            df.setLenient(false);
+            df.set2DigitYearStart(cal.getTime());
+            try {
+                cal.setTime(df.parse(dateString));
+                if (!COOKIE_DATE_FORMATS[i].contains("yyyy")) {
+                    // 2-digit years following the standard set
+                    // out it rfc 6265
+                    int year = cal.get(Calendar.YEAR);
+                    year %= 100;
+                    if (year < 70) {
+                        year += 2000;
+                    } else {
+                        year += 1900;
+                    }
+                    cal.set(Calendar.YEAR, year);
+                }
+                return (cal.getTimeInMillis() - whenCreated) / 1000;
+            } catch (Exception e) {
+                // Ignore, try the next date format
+            }
+        }
+        return 0;
+    }
+    */
+    // END Android-removed: not used.
+
+    /*
+     * try to guess the cookie version through set-cookie header string
+     */
+    private static int guessCookieVersion(String header) {
+        int version = 0;
+
+        header = header.toLowerCase();
+        if (header.indexOf("expires=") != -1) {
+            // only netscape cookie using 'expires'
+            version = 0;
+        } else if (header.indexOf("version=") != -1) {
+            // version is mandatory for rfc 2965/2109 cookie
+            version = 1;
+        } else if (header.indexOf("max-age") != -1) {
+            // rfc 2965/2109 use 'max-age'
+            version = 1;
+        } else if (startsWithIgnoreCase(header, SET_COOKIE2)) {
+            // only rfc 2965 cookie starts with 'set-cookie2'
+            version = 1;
+        }
+
+        return version;
+    }
+
+    private static String stripOffSurroundingQuote(String str) {
+        if (str != null && str.length() > 2 &&
+            str.charAt(0) == '"' && str.charAt(str.length() - 1) == '"') {
+            return str.substring(1, str.length() - 1);
+        }
+        if (str != null && str.length() > 2 &&
+            str.charAt(0) == '\'' && str.charAt(str.length() - 1) == '\'') {
+            return str.substring(1, str.length() - 1);
+        }
+        return str;
+    }
+
+    private static boolean equalsIgnoreCase(String s, String t) {
+        if (s == t) return true;
+        if ((s != null) && (t != null)) {
+            return s.equalsIgnoreCase(t);
+        }
+        return false;
+    }
+
+    private static boolean startsWithIgnoreCase(String s, String start) {
+        if (s == null || start == null) return false;
+
+        if (s.length() >= start.length() &&
+                start.equalsIgnoreCase(s.substring(0, start.length()))) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /*
+     * Split cookie header string according to rfc 2965:
+     *   1) split where it is a comma;
+     *   2) but not the comma surrounding by double-quotes, which is the comma
+     *      inside port list or embeded URIs.
+     *
+     * @param  header
+     *         the cookie header string to split
+     *
+     * @return  list of strings; never null
+     */
+    private static List<String> splitMultiCookies(String header) {
+        List<String> cookies = new java.util.ArrayList<String>();
+        int quoteCount = 0;
+        int p, q;
+
+        for (p = 0, q = 0; p < header.length(); p++) {
+            char c = header.charAt(p);
+            if (c == '"') quoteCount++;
+            if (c == ',' && (quoteCount % 2 == 0)) {
+                // it is comma and not surrounding by double-quotes
+                cookies.add(header.substring(q, p));
+                q = p + 1;
+            }
+        }
+
+        cookies.add(header.substring(q));
+
+        return cookies;
+    }
+}
diff --git a/java/net/HttpRetryException.java b/java/net/HttpRetryException.java
new file mode 100644
index 0000000..d498a65
--- /dev/null
+++ b/java/net/HttpRetryException.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * Thrown to indicate that a HTTP request needs to be retried
+ * but cannot be retried automatically, due to streaming mode
+ * being enabled.
+ *
+ * @author  Michael McMahon
+ * @since   1.5
+ */
+public
+class HttpRetryException extends IOException {
+    private static final long serialVersionUID = -9186022286469111381L;
+
+    private int responseCode;
+    private String location;
+
+    /**
+     * Constructs a new {@code HttpRetryException} from the
+     * specified response code and exception detail message
+     *
+     * @param   detail   the detail message.
+     * @param   code   the HTTP response code from server.
+     */
+    public HttpRetryException(String detail, int code) {
+        super(detail);
+        responseCode = code;
+    }
+
+    /**
+     * Constructs a new {@code HttpRetryException} with detail message
+     * responseCode and the contents of the Location response header field.
+     *
+     * @param   detail   the detail message.
+     * @param   code   the HTTP response code from server.
+     * @param   location   the URL to be redirected to
+     */
+    public HttpRetryException(String detail, int code, String location) {
+        super (detail);
+        responseCode = code;
+        this.location = location;
+    }
+
+    /**
+     * Returns the http response code
+     *
+     * @return  The http response code.
+     */
+    public int responseCode() {
+        return responseCode;
+    }
+
+    /**
+     * Returns a string explaining why the http request could
+     * not be retried.
+     *
+     * @return  The reason string
+     */
+    public String getReason() {
+        return super.getMessage();
+    }
+
+    /**
+     * Returns the value of the Location header field if the
+     * error resulted from redirection.
+     *
+     * @return The location string
+     */
+    public String getLocation() {
+        return location;
+    }
+}
diff --git a/java/net/HttpURLConnection.java b/java/net/HttpURLConnection.java
new file mode 100644
index 0000000..b72168b
--- /dev/null
+++ b/java/net/HttpURLConnection.java
@@ -0,0 +1,1023 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.security.Permission;
+import java.util.Date;
+
+// Android-changed: top-level documentation substantially changed/rewritten.
+/**
+ * A URLConnection with support for HTTP-specific features. See
+ * <A HREF="http://www.w3.org/pub/WWW/Protocols/"> the spec </A> for
+ * details.
+ * <p>
+ *
+ * <p>Uses of this class follow a pattern:
+ * <ol>
+ *   <li>Obtain a new {@code HttpURLConnection} by calling {@link
+ *       URL#openConnection() URL.openConnection()} and casting the result to
+ *       {@code HttpURLConnection}.
+ *   <li>Prepare the request. The primary property of a request is its URI.
+ *       Request headers may also include metadata such as credentials, preferred
+ *       content types, and session cookies.
+ *   <li>Optionally upload a request body. Instances must be configured with
+ *       {@link #setDoOutput(boolean) setDoOutput(true)} if they include a
+ *       request body. Transmit data by writing to the stream returned by {@link
+ *       #getOutputStream()}.
+ *   <li>Read the response. Response headers typically include metadata such as
+ *       the response body's content type and length, modified dates and session
+ *       cookies. The response body may be read from the stream returned by {@link
+ *       #getInputStream()}. If the response has no body, that method returns an
+ *       empty stream.
+ *   <li>Disconnect. Once the response body has been read, the {@code
+ *       HttpURLConnection} should be closed by calling {@link #disconnect()}.
+ *       Disconnecting releases the resources held by a connection so they may
+ *       be closed or reused.
+ * </ol>
+ *
+ * <p>For example, to retrieve the webpage at {@code http://www.android.com/}:
+ * <pre>   {@code
+ *   URL url = new URL("http://www.android.com/");
+ *   HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
+ *   try {
+ *     InputStream in = new BufferedInputStream(urlConnection.getInputStream());
+ *     readStream(in);
+ *   } finally {
+ *     urlConnection.disconnect();
+ *   }
+ * }</pre>
+ *
+ * <h3>Secure Communication with HTTPS</h3>
+ * Calling {@link URL#openConnection()} on a URL with the "https"
+ * scheme will return an {@code HttpsURLConnection}, which allows for
+ * overriding the default {@link javax.net.ssl.HostnameVerifier
+ * HostnameVerifier} and {@link javax.net.ssl.SSLSocketFactory
+ * SSLSocketFactory}. An application-supplied {@code SSLSocketFactory}
+ * created from an {@link javax.net.ssl.SSLContext SSLContext} can
+ * provide a custom {@link javax.net.ssl.X509TrustManager
+ * X509TrustManager} for verifying certificate chains and a custom
+ * {@link javax.net.ssl.X509KeyManager X509KeyManager} for supplying
+ * client certificates. See {@link javax.net.ssl.HttpsURLConnection
+ * HttpsURLConnection} for more details.
+ *
+ * <h3>Response Handling</h3>
+ * {@code HttpURLConnection} will follow up to five HTTP redirects. It will
+ * follow redirects from one origin server to another. This implementation
+ * doesn't follow redirects from HTTPS to HTTP or vice versa.
+ *
+ * <p>If the HTTP response indicates that an error occurred, {@link
+ * #getInputStream()} will throw an {@link IOException}. Use {@link
+ * #getErrorStream()} to read the error response. The headers can be read in
+ * the normal way using {@link #getHeaderFields()},
+ *
+ * <h3>Posting Content</h3>
+ * To upload data to a web server, configure the connection for output using
+ * {@link #setDoOutput(boolean) setDoOutput(true)}.
+ *
+ * <p>For best performance, you should call either {@link
+ * #setFixedLengthStreamingMode(int)} when the body length is known in advance,
+ * or {@link #setChunkedStreamingMode(int)} when it is not. Otherwise {@code
+ * HttpURLConnection} will be forced to buffer the complete request body in
+ * memory before it is transmitted, wasting (and possibly exhausting) heap and
+ * increasing latency.
+ *
+ * <p>For example, to perform an upload: <pre>   {@code
+ *   HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
+ *   try {
+ *     urlConnection.setDoOutput(true);
+ *     urlConnection.setChunkedStreamingMode(0);
+ *
+ *     OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
+ *     writeStream(out);
+ *
+ *     InputStream in = new BufferedInputStream(urlConnection.getInputStream());
+ *     readStream(in);
+ *   } finally {
+ *     urlConnection.disconnect();
+ *   }
+ * }</pre>
+ *
+ * <h3>Performance</h3>
+ * The input and output streams returned by this class are <strong>not
+ * buffered</strong>. Most callers should wrap the returned streams with {@link
+ * java.io.BufferedInputStream BufferedInputStream} or {@link
+ * java.io.BufferedOutputStream BufferedOutputStream}. Callers that do only bulk
+ * reads or writes may omit buffering.
+ *
+ * <p>When transferring large amounts of data to or from a server, use streams
+ * to limit how much data is in memory at once. Unless you need the entire
+ * body to be in memory at once, process it as a stream (rather than storing
+ * the complete body as a single byte array or string).
+ *
+ * <p>To reduce latency, this class may reuse the same underlying {@code Socket}
+ * for multiple request/response pairs. As a result, HTTP connections may be
+ * held open longer than necessary. Calls to {@link #disconnect()} may return
+ * the socket to a pool of connected sockets.
+ *
+ * <p>By default, this implementation of {@code HttpURLConnection} requests that
+ * servers use gzip compression and it automatically decompresses the data for
+ * callers of {@link #getInputStream()}. The Content-Encoding and Content-Length
+ * response headers are cleared in this case. Gzip compression can be disabled by
+ * setting the acceptable encodings in the request header: <pre>   {@code
+ *   urlConnection.setRequestProperty("Accept-Encoding", "identity");
+ * }</pre>
+ *
+ * <p>Setting the Accept-Encoding request header explicitly disables automatic
+ * decompression and leaves the response headers intact; callers must handle
+ * decompression as needed, according to the Content-Encoding header of the
+ * response.
+ *
+ * <p>{@link #getContentLength()} returns the number of bytes transmitted and
+ * cannot be used to predict how many bytes can be read from
+ * {@link #getInputStream()} for compressed streams. Instead, read that stream
+ * until it is exhausted, i.e. when {@link InputStream#read} returns -1.
+ *
+ * <h3>Handling Network Sign-On</h3>
+ * Some Wi-Fi networks block Internet access until the user clicks through a
+ * sign-on page. Such sign-on pages are typically presented by using HTTP
+ * redirects. You can use {@link #getURL()} to test if your connection has been
+ * unexpectedly redirected. This check is not valid until <strong>after</strong>
+ * the response headers have been received, which you can trigger by calling
+ * {@link #getHeaderFields()} or {@link #getInputStream()}. For example, to
+ * check that a response was not redirected to an unexpected host:
+ * <pre>   {@code
+ *   HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
+ *   try {
+ *     InputStream in = new BufferedInputStream(urlConnection.getInputStream());
+ *     if (!url.getHost().equals(urlConnection.getURL().getHost())) {
+ *       // we were redirected! Kick the user out to the browser to sign on?
+ *     }
+ *     ...
+ *   } finally {
+ *     urlConnection.disconnect();
+ *   }
+ * }</pre>
+ *
+ * <h3>HTTP Authentication</h3>
+ * {@code HttpURLConnection} supports <a
+ * href="http://www.ietf.org/rfc/rfc2617">HTTP basic authentication</a>. Use
+ * {@link Authenticator} to set the VM-wide authentication handler:
+ * <pre>   {@code
+ *   Authenticator.setDefault(new Authenticator() {
+ *     protected PasswordAuthentication getPasswordAuthentication() {
+ *       return new PasswordAuthentication(username, password.toCharArray());
+ *     }
+ *   });
+ * }</pre>
+ * Unless paired with HTTPS, this is <strong>not</strong> a secure mechanism for
+ * user authentication. In particular, the username, password, request and
+ * response are all transmitted over the network without encryption.
+ *
+ * <h3>Sessions with Cookies</h3>
+ * To establish and maintain a potentially long-lived session between client
+ * and server, {@code HttpURLConnection} includes an extensible cookie manager.
+ * Enable VM-wide cookie management using {@link CookieHandler} and {@link
+ * CookieManager}: <pre>   {@code
+ *   CookieManager cookieManager = new CookieManager();
+ *   CookieHandler.setDefault(cookieManager);
+ * }</pre>
+ * By default, {@code CookieManager} accepts cookies from the <a
+ * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec1.html">origin
+ * server</a> only. Two other policies are included: {@link
+ * CookiePolicy#ACCEPT_ALL} and {@link CookiePolicy#ACCEPT_NONE}. Implement
+ * {@link CookiePolicy} to define a custom policy.
+ *
+ * <p>The default {@code CookieManager} keeps all accepted cookies in memory. It
+ * will forget these cookies when the VM exits. Implement {@link CookieStore} to
+ * define a custom cookie store.
+ *
+ * <p>In addition to the cookies set by HTTP responses, you may set cookies
+ * programmatically. To be included in HTTP request headers, cookies must have
+ * the domain and path properties set.
+ *
+ * <p>By default, new instances of {@code HttpCookie} work only with servers
+ * that support <a href="http://www.ietf.org/rfc/rfc2965.txt">RFC 2965</a>
+ * cookies. Many web servers support only the older specification, <a
+ * href="http://www.ietf.org/rfc/rfc2109.txt">RFC 2109</a>. For compatibility
+ * with the most web servers, set the cookie version to 0.
+ *
+ * <p>For example, to receive {@code www.twitter.com} in French: <pre>   {@code
+ *   HttpCookie cookie = new HttpCookie("lang", "fr");
+ *   cookie.setDomain("twitter.com");
+ *   cookie.setPath("/");
+ *   cookie.setVersion(0);
+ *   cookieManager.getCookieStore().add(new URI("http://twitter.com/"), cookie);
+ * }</pre>
+ *
+ * <h3>HTTP Methods</h3>
+ * <p>{@code HttpURLConnection} uses the {@code GET} method by default. It will
+ * use {@code POST} if {@link #setDoOutput setDoOutput(true)} has been called.
+ * Other HTTP methods ({@code OPTIONS}, {@code HEAD}, {@code PUT}, {@code
+ * DELETE} and {@code TRACE}) can be used with {@link #setRequestMethod}.
+ *
+ * <h3>Proxies</h3>
+ * By default, this class will connect directly to the <a
+ * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec1.html">origin
+ * server</a>. It can also connect via an {@link Proxy.Type#HTTP HTTP} or {@link
+ * Proxy.Type#SOCKS SOCKS} proxy. To use a proxy, use {@link
+ * URL#openConnection(Proxy) URL.openConnection(Proxy)} when creating the
+ * connection.
+ *
+ * <h3>IPv6 Support</h3>
+ * <p>This class includes transparent support for IPv6. For hosts with both IPv4
+ * and IPv6 addresses, it will attempt to connect to each of a host's addresses
+ * until a connection is established.
+ *
+ * <h3>Response Caching</h3>
+ * Android 4.0 (Ice Cream Sandwich, API level 15) includes a response cache. See
+ * {@code android.net.http.HttpResponseCache} for instructions on enabling HTTP
+ * caching in your application.
+ *
+ * <h3>Avoiding Bugs In Earlier Releases</h3>
+ * Prior to Android 2.2 (Froyo), this class had some frustrating bugs. In
+ * particular, calling {@code close()} on a readable {@code InputStream} could
+ * <a href="http://code.google.com/p/android/issues/detail?id=2939">poison the
+ * connection pool</a>. Work around this by disabling connection pooling:
+ * <pre>   {@code
+ * private void disableConnectionReuseIfNecessary() {
+ *   // Work around pre-Froyo bugs in HTTP connection reuse.
+ *   if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
+ *     System.setProperty("http.keepAlive", "false");
+ *   }
+ * }}</pre>
+ *
+ * <p>Each instance of {@code HttpURLConnection} may be used for one
+ * request/response pair. Instances of this class are not thread safe.
+ *
+ * @see     java.net.HttpURLConnection#disconnect()
+ * @since JDK1.1
+ */
+abstract public class HttpURLConnection extends URLConnection {
+    /* instance variables */
+
+    /**
+     * The HTTP method (GET,POST,PUT,etc.).
+     */
+    protected String method = "GET";
+
+    /**
+     * The chunk-length when using chunked encoding streaming mode for output.
+     * A value of {@code -1} means chunked encoding is disabled for output.
+     * @since 1.5
+     */
+    protected int chunkLength = -1;
+
+    /**
+     * The fixed content-length when using fixed-length streaming mode.
+     * A value of {@code -1} means fixed-length streaming mode is disabled
+     * for output.
+     *
+     * <P> <B>NOTE:</B> {@link #fixedContentLengthLong} is recommended instead
+     * of this field, as it allows larger content lengths to be set.
+     *
+     * @since 1.5
+     */
+    protected int fixedContentLength = -1;
+
+    /**
+     * The fixed content-length when using fixed-length streaming mode.
+     * A value of {@code -1} means fixed-length streaming mode is disabled
+     * for output.
+     *
+     * @since 1.7
+     */
+    protected long fixedContentLengthLong = -1;
+
+    /**
+     * Returns the key for the {@code n}<sup>th</sup> header field.
+     * Some implementations may treat the {@code 0}<sup>th</sup>
+     * header field as special, i.e. as the status line returned by the HTTP
+     * server. In this case, {@link #getHeaderField(int) getHeaderField(0)} returns the status
+     * line, but {@code getHeaderFieldKey(0)} returns null.
+     *
+     * @param   n   an index, where {@code n >=0}.
+     * @return  the key for the {@code n}<sup>th</sup> header field,
+     *          or {@code null} if the key does not exist.
+     */
+    public String getHeaderFieldKey (int n) {
+        return null;
+    }
+
+    /**
+     * This method is used to enable streaming of a HTTP request body
+     * without internal buffering, when the content length is known in
+     * advance.
+     * <p>
+     * An exception will be thrown if the application
+     * attempts to write more data than the indicated
+     * content-length, or if the application closes the OutputStream
+     * before writing the indicated amount.
+     * <p>
+     * When output streaming is enabled, authentication
+     * and redirection cannot be handled automatically.
+     * A HttpRetryException will be thrown when reading
+     * the response if authentication or redirection are required.
+     * This exception can be queried for the details of the error.
+     * <p>
+     * This method must be called before the URLConnection is connected.
+     * <p>
+     * <B>NOTE:</B> {@link #setFixedLengthStreamingMode(long)} is recommended
+     * instead of this method as it allows larger content lengths to be set.
+     *
+     * @param   contentLength The number of bytes which will be written
+     *          to the OutputStream.
+     *
+     * @throws  IllegalStateException if URLConnection is already connected
+     *          or if a different streaming mode is already enabled.
+     *
+     * @throws  IllegalArgumentException if a content length less than
+     *          zero is specified.
+     *
+     * @see     #setChunkedStreamingMode(int)
+     * @since 1.5
+     */
+    public void setFixedLengthStreamingMode (int contentLength) {
+        if (connected) {
+            throw new IllegalStateException ("Already connected");
+        }
+        if (chunkLength != -1) {
+            throw new IllegalStateException ("Chunked encoding streaming mode set");
+        }
+        if (contentLength < 0) {
+            throw new IllegalArgumentException ("invalid content length");
+        }
+        fixedContentLength = contentLength;
+    }
+
+    /**
+     * This method is used to enable streaming of a HTTP request body
+     * without internal buffering, when the content length is known in
+     * advance.
+     *
+     * <P> An exception will be thrown if the application attempts to write
+     * more data than the indicated content-length, or if the application
+     * closes the OutputStream before writing the indicated amount.
+     *
+     * <P> When output streaming is enabled, authentication and redirection
+     * cannot be handled automatically. A {@linkplain HttpRetryException} will
+     * be thrown when reading the response if authentication or redirection
+     * are required. This exception can be queried for the details of the
+     * error.
+     *
+     * <P> This method must be called before the URLConnection is connected.
+     *
+     * <P> The content length set by invoking this method takes precedence
+     * over any value set by {@link #setFixedLengthStreamingMode(int)}.
+     *
+     * @param  contentLength
+     *         The number of bytes which will be written to the OutputStream.
+     *
+     * @throws  IllegalStateException
+     *          if URLConnection is already connected or if a different
+     *          streaming mode is already enabled.
+     *
+     * @throws  IllegalArgumentException
+     *          if a content length less than zero is specified.
+     *
+     * @since 1.7
+     */
+    public void setFixedLengthStreamingMode(long contentLength) {
+        if (connected) {
+            throw new IllegalStateException("Already connected");
+        }
+        if (chunkLength != -1) {
+            throw new IllegalStateException(
+                "Chunked encoding streaming mode set");
+        }
+        if (contentLength < 0) {
+            throw new IllegalArgumentException("invalid content length");
+        }
+        fixedContentLengthLong = contentLength;
+    }
+
+    /* Default chunk size (including chunk header) if not specified;
+     * we want to keep this in sync with the one defined in
+     * sun.net.www.http.ChunkedOutputStream
+     */
+    private static final int DEFAULT_CHUNK_SIZE = 4096;
+
+    /**
+     * This method is used to enable streaming of a HTTP request body
+     * without internal buffering, when the content length is <b>not</b>
+     * known in advance. In this mode, chunked transfer encoding
+     * is used to send the request body. Note, not all HTTP servers
+     * support this mode.
+     * <p>
+     * When output streaming is enabled, authentication
+     * and redirection cannot be handled automatically.
+     * A HttpRetryException will be thrown when reading
+     * the response if authentication or redirection are required.
+     * This exception can be queried for the details of the error.
+     * <p>
+     * This method must be called before the URLConnection is connected.
+     *
+     * @param   chunklen The number of bytes to write in each chunk.
+     *          If chunklen is less than or equal to zero, a default
+     *          value will be used.
+     *
+     * @throws  IllegalStateException if URLConnection is already connected
+     *          or if a different streaming mode is already enabled.
+     *
+     * @see     #setFixedLengthStreamingMode(int)
+     * @since 1.5
+     */
+    public void setChunkedStreamingMode (int chunklen) {
+        if (connected) {
+            throw new IllegalStateException ("Can't set streaming mode: already connected");
+        }
+        if (fixedContentLength != -1 || fixedContentLengthLong != -1) {
+            throw new IllegalStateException ("Fixed length streaming mode set");
+        }
+        chunkLength = chunklen <=0? DEFAULT_CHUNK_SIZE : chunklen;
+    }
+
+    /**
+     * Returns the value for the {@code n}<sup>th</sup> header field.
+     * Some implementations may treat the {@code 0}<sup>th</sup>
+     * header field as special, i.e. as the status line returned by the HTTP
+     * server.
+     * <p>
+     * This method can be used in conjunction with the
+     * {@link #getHeaderFieldKey getHeaderFieldKey} method to iterate through all
+     * the headers in the message.
+     *
+     * @param   n   an index, where {@code n>=0}.
+     * @return  the value of the {@code n}<sup>th</sup> header field,
+     *          or {@code null} if the value does not exist.
+     * @see     java.net.HttpURLConnection#getHeaderFieldKey(int)
+     */
+    public String getHeaderField(int n) {
+        return null;
+    }
+
+    /**
+     * An {@code int} representing the three digit HTTP Status-Code.
+     * <ul>
+     * <li> 1xx: Informational
+     * <li> 2xx: Success
+     * <li> 3xx: Redirection
+     * <li> 4xx: Client Error
+     * <li> 5xx: Server Error
+     * </ul>
+     */
+    protected int responseCode = -1;
+
+    /**
+     * The HTTP response message.
+     */
+    protected String responseMessage = null;
+
+    /* static variables */
+
+    /* do we automatically follow redirects? The default is true. */
+    private static boolean followRedirects = true;
+
+    /**
+     * If {@code true}, the protocol will automatically follow redirects.
+     * If {@code false}, the protocol will not automatically follow
+     * redirects.
+     * <p>
+     * This field is set by the {@code setInstanceFollowRedirects}
+     * method. Its value is returned by the {@code getInstanceFollowRedirects}
+     * method.
+     * <p>
+     * Its default value is based on the value of the static followRedirects
+     * at HttpURLConnection construction time.
+     *
+     * @see     java.net.HttpURLConnection#setInstanceFollowRedirects(boolean)
+     * @see     java.net.HttpURLConnection#getInstanceFollowRedirects()
+     * @see     java.net.HttpURLConnection#setFollowRedirects(boolean)
+     */
+    protected boolean instanceFollowRedirects = followRedirects;
+
+    /* valid HTTP methods */
+    private static final String[] methods = {
+        "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE"
+    };
+
+    /**
+     * Constructor for the HttpURLConnection.
+     * @param u the URL
+     */
+    protected HttpURLConnection (URL u) {
+        super(u);
+    }
+
+    /**
+     * Sets whether HTTP redirects  (requests with response code 3xx) should
+     * be automatically followed by this class.  True by default.  Applets
+     * cannot change this variable.
+     * <p>
+     * If there is a security manager, this method first calls
+     * the security manager's {@code checkSetFactory} method
+     * to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param set a {@code boolean} indicating whether or not
+     * to follow HTTP redirects.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkSetFactory} method doesn't
+     *             allow the operation.
+     * @see        SecurityManager#checkSetFactory
+     * @see #getFollowRedirects()
+     */
+    public static void setFollowRedirects(boolean set) {
+        SecurityManager sec = System.getSecurityManager();
+        if (sec != null) {
+            // seems to be the best check here...
+            sec.checkSetFactory();
+        }
+        followRedirects = set;
+    }
+
+    /**
+     * Returns a {@code boolean} indicating
+     * whether or not HTTP redirects (3xx) should
+     * be automatically followed.
+     *
+     * @return {@code true} if HTTP redirects should
+     * be automatically followed, {@code false} if not.
+     * @see #setFollowRedirects(boolean)
+     */
+    public static boolean getFollowRedirects() {
+        return followRedirects;
+    }
+
+    /**
+     * Sets whether HTTP redirects (requests with response code 3xx) should
+     * be automatically followed by this {@code HttpURLConnection}
+     * instance.
+     * <p>
+     * The default value comes from followRedirects, which defaults to
+     * true.
+     *
+     * @param followRedirects a {@code boolean} indicating
+     * whether or not to follow HTTP redirects.
+     *
+     * @see    java.net.HttpURLConnection#instanceFollowRedirects
+     * @see #getInstanceFollowRedirects
+     * @since 1.3
+     */
+     public void setInstanceFollowRedirects(boolean followRedirects) {
+        instanceFollowRedirects = followRedirects;
+     }
+
+     /**
+     * Returns the value of this {@code HttpURLConnection}'s
+     * {@code instanceFollowRedirects} field.
+     *
+     * @return  the value of this {@code HttpURLConnection}'s
+     *          {@code instanceFollowRedirects} field.
+     * @see     java.net.HttpURLConnection#instanceFollowRedirects
+     * @see #setInstanceFollowRedirects(boolean)
+     * @since 1.3
+     */
+     public boolean getInstanceFollowRedirects() {
+         return instanceFollowRedirects;
+     }
+
+    /**
+     * Set the method for the URL request, one of:
+     * <UL>
+     *  <LI>GET
+     *  <LI>POST
+     *  <LI>HEAD
+     *  <LI>OPTIONS
+     *  <LI>PUT
+     *  <LI>DELETE
+     *  <LI>TRACE
+     * </UL> are legal, subject to protocol restrictions.  The default
+     * method is GET.
+     *
+     * @param method the HTTP method
+     * @exception ProtocolException if the method cannot be reset or if
+     *              the requested method isn't valid for HTTP.
+     * @exception SecurityException if a security manager is set and the
+     *              method is "TRACE", but the "allowHttpTrace"
+     *              NetPermission is not granted.
+     * @see #getRequestMethod()
+     */
+    public void setRequestMethod(String method) throws ProtocolException {
+        if (connected) {
+            throw new ProtocolException("Can't reset method: already connected");
+        }
+        // This restriction will prevent people from using this class to
+        // experiment w/ new HTTP methods using java.  But it should
+        // be placed for security - the request String could be
+        // arbitrarily long.
+
+        for (int i = 0; i < methods.length; i++) {
+            if (methods[i].equals(method)) {
+                if (method.equals("TRACE")) {
+                    SecurityManager s = System.getSecurityManager();
+                    if (s != null) {
+                        s.checkPermission(new NetPermission("allowHttpTrace"));
+                    }
+                }
+                this.method = method;
+                return;
+            }
+        }
+        throw new ProtocolException("Invalid HTTP method: " + method);
+    }
+
+    /**
+     * Get the request method.
+     * @return the HTTP request method
+     * @see #setRequestMethod(java.lang.String)
+     */
+    public String getRequestMethod() {
+        return method;
+    }
+
+    /**
+     * Gets the status code from an HTTP response message.
+     * For example, in the case of the following status lines:
+     * <PRE>
+     * HTTP/1.0 200 OK
+     * HTTP/1.0 401 Unauthorized
+     * </PRE>
+     * It will return 200 and 401 respectively.
+     * Returns -1 if no code can be discerned
+     * from the response (i.e., the response is not valid HTTP).
+     * @throws IOException if an error occurred connecting to the server.
+     * @return the HTTP Status-Code, or -1
+     */
+    public int getResponseCode() throws IOException {
+        /*
+         * We're got the response code already
+         */
+        if (responseCode != -1) {
+            return responseCode;
+        }
+
+        /*
+         * Ensure that we have connected to the server. Record
+         * exception as we need to re-throw it if there isn't
+         * a status line.
+         */
+        Exception exc = null;
+        try {
+            getInputStream();
+        } catch (Exception e) {
+            exc = e;
+        }
+
+        /*
+         * If we can't a status-line then re-throw any exception
+         * that getInputStream threw.
+         */
+        String statusLine = getHeaderField(0);
+        if (statusLine == null) {
+            if (exc != null) {
+                if (exc instanceof RuntimeException)
+                    throw (RuntimeException)exc;
+                else
+                    throw (IOException)exc;
+            }
+            return -1;
+        }
+
+        /*
+         * Examine the status-line - should be formatted as per
+         * section 6.1 of RFC 2616 :-
+         *
+         * Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase
+         *
+         * If status line can't be parsed return -1.
+         */
+        if (statusLine.startsWith("HTTP/1.")) {
+            int codePos = statusLine.indexOf(' ');
+            if (codePos > 0) {
+
+                int phrasePos = statusLine.indexOf(' ', codePos+1);
+                if (phrasePos > 0 && phrasePos < statusLine.length()) {
+                    responseMessage = statusLine.substring(phrasePos+1);
+                }
+
+                // deviation from RFC 2616 - don't reject status line
+                // if SP Reason-Phrase is not included.
+                if (phrasePos < 0)
+                    phrasePos = statusLine.length();
+
+                try {
+                    responseCode = Integer.parseInt
+                            (statusLine.substring(codePos+1, phrasePos));
+                    return responseCode;
+                } catch (NumberFormatException e) { }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Gets the HTTP response message, if any, returned along with the
+     * response code from a server.  From responses like:
+     * <PRE>
+     * HTTP/1.0 200 OK
+     * HTTP/1.0 404 Not Found
+     * </PRE>
+     * Extracts the Strings "OK" and "Not Found" respectively.
+     * Returns null if none could be discerned from the responses
+     * (the result was not valid HTTP).
+     * @throws IOException if an error occurred connecting to the server.
+     * @return the HTTP response message, or {@code null}
+     */
+    public String getResponseMessage() throws IOException {
+        getResponseCode();
+        return responseMessage;
+    }
+
+    @SuppressWarnings("deprecation")
+    public long getHeaderFieldDate(String name, long Default) {
+        String dateString = getHeaderField(name);
+        try {
+            if (dateString.indexOf("GMT") == -1) {
+                dateString = dateString+" GMT";
+            }
+            return Date.parse(dateString);
+        } catch (Exception e) {
+        }
+        return Default;
+    }
+
+
+    /**
+     * Indicates that other requests to the server
+     * are unlikely in the near future. Calling disconnect()
+     * should not imply that this HttpURLConnection
+     * instance can be reused for other requests.
+     */
+    public abstract void disconnect();
+
+    /**
+     * Indicates if the connection is going through a proxy.
+     * @return a boolean indicating if the connection is
+     * using a proxy.
+     */
+    public abstract boolean usingProxy();
+
+    /**
+     * Returns a {@link SocketPermission} object representing the
+     * permission necessary to connect to the destination host and port.
+     *
+     * @exception IOException if an error occurs while computing
+     *            the permission.
+     *
+     * @return a {@code SocketPermission} object representing the
+     *         permission necessary to connect to the destination
+     *         host and port.
+     */
+    public Permission getPermission() throws IOException {
+        int port = url.getPort();
+        port = port < 0 ? 80 : port;
+        String host = url.getHost() + ":" + port;
+        Permission permission = new SocketPermission(host, "connect");
+        return permission;
+    }
+
+   /**
+    * Returns the error stream if the connection failed
+    * but the server sent useful data nonetheless. The
+    * typical example is when an HTTP server responds
+    * with a 404, which will cause a FileNotFoundException
+    * to be thrown in connect, but the server sent an HTML
+    * help page with suggestions as to what to do.
+    *
+    * <p>This method will not cause a connection to be initiated.  If
+    * the connection was not connected, or if the server did not have
+    * an error while connecting or if the server had an error but
+    * no error data was sent, this method will return null. This is
+    * the default.
+    *
+    * @return an error stream if any, null if there have been no
+    * errors, the connection is not connected or the server sent no
+    * useful data.
+    */
+    public InputStream getErrorStream() {
+        return null;
+    }
+
+    /**
+     * The response codes for HTTP, as of version 1.1.
+     */
+
+    // REMIND: do we want all these??
+    // Others not here that we do want??
+
+    /* 2XX: generally "OK" */
+
+    /**
+     * HTTP Status-Code 200: OK.
+     */
+    public static final int HTTP_OK = 200;
+
+    /**
+     * HTTP Status-Code 201: Created.
+     */
+    public static final int HTTP_CREATED = 201;
+
+    /**
+     * HTTP Status-Code 202: Accepted.
+     */
+    public static final int HTTP_ACCEPTED = 202;
+
+    /**
+     * HTTP Status-Code 203: Non-Authoritative Information.
+     */
+    public static final int HTTP_NOT_AUTHORITATIVE = 203;
+
+    /**
+     * HTTP Status-Code 204: No Content.
+     */
+    public static final int HTTP_NO_CONTENT = 204;
+
+    /**
+     * HTTP Status-Code 205: Reset Content.
+     */
+    public static final int HTTP_RESET = 205;
+
+    /**
+     * HTTP Status-Code 206: Partial Content.
+     */
+    public static final int HTTP_PARTIAL = 206;
+
+    /* 3XX: relocation/redirect */
+
+    /**
+     * HTTP Status-Code 300: Multiple Choices.
+     */
+    public static final int HTTP_MULT_CHOICE = 300;
+
+    /**
+     * HTTP Status-Code 301: Moved Permanently.
+     */
+    public static final int HTTP_MOVED_PERM = 301;
+
+    /**
+     * HTTP Status-Code 302: Temporary Redirect.
+     */
+    public static final int HTTP_MOVED_TEMP = 302;
+
+    /**
+     * HTTP Status-Code 303: See Other.
+     */
+    public static final int HTTP_SEE_OTHER = 303;
+
+    /**
+     * HTTP Status-Code 304: Not Modified.
+     */
+    public static final int HTTP_NOT_MODIFIED = 304;
+
+    /**
+     * HTTP Status-Code 305: Use Proxy.
+     */
+    public static final int HTTP_USE_PROXY = 305;
+
+    /* 4XX: client error */
+
+    /**
+     * HTTP Status-Code 400: Bad Request.
+     */
+    public static final int HTTP_BAD_REQUEST = 400;
+
+    /**
+     * HTTP Status-Code 401: Unauthorized.
+     */
+    public static final int HTTP_UNAUTHORIZED = 401;
+
+    /**
+     * HTTP Status-Code 402: Payment Required.
+     */
+    public static final int HTTP_PAYMENT_REQUIRED = 402;
+
+    /**
+     * HTTP Status-Code 403: Forbidden.
+     */
+    public static final int HTTP_FORBIDDEN = 403;
+
+    /**
+     * HTTP Status-Code 404: Not Found.
+     */
+    public static final int HTTP_NOT_FOUND = 404;
+
+    /**
+     * HTTP Status-Code 405: Method Not Allowed.
+     */
+    public static final int HTTP_BAD_METHOD = 405;
+
+    /**
+     * HTTP Status-Code 406: Not Acceptable.
+     */
+    public static final int HTTP_NOT_ACCEPTABLE = 406;
+
+    /**
+     * HTTP Status-Code 407: Proxy Authentication Required.
+     */
+    public static final int HTTP_PROXY_AUTH = 407;
+
+    /**
+     * HTTP Status-Code 408: Request Time-Out.
+     */
+    public static final int HTTP_CLIENT_TIMEOUT = 408;
+
+    /**
+     * HTTP Status-Code 409: Conflict.
+     */
+    public static final int HTTP_CONFLICT = 409;
+
+    /**
+     * HTTP Status-Code 410: Gone.
+     */
+    public static final int HTTP_GONE = 410;
+
+    /**
+     * HTTP Status-Code 411: Length Required.
+     */
+    public static final int HTTP_LENGTH_REQUIRED = 411;
+
+    /**
+     * HTTP Status-Code 412: Precondition Failed.
+     */
+    public static final int HTTP_PRECON_FAILED = 412;
+
+    /**
+     * HTTP Status-Code 413: Request Entity Too Large.
+     */
+    public static final int HTTP_ENTITY_TOO_LARGE = 413;
+
+    /**
+     * HTTP Status-Code 414: Request-URI Too Large.
+     */
+    public static final int HTTP_REQ_TOO_LONG = 414;
+
+    /**
+     * HTTP Status-Code 415: Unsupported Media Type.
+     */
+    public static final int HTTP_UNSUPPORTED_TYPE = 415;
+
+    /* 5XX: server error */
+
+    /**
+     * HTTP Status-Code 500: Internal Server Error.
+     * @deprecated   it is misplaced and shouldn't have existed.
+     */
+    @Deprecated
+    public static final int HTTP_SERVER_ERROR = 500;
+
+    /**
+     * HTTP Status-Code 500: Internal Server Error.
+     */
+    public static final int HTTP_INTERNAL_ERROR = 500;
+
+    /**
+     * HTTP Status-Code 501: Not Implemented.
+     */
+    public static final int HTTP_NOT_IMPLEMENTED = 501;
+
+    /**
+     * HTTP Status-Code 502: Bad Gateway.
+     */
+    public static final int HTTP_BAD_GATEWAY = 502;
+
+    /**
+     * HTTP Status-Code 503: Service Unavailable.
+     */
+    public static final int HTTP_UNAVAILABLE = 503;
+
+    /**
+     * HTTP Status-Code 504: Gateway Timeout.
+     */
+    public static final int HTTP_GATEWAY_TIMEOUT = 504;
+
+    /**
+     * HTTP Status-Code 505: HTTP Version Not Supported.
+     */
+    public static final int HTTP_VERSION = 505;
+
+}
diff --git a/java/net/IDN.java b/java/net/IDN.java
new file mode 100644
index 0000000..a18c3a8
--- /dev/null
+++ b/java/net/IDN.java
@@ -0,0 +1,498 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+
+import android.icu.text.IDNA;
+
+/**
+ * Provides methods to convert internationalized domain names (IDNs) between
+ * a normal Unicode representation and an ASCII Compatible Encoding (ACE) representation.
+ * Internationalized domain names can use characters from the entire range of
+ * Unicode, while traditional domain names are restricted to ASCII characters.
+ * ACE is an encoding of Unicode strings that uses only ASCII characters and
+ * can be used with software (such as the Domain Name System) that only
+ * understands traditional domain names.
+ *
+ * <p>Internationalized domain names are defined in <a href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a>.
+ * RFC 3490 defines two operations: ToASCII and ToUnicode. These 2 operations employ
+ * <a href="http://www.ietf.org/rfc/rfc3491.txt">Nameprep</a> algorithm, which is a
+ * profile of <a href="http://www.ietf.org/rfc/rfc3454.txt">Stringprep</a>, and
+ * <a href="http://www.ietf.org/rfc/rfc3492.txt">Punycode</a> algorithm to convert
+ * domain name string back and forth.
+ *
+ * <p>The behavior of aforementioned conversion process can be adjusted by various flags:
+ *   <ul>
+ *     <li>If the ALLOW_UNASSIGNED flag is used, the domain name string to be converted
+ *         can contain code points that are unassigned in Unicode 3.2, which is the
+ *         Unicode version on which IDN conversion is based. If the flag is not used,
+ *         the presence of such unassigned code points is treated as an error.
+ *     <li>If the USE_STD3_ASCII_RULES flag is used, ASCII strings are checked against <a href="http://www.ietf.org/rfc/rfc1122.txt">RFC 1122</a> and <a href="http://www.ietf.org/rfc/rfc1123.txt">RFC 1123</a>.
+ *         It is an error if they don't meet the requirements.
+ *   </ul>
+ * These flags can be logically OR'ed together.
+ *
+ * <p>The security consideration is important with respect to internationalization
+ * domain name support. For example, English domain names may be <i>homographed</i>
+ * - maliciously misspelled by substitution of non-Latin letters.
+ * <a href="http://www.unicode.org/reports/tr36/">Unicode Technical Report #36</a>
+ * discusses security issues of IDN support as well as possible solutions.
+ * Applications are responsible for taking adequate security measures when using
+ * international domain names.
+ *
+ * @author Edward Wang
+ * @since 1.6
+ *
+ */
+public final class IDN {
+    /**
+     * Flag to allow processing of unassigned code points
+     */
+    public static final int ALLOW_UNASSIGNED = 0x01;
+
+    /**
+     * Flag to turn on the check against STD-3 ASCII rules
+     */
+    public static final int USE_STD3_ASCII_RULES = 0x02;
+
+
+    /**
+     * Translates a string from Unicode to ASCII Compatible Encoding (ACE),
+     * as defined by the ToASCII operation of <a href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a>.
+     *
+     * <p>ToASCII operation can fail. ToASCII fails if any step of it fails.
+     * If ToASCII operation fails, an IllegalArgumentException will be thrown.
+     * In this case, the input string should not be used in an internationalized domain name.
+     *
+     * <p> A label is an individual part of a domain name. The original ToASCII operation,
+     * as defined in RFC 3490, only operates on a single label. This method can handle
+     * both label and entire domain name, by assuming that labels in a domain name are
+     * always separated by dots. The following characters are recognized as dots:
+     * &#0092;u002E (full stop), &#0092;u3002 (ideographic full stop), &#0092;uFF0E (fullwidth full stop),
+     * and &#0092;uFF61 (halfwidth ideographic full stop). if dots are
+     * used as label separators, this method also changes all of them to &#0092;u002E (full stop)
+     * in output translated string.
+     *
+     * @param input     the string to be processed
+     * @param flag      process flag; can be 0 or any logical OR of possible flags
+     *
+     * @return          the translated {@code String}
+     *
+     * @throws IllegalArgumentException   if the input string doesn't conform to RFC 3490 specification
+     */
+    public static String toASCII(String input, int flag) {
+        // BEGIN Android-changed: Use ICU4J implementation
+        try {
+            return IDNA.convertIDNToASCII(input, flag).toString();
+        } catch (android.icu.text.StringPrepParseException e) {
+            // b/113787610: "." is a valid IDN but is rejected by ICU.
+            // Usage is relatively uncommon, so only check for it if ICU throws.
+            if (".".equals(input)) {
+                return input;
+            }
+            throw new IllegalArgumentException("Invalid input to toASCII: " + input, e);
+        }
+        // END Android-changed: Use ICU4J implementation
+    }
+
+
+    /**
+     * Translates a string from Unicode to ASCII Compatible Encoding (ACE),
+     * as defined by the ToASCII operation of <a href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a>.
+     *
+     * <p> This convenience method works as if by invoking the
+     * two-argument counterpart as follows:
+     * <blockquote>
+     * {@link #toASCII(String, int) toASCII}(input,&nbsp;0);
+     * </blockquote>
+     *
+     * @param input     the string to be processed
+     *
+     * @return          the translated {@code String}
+     *
+     * @throws IllegalArgumentException   if the input string doesn't conform to RFC 3490 specification
+     */
+    public static String toASCII(String input) {
+        return toASCII(input, 0);
+    }
+
+
+    /**
+     * Translates a string from ASCII Compatible Encoding (ACE) to Unicode,
+     * as defined by the ToUnicode operation of <a href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a>.
+     *
+     * <p>ToUnicode never fails. In case of any error, the input string is returned unmodified.
+     *
+     * <p> A label is an individual part of a domain name. The original ToUnicode operation,
+     * as defined in RFC 3490, only operates on a single label. This method can handle
+     * both label and entire domain name, by assuming that labels in a domain name are
+     * always separated by dots. The following characters are recognized as dots:
+     * &#0092;u002E (full stop), &#0092;u3002 (ideographic full stop), &#0092;uFF0E (fullwidth full stop),
+     * and &#0092;uFF61 (halfwidth ideographic full stop).
+     *
+     * @param input     the string to be processed
+     * @param flag      process flag; can be 0 or any logical OR of possible flags
+     *
+     * @return          the translated {@code String}
+     */
+    public static String toUnicode(String input, int flag) {
+        // BEGIN Android-changed: Use ICU4J implementation
+        try {
+            // ICU only translates separators to ASCII for toASCII.
+            // Java expects the translation for toUnicode too.
+            return convertFullStop(IDNA.convertIDNToUnicode(input, flag)).toString();
+        } catch (android.icu.text.StringPrepParseException e) {
+            // The RI documentation explicitly states that if the conversion was unsuccessful
+            // the original string is returned.
+            return input;
+        }
+        // END Android-changed: Use ICU4J implementation
+    }
+
+    // BEGIN Android-added: Use ICU4J implementation
+    private static boolean isLabelSeperator(char c) {
+        return (c == '\u3002' || c == '\uff0e' || c == '\uff61');
+    }
+
+    private static StringBuffer convertFullStop(StringBuffer input) {
+        for (int i = 0; i < input.length(); i++) {
+            if (isLabelSeperator(input.charAt(i))) {
+                input.setCharAt(i, '.');
+            }
+        }
+        return input;
+    }
+    // END Android-added: Use ICU4J implementation
+
+    /**
+     * Translates a string from ASCII Compatible Encoding (ACE) to Unicode,
+     * as defined by the ToUnicode operation of <a href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a>.
+     *
+     * <p> This convenience method works as if by invoking the
+     * two-argument counterpart as follows:
+     * <blockquote>
+     * {@link #toUnicode(String, int) toUnicode}(input,&nbsp;0);
+     * </blockquote>
+     *
+     * @param input     the string to be processed
+     *
+     * @return          the translated {@code String}
+     */
+    public static String toUnicode(String input) {
+        return toUnicode(input, 0);
+    }
+
+
+    /* ---------------- Private members -------------- */
+
+    // Android-removed: Private helper methods, unused because we use ICU.
+    /*
+    // ACE Prefix is "xn--"
+    private static final String ACE_PREFIX = "xn--";
+    private static final int ACE_PREFIX_LENGTH = ACE_PREFIX.length();
+
+    private static final int MAX_LABEL_LENGTH   = 63;
+
+    // single instance of nameprep
+    private static StringPrep namePrep = null;
+
+    static {
+        InputStream stream = null;
+
+        try {
+            final String IDN_PROFILE = "uidna.spp";
+            if (System.getSecurityManager() != null) {
+                stream = AccessController.doPrivileged(new PrivilegedAction<InputStream>() {
+                    public InputStream run() {
+                        return StringPrep.class.getResourceAsStream(IDN_PROFILE);
+                    }
+                });
+            } else {
+                stream = StringPrep.class.getResourceAsStream(IDN_PROFILE);
+            }
+
+            namePrep = new StringPrep(stream);
+            stream.close();
+        } catch (IOException e) {
+            // should never reach here
+            assert false;
+        }
+    }
+    */
+
+    /* ---------------- Private operations -------------- */
+
+
+    //
+    // to suppress the default zero-argument constructor
+    //
+    private IDN() {}
+
+    // Android-removed: Private helper methods, unused because we use ICU.
+    /*
+    //
+    // toASCII operation; should only apply to a single label
+    //
+    private static String toASCIIInternal(String label, int flag)
+    {
+        // step 1
+        // Check if the string contains code points outside the ASCII range 0..0x7c.
+        boolean isASCII  = isAllASCII(label);
+        StringBuffer dest;
+
+        // step 2
+        // perform the nameprep operation; flag ALLOW_UNASSIGNED is used here
+        if (!isASCII) {
+            UCharacterIterator iter = UCharacterIterator.getInstance(label);
+            try {
+                dest = namePrep.prepare(iter, flag);
+            } catch (java.text.ParseException e) {
+                throw new IllegalArgumentException(e);
+            }
+        } else {
+            dest = new StringBuffer(label);
+        }
+
+        // step 8, move forward to check the smallest number of the code points
+        // the length must be inside 1..63
+        if (dest.length() == 0) {
+            throw new IllegalArgumentException(
+                        "Empty label is not a legal name");
+        }
+
+        // step 3
+        // Verify the absence of non-LDH ASCII code points
+        //   0..0x2c, 0x2e..0x2f, 0x3a..0x40, 0x5b..0x60, 0x7b..0x7f
+        // Verify the absence of leading and trailing hyphen
+        boolean useSTD3ASCIIRules = ((flag & USE_STD3_ASCII_RULES) != 0);
+        if (useSTD3ASCIIRules) {
+            for (int i = 0; i < dest.length(); i++) {
+                int c = dest.charAt(i);
+                if (isNonLDHAsciiCodePoint(c)) {
+                    throw new IllegalArgumentException(
+                        "Contains non-LDH ASCII characters");
+                }
+            }
+
+            if (dest.charAt(0) == '-' ||
+                dest.charAt(dest.length() - 1) == '-') {
+
+                throw new IllegalArgumentException(
+                        "Has leading or trailing hyphen");
+            }
+        }
+
+        if (!isASCII) {
+            // step 4
+            // If all code points are inside 0..0x7f, skip to step 8
+            if (!isAllASCII(dest.toString())) {
+                // step 5
+                // verify the sequence does not begin with ACE prefix
+                if(!startsWithACEPrefix(dest)){
+
+                    // step 6
+                    // encode the sequence with punycode
+                    try {
+                        dest = Punycode.encode(dest, null);
+                    } catch (java.text.ParseException e) {
+                        throw new IllegalArgumentException(e);
+                    }
+
+                    dest = toASCIILower(dest);
+
+                    // step 7
+                    // prepend the ACE prefix
+                    dest.insert(0, ACE_PREFIX);
+                } else {
+                    throw new IllegalArgumentException("The input starts with the ACE Prefix");
+                }
+
+            }
+        }
+
+        // step 8
+        // the length must be inside 1..63
+        if (dest.length() > MAX_LABEL_LENGTH) {
+            throw new IllegalArgumentException("The label in the input is too long");
+        }
+
+        return dest.toString();
+    }
+
+    //
+    // toUnicode operation; should only apply to a single label
+    //
+    private static String toUnicodeInternal(String label, int flag) {
+        boolean[] caseFlags = null;
+        StringBuffer dest;
+
+        // step 1
+        // find out if all the codepoints in input are ASCII
+        boolean isASCII = isAllASCII(label);
+
+        if(!isASCII){
+            // step 2
+            // perform the nameprep operation; flag ALLOW_UNASSIGNED is used here
+            try {
+                UCharacterIterator iter = UCharacterIterator.getInstance(label);
+                dest = namePrep.prepare(iter, flag);
+            } catch (Exception e) {
+                // toUnicode never fails; if any step fails, return the input string
+                return label;
+            }
+        } else {
+            dest = new StringBuffer(label);
+        }
+
+        // step 3
+        // verify ACE Prefix
+        if(startsWithACEPrefix(dest)) {
+
+            // step 4
+            // Remove the ACE Prefix
+            String temp = dest.substring(ACE_PREFIX_LENGTH, dest.length());
+
+            try {
+                // step 5
+                // Decode using punycode
+                StringBuffer decodeOut = Punycode.decode(new StringBuffer(temp), null);
+
+                // step 6
+                // Apply toASCII
+                String toASCIIOut = toASCII(decodeOut.toString(), flag);
+
+                // step 7
+                // verify
+                if (toASCIIOut.equalsIgnoreCase(dest.toString())) {
+                    // step 8
+                    // return output of step 5
+                    return decodeOut.toString();
+                }
+            } catch (Exception ignored) {
+                // no-op
+            }
+        }
+
+        // just return the input
+        return label;
+    }
+
+
+    //
+    // LDH stands for "letter/digit/hyphen", with characters restricted to the
+    // 26-letter Latin alphabet <A-Z a-z>, the digits <0-9>, and the hyphen
+    // <->.
+    // Non LDH refers to characters in the ASCII range, but which are not
+    // letters, digits or the hypen.
+    //
+    // non-LDH = 0..0x2C, 0x2E..0x2F, 0x3A..0x40, 0x5B..0x60, 0x7B..0x7F
+    //
+    private static boolean isNonLDHAsciiCodePoint(int ch){
+        return (0x0000 <= ch && ch <= 0x002C) ||
+               (0x002E <= ch && ch <= 0x002F) ||
+               (0x003A <= ch && ch <= 0x0040) ||
+               (0x005B <= ch && ch <= 0x0060) ||
+               (0x007B <= ch && ch <= 0x007F);
+    }
+
+    //
+    // search dots in a string and return the index of that character;
+    // or if there is no dots, return the length of input string
+    // dots might be: \u002E (full stop), \u3002 (ideographic full stop), \uFF0E (fullwidth full stop),
+    // and \uFF61 (halfwidth ideographic full stop).
+    //
+    private static int searchDots(String s, int start) {
+        int i;
+        for (i = start; i < s.length(); i++) {
+            if (isLabelSeparator(s.charAt(i))) {
+                break;
+            }
+        }
+
+        return i;
+    }
+
+    //
+    // to check if a string is a root label, ".".
+    //
+    private static boolean isRootLabel(String s) {
+        return (s.length() == 1 && isLabelSeparator(s.charAt(0)));
+    }
+
+    //
+    // to check if a character is a label separator, i.e. a dot character.
+    //
+    private static boolean isLabelSeparator(char c) {
+        return (c == '.' || c == '\u3002' || c == '\uFF0E' || c == '\uFF61');
+    }
+
+    //
+    // to check if a string only contains US-ASCII code point
+    //
+    private static boolean isAllASCII(String input) {
+        boolean isASCII = true;
+        for (int i = 0; i < input.length(); i++) {
+            int c = input.charAt(i);
+            if (c > 0x7F) {
+                isASCII = false;
+                break;
+            }
+        }
+        return isASCII;
+    }
+
+    //
+    // to check if a string starts with ACE-prefix
+    //
+    private static boolean startsWithACEPrefix(StringBuffer input){
+        boolean startsWithPrefix = true;
+
+        if(input.length() < ACE_PREFIX_LENGTH){
+            return false;
+        }
+        for(int i = 0; i < ACE_PREFIX_LENGTH; i++){
+            if(toASCIILower(input.charAt(i)) != ACE_PREFIX.charAt(i)){
+                startsWithPrefix = false;
+            }
+        }
+        return startsWithPrefix;
+    }
+
+    private static char toASCIILower(char ch){
+        if('A' <= ch && ch <= 'Z'){
+            return (char)(ch + 'a' - 'A');
+        }
+        return ch;
+    }
+
+    private static StringBuffer toASCIILower(StringBuffer input){
+        StringBuffer dest = new StringBuffer();
+        for(int i = 0; i < input.length();i++){
+            dest.append(toASCIILower(input.charAt(i)));
+        }
+        return dest;
+    }
+    */
+}
diff --git a/java/net/InMemoryCookieStore.java b/java/net/InMemoryCookieStore.java
new file mode 100644
index 0000000..5df66c0
--- /dev/null
+++ b/java/net/InMemoryCookieStore.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import dalvik.system.VMRuntime;
+
+import java.util.List;
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.concurrent.locks.ReentrantLock;
+
+// Android-changed: App compat changes and bug fixes
+// b/26456024 Add targetSdkVersion based compatibility for domain matching
+// b/33034917 Support clearing cookies by adding it with "max-age=0"
+// b/25897688 InMemoryCookieStore ignores scheme (http/https) port and path of the cookie
+// Remove cookieJar and domainIndex. Use urlIndex as single Cookie storage
+// Fix InMemoryCookieStore#remove to verify cookie URI before removal
+// Fix InMemoryCookieStore#removeAll to return false if it's empty.
+/**
+ * A simple in-memory java.net.CookieStore implementation
+ *
+ * @author Edward Wang
+ * @since 1.6
+ * @hide Visible for testing only.
+ */
+public class InMemoryCookieStore implements CookieStore {
+    // the in-memory representation of cookies
+    // BEGIN Android-removed: Remove cookieJar and domainIndex
+    /*
+    private List<HttpCookie> cookieJar = null;
+
+    // the cookies are indexed by its domain and associated uri (if present)
+    // CAUTION: when a cookie removed from main data structure (i.e. cookieJar),
+    //          it won't be cleared in domainIndex & uriIndex. Double-check the
+    //          presence of cookie when retrieve one form index store.
+    private Map<String, List<HttpCookie>> domainIndex = null;
+    */
+    // END Android-removed: Remove cookieJar and domainIndex
+    private Map<URI, List<HttpCookie>> uriIndex = null;
+
+    // use ReentrantLock instead of syncronized for scalability
+    private ReentrantLock lock = null;
+
+    // BEGIN Android-changed: Add targetSdkVersion and remove cookieJar and domainIndex
+    private final boolean applyMCompatibility;
+
+    /**
+     * The default ctor
+     */
+    public InMemoryCookieStore() {
+        this(VMRuntime.getRuntime().getTargetSdkVersion());
+    }
+
+    public InMemoryCookieStore(int targetSdkVersion) {
+        uriIndex = new HashMap<>();
+        lock = new ReentrantLock(false);
+        applyMCompatibility = (targetSdkVersion <= 23);
+    }
+    // END Android-changed: Add targetSdkVersion and remove cookieJar and domainIndex
+
+    /**
+     * Add one cookie into cookie store.
+     */
+    public void add(URI uri, HttpCookie cookie) {
+        // pre-condition : argument can't be null
+        if (cookie == null) {
+            throw new NullPointerException("cookie is null");
+        }
+
+        lock.lock();
+        try {
+            // Android-changed: http://b/33034917, android supports clearing cookies
+            // by adding the cookie with max-age: 0.
+            //if (cookie.getMaxAge() != 0) {
+            addIndex(uriIndex, getEffectiveURI(uri), cookie);
+            //}
+        } finally {
+            lock.unlock();
+        }
+    }
+
+
+    /**
+     * Get all cookies, which:
+     *  1) given uri domain-matches with, or, associated with
+     *     given uri when added to the cookie store.
+     *  3) not expired.
+     * See RFC 2965 sec. 3.3.4 for more detail.
+     */
+    public List<HttpCookie> get(URI uri) {
+        // argument can't be null
+        if (uri == null) {
+            throw new NullPointerException("uri is null");
+        }
+
+        List<HttpCookie> cookies = new ArrayList<HttpCookie>();
+        // BEGIN Android-changed: b/25897688 InMemoryCookieStore ignores scheme (http/https)
+        lock.lock();
+        try {
+            // check domainIndex first
+            getInternal1(cookies, uriIndex, uri.getHost());
+            // check uriIndex then
+            getInternal2(cookies, uriIndex, getEffectiveURI(uri));
+        } finally {
+            lock.unlock();
+        }
+        // END Android-changed: b/25897688 InMemoryCookieStore ignores scheme (http/https)
+        return cookies;
+    }
+
+    /**
+     * Get all cookies in cookie store, except those have expired
+     */
+    public List<HttpCookie> getCookies() {
+        // BEGIN Android-changed: Remove cookieJar and domainIndex
+        List<HttpCookie> rt = new ArrayList<HttpCookie>();
+
+        lock.lock();
+        try {
+            for (List<HttpCookie> list : uriIndex.values()) {
+                Iterator<HttpCookie> it = list.iterator();
+                while (it.hasNext()) {
+                    HttpCookie cookie = it.next();
+                    if (cookie.hasExpired()) {
+                        it.remove();
+                    } else if (!rt.contains(cookie)) {
+                        rt.add(cookie);
+                    }
+                }
+            }
+        } finally {
+            rt = Collections.unmodifiableList(rt);
+            lock.unlock();
+        }
+        // END Android-changed: Remove cookieJar and domainIndex
+
+        return rt;
+    }
+
+    /**
+     * Get all URIs, which are associated with at least one cookie
+     * of this cookie store.
+     */
+    public List<URI> getURIs() {
+        // BEGIN Android-changed: App compat. Return URI with no cookies. http://b/65538736
+        /*
+        List<URI> uris = new ArrayList<URI>();
+
+        lock.lock();
+        try {
+            Iterator<URI> it = uriIndex.keySet().iterator();
+            while (it.hasNext()) {
+                URI uri = it.next();
+                List<HttpCookie> cookies = uriIndex.get(uri);
+                if (cookies == null || cookies.size() == 0) {
+                    // no cookies list or an empty list associated with
+                    // this uri entry, delete it
+                    it.remove();
+                }
+            }
+        } finally {
+            uris.addAll(uriIndex.keySet());
+            lock.unlock();
+        }
+
+        return uris;
+         */
+        lock.lock();
+        try {
+            List<URI> result = new ArrayList<URI>(uriIndex.keySet());
+            result.remove(null);
+            return Collections.unmodifiableList(result);
+        } finally {
+            lock.unlock();
+        }
+        // END Android-changed: App compat. Return URI with no cookies. http://b/65538736
+    }
+
+
+    /**
+     * Remove a cookie from store
+     */
+    public boolean remove(URI uri, HttpCookie ck) {
+        // argument can't be null
+        if (ck == null) {
+            throw new NullPointerException("cookie is null");
+        }
+
+        // BEGIN Android-changed: Fix uri not being removed from uriIndex
+        lock.lock();
+        try {
+            uri = getEffectiveURI(uri);
+            if (uriIndex.get(uri) == null) {
+                return false;
+            } else {
+                List<HttpCookie> cookies = uriIndex.get(uri);
+                if (cookies != null) {
+                    return cookies.remove(ck);
+                } else {
+                    return false;
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+        // END Android-changed: Fix uri not being removed from uriIndex
+    }
+
+
+    /**
+     * Remove all cookies in this cookie store.
+     */
+    public boolean removeAll() {
+        lock.lock();
+        // BEGIN Android-changed: Let removeAll() return false when there are no cookies.
+        boolean result = false;
+
+        try {
+            result = !uriIndex.isEmpty();
+            uriIndex.clear();
+        } finally {
+            lock.unlock();
+        }
+
+        return result;
+        // END Android-changed: Let removeAll() return false when there are no cookies.
+    }
+
+
+    /* ---------------- Private operations -------------- */
+
+
+    /*
+     * This is almost the same as HttpCookie.domainMatches except for
+     * one difference: It won't reject cookies when the 'H' part of the
+     * domain contains a dot ('.').
+     * I.E.: RFC 2965 section 3.3.2 says that if host is x.y.domain.com
+     * and the cookie domain is .domain.com, then it should be rejected.
+     * However that's not how the real world works. Browsers don't reject and
+     * some sites, like yahoo.com do actually expect these cookies to be
+     * passed along.
+     * And should be used for 'old' style cookies (aka Netscape type of cookies)
+     */
+    private boolean netscapeDomainMatches(String domain, String host)
+    {
+        if (domain == null || host == null) {
+            return false;
+        }
+
+        // if there's no embedded dot in domain and domain is not .local
+        boolean isLocalDomain = ".local".equalsIgnoreCase(domain);
+        int embeddedDotInDomain = domain.indexOf('.');
+        if (embeddedDotInDomain == 0) {
+            embeddedDotInDomain = domain.indexOf('.', 1);
+        }
+        if (!isLocalDomain && (embeddedDotInDomain == -1 || embeddedDotInDomain == domain.length() - 1)) {
+            return false;
+        }
+
+        // if the host name contains no dot and the domain name is .local
+        int firstDotInHost = host.indexOf('.');
+        if (firstDotInHost == -1 && isLocalDomain) {
+            return true;
+        }
+
+        int domainLength = domain.length();
+        int lengthDiff = host.length() - domainLength;
+        if (lengthDiff == 0) {
+            // if the host name and the domain name are just string-compare euqal
+            return host.equalsIgnoreCase(domain);
+        } else if (lengthDiff > 0) {
+            // need to check H & D component
+            String D = host.substring(lengthDiff);
+
+            // Android-changed: b/26456024 targetSdkVersion based compatibility for domain matching
+            // Android M and earlier: Cookies with domain "foo.com" would not match "bar.foo.com".
+            // The RFC dictates that the user agent must treat those domains as if they had a
+            // leading period and must therefore match "bar.foo.com".
+            if (applyMCompatibility && !domain.startsWith(".")) {
+                return false;
+            }
+
+            return (D.equalsIgnoreCase(domain));
+        } else if (lengthDiff == -1) {
+            // if domain is actually .host
+            return (domain.charAt(0) == '.' &&
+                    host.equalsIgnoreCase(domain.substring(1)));
+        }
+
+        return false;
+    }
+
+    private void getInternal1(List<HttpCookie> cookies, Map<URI, List<HttpCookie>> cookieIndex,
+            String host) {
+        // BEGIN Android-changed: b/25897688 InMemoryCookieStore ignores scheme (http/https)
+        // Use a separate list to handle cookies that need to be removed so
+        // that there is no conflict with iterators.
+        ArrayList<HttpCookie> toRemove = new ArrayList<HttpCookie>();
+        for (Map.Entry<URI, List<HttpCookie>> entry : cookieIndex.entrySet()) {
+            List<HttpCookie> lst = entry.getValue();
+            for (HttpCookie c : lst) {
+                String domain = c.getDomain();
+                if ((c.getVersion() == 0 && netscapeDomainMatches(domain, host)) ||
+                        (c.getVersion() == 1 && HttpCookie.domainMatches(domain, host))) {
+
+                    // the cookie still in main cookie store
+                    if (!c.hasExpired()) {
+                        // don't add twice
+                        if (!cookies.contains(c)) {
+                            cookies.add(c);
+                        }
+                    } else {
+                        toRemove.add(c);
+                    }
+                }
+            }
+            // Clear up the cookies that need to be removed
+            for (HttpCookie c : toRemove) {
+                lst.remove(c);
+
+            }
+            toRemove.clear();
+        }
+        // END Android-changed: b/25897688 InMemoryCookieStore ignores scheme (http/https)
+    }
+
+    // @param cookies           [OUT] contains the found cookies
+    // @param cookieIndex       the index
+    // @param comparator        the prediction to decide whether or not
+    //                          a cookie in index should be returned
+    private <T extends Comparable<T>>
+        void getInternal2(List<HttpCookie> cookies, Map<T, List<HttpCookie>> cookieIndex,
+                          T comparator)
+    {
+        // BEGIN Android-changed: b/25897688 InMemoryCookieStore ignores scheme (http/https)
+        // Removed cookieJar
+        for (T index : cookieIndex.keySet()) {
+            if ((index == comparator) || (index != null && comparator.compareTo(index) == 0)) {
+                List<HttpCookie> indexedCookies = cookieIndex.get(index);
+                // check the list of cookies associated with this domain
+                if (indexedCookies != null) {
+                    Iterator<HttpCookie> it = indexedCookies.iterator();
+                    while (it.hasNext()) {
+                        HttpCookie ck = it.next();
+                        // the cookie still in main cookie store
+                        if (!ck.hasExpired()) {
+                            // don't add twice
+                            if (!cookies.contains(ck))
+                                cookies.add(ck);
+                        } else {
+                            it.remove();
+                        }
+                    }
+                } // end of indexedCookies != null
+            } // end of comparator.compareTo(index) == 0
+        } // end of cookieIndex iteration
+        // END Android-changed: b/25897688 InMemoryCookieStore ignores scheme (http/https)
+    }
+
+    // add 'cookie' indexed by 'index' into 'indexStore'
+    private <T> void addIndex(Map<T, List<HttpCookie>> indexStore,
+                              T index,
+                              HttpCookie cookie)
+    {
+        // Android-changed: "index" can be null. We only use the URI based
+        // index on Android and we want to support null URIs. The underlying
+        // store is a HashMap which will support null keys anyway.
+        // if (index != null) {
+        List<HttpCookie> cookies = indexStore.get(index);
+        if (cookies != null) {
+            // there may already have the same cookie, so remove it first
+            cookies.remove(cookie);
+
+            cookies.add(cookie);
+        } else {
+            cookies = new ArrayList<HttpCookie>();
+            cookies.add(cookie);
+            indexStore.put(index, cookies);
+        }
+    }
+
+
+    //
+    // for cookie purpose, the effective uri should only be http://host
+    // the path will be taken into account when path-match algorithm applied
+    //
+    private URI getEffectiveURI(URI uri) {
+        URI effectiveURI = null;
+        // Android-added: Fix NullPointerException
+        if (uri == null) {
+            return null;
+        }
+        try {
+            effectiveURI = new URI("http",
+                                   uri.getHost(),
+                                   null,  // path component
+                                   null,  // query component
+                                   null   // fragment component
+                                  );
+        } catch (URISyntaxException ignored) {
+            effectiveURI = uri;
+        }
+
+        return effectiveURI;
+    }
+}
diff --git a/java/net/Inet4Address.annotated.java b/java/net/Inet4Address.annotated.java
new file mode 100644
index 0000000..e10debf
--- /dev/null
+++ b/java/net/Inet4Address.annotated.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.net;
+
+import java.io.ObjectStreamException;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Inet4Address extends java.net.InetAddress {
+
+Inet4Address() { throw new RuntimeException("Stub!"); }
+
+public boolean isMulticastAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isAnyLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isLoopbackAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isLinkLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isSiteLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCGlobal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCNodeLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCLinkLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCSiteLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCOrgLocal() { throw new RuntimeException("Stub!"); }
+
+public byte[] getAddress() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getHostAddress() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static final java.net.InetAddress ALL;
+static { ALL = null; }
+
[email protected]
+public static final java.net.InetAddress ANY;
+static { ANY = null; }
+
[email protected]
+public static final java.net.InetAddress LOOPBACK;
+static { LOOPBACK = null; }
+}
+
diff --git a/java/net/Inet4Address.java b/java/net/Inet4Address.java
new file mode 100644
index 0000000..1fb7b92
--- /dev/null
+++ b/java/net/Inet4Address.java
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.ObjectStreamException;
+import static android.system.OsConstants.*;
+
+/**
+ * This class represents an Internet Protocol version 4 (IPv4) address.
+ * Defined by <a href="http://www.ietf.org/rfc/rfc790.txt">
+ * <i>RFC&nbsp;790: Assigned Numbers</i></a>,
+ * <a href="http://www.ietf.org/rfc/rfc1918.txt">
+ * <i>RFC&nbsp;1918: Address Allocation for Private Internets</i></a>,
+ * and <a href="http://www.ietf.org/rfc/rfc2365.txt"><i>RFC&nbsp;2365:
+ * Administratively Scoped IP Multicast</i></a>
+ *
+ * <h3> <A NAME="format">Textual representation of IP addresses</a> </h3>
+ *
+ * Textual representation of IPv4 address used as input to methods
+ * takes one of the following forms:
+ *
+ * <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
+ * <tr><td>{@code d.d.d.d}</td></tr>
+ * <tr><td>{@code d.d.d}</td></tr>
+ * <tr><td>{@code d.d}</td></tr>
+ * <tr><td>{@code d}</td></tr>
+ * </table></blockquote>
+ *
+ * <p> When four parts are specified, each is interpreted as a byte of
+ * data and assigned, from left to right, to the four bytes of an IPv4
+ * address.
+
+ * <p> When a three part address is specified, the last part is
+ * interpreted as a 16-bit quantity and placed in the right most two
+ * bytes of the network address. This makes the three part address
+ * format convenient for specifying Class B net- work addresses as
+ * 128.net.host.
+ *
+ * <p> When a two part address is supplied, the last part is
+ * interpreted as a 24-bit quantity and placed in the right most three
+ * bytes of the network address. This makes the two part address
+ * format convenient for specifying Class A network addresses as
+ * net.host.
+ *
+ * <p> When only one part is given, the value is stored directly in
+ * the network address without any byte rearrangement.
+ *
+ * <p> For methods that return a textual representation as output
+ * value, the first form, i.e. a dotted-quad string, is used.
+ *
+ * <h4> The Scope of a Multicast Address </h4>
+ *
+ * Historically the IPv4 TTL field in the IP header has doubled as a
+ * multicast scope field: a TTL of 0 means node-local, 1 means
+ * link-local, up through 32 means site-local, up through 64 means
+ * region-local, up through 128 means continent-local, and up through
+ * 255 are global. However, the administrative scoping is preferred.
+ * Please refer to <a href="http://www.ietf.org/rfc/rfc2365.txt">
+ * <i>RFC&nbsp;2365: Administratively Scoped IP Multicast</i></a>
+ * @since 1.4
+ */
+
+public final
+class Inet4Address extends InetAddress {
+    final static int INADDRSZ = 4;
+
+    /** use serialVersionUID from InetAddress, but Inet4Address instance
+     *  is always replaced by an InetAddress instance before being
+     *  serialized */
+    private static final long serialVersionUID = 3286316764910316507L;
+
+    // BEGIN Android-added: Define special-purpose IPv4 address
+    /** @hide */
+    public static final InetAddress ANY = new Inet4Address(null, new byte[] { 0, 0, 0, 0 });
+
+    /** @hide */
+    public static final InetAddress ALL =
+            new Inet4Address(null, new byte[] { (byte) 255, (byte) 255,
+                  (byte) 255, (byte) 255 });
+    /** @hide */
+    public static final InetAddress LOOPBACK =
+            new Inet4Address("localhost", new byte[] { 127, 0, 0, 1 });
+    // END Android-added: Define special-purpose IPv4 address
+
+
+    // BEGIN Android-removed: Android doesn't need to call native init
+    /*
+     * Perform initializations.
+     *
+    static {
+        init();
+    }
+    */
+    // END Android-removed: Android doesn't need to call native init
+    Inet4Address() {
+        super();
+        holder().hostName = null;
+        holder().address = 0;
+        holder().family = AF_INET;
+    }
+
+    Inet4Address(String hostName, byte addr[]) {
+        holder().hostName = hostName;
+        holder().family = AF_INET;
+        if (addr != null) {
+            if (addr.length == INADDRSZ) {
+                int address  = addr[3] & 0xFF;
+                address |= ((addr[2] << 8) & 0xFF00);
+                address |= ((addr[1] << 16) & 0xFF0000);
+                address |= ((addr[0] << 24) & 0xFF000000);
+                holder().address = address;
+            }
+        }
+        holder().originalHostName = hostName;
+    }
+    Inet4Address(String hostName, int address) {
+        holder().hostName = hostName;
+        holder().family = AF_INET;
+        holder().address = address;
+        holder().originalHostName = hostName;
+    }
+
+    /**
+     * Replaces the object to be serialized with an InetAddress object.
+     *
+     * @return the alternate object to be serialized.
+     *
+     * @throws ObjectStreamException if a new object replacing this
+     * object could not be created
+     */
+    private Object writeReplace() throws ObjectStreamException {
+        // will replace the to be serialized 'this' object
+        InetAddress inet = new InetAddress();
+        inet.holder().hostName = holder().getHostName();
+        inet.holder().address = holder().getAddress();
+
+        /**
+         * Prior to 1.4 an InetAddress was created with a family
+         * based on the platform AF_INET value (usually 2).
+         * For compatibility reasons we must therefore write the
+         * the InetAddress with this family.
+         */
+        inet.holder().family = 2;
+
+        return inet;
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is an
+     * IP multicast address. IP multicast address is a Class D
+     * address i.e first four bits of the address are 1110.
+     * @return a {@code boolean} indicating if the InetAddress is
+     * an IP multicast address
+     * @since   JDK1.1
+     */
+    public boolean isMulticastAddress() {
+        return ((holder().getAddress() & 0xf0000000) == 0xe0000000);
+    }
+
+    /**
+     * Utility routine to check if the InetAddress in a wildcard address.
+     * @return a {@code boolean} indicating if the Inetaddress is
+     *         a wildcard address.
+     * @since 1.4
+     */
+    public boolean isAnyLocalAddress() {
+        return holder().getAddress() == 0;
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is a loopback address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is
+     * a loopback address; or false otherwise.
+     * @since 1.4
+     */
+    public boolean isLoopbackAddress() {
+        /* 127.x.x.x */
+        byte[] byteAddr = getAddress();
+        return byteAddr[0] == 127;
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is an link local address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is
+     * a link local address; or false if address is not a link local unicast address.
+     * @since 1.4
+     */
+    public boolean isLinkLocalAddress() {
+        // link-local unicast in IPv4 (169.254.0.0/16)
+        // defined in "Documenting Special Use IPv4 Address Blocks
+        // that have been Registered with IANA" by Bill Manning
+        // draft-manning-dsua-06.txt
+        int address = holder().getAddress();
+        return (((address >>> 24) & 0xFF) == 169)
+            && (((address >>> 16) & 0xFF) == 254);
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is a site local address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is
+     * a site local address; or false if address is not a site local unicast address.
+     * @since 1.4
+     */
+    public boolean isSiteLocalAddress() {
+        // refer to RFC 1918
+        // 10/8 prefix
+        // 172.16/12 prefix
+        // 192.168/16 prefix
+        int address = holder().getAddress();
+        return (((address >>> 24) & 0xFF) == 10)
+            || ((((address >>> 24) & 0xFF) == 172)
+                && (((address >>> 16) & 0xF0) == 16))
+            || ((((address >>> 24) & 0xFF) == 192)
+                && (((address >>> 16) & 0xFF) == 168));
+    }
+
+    /**
+     * Utility routine to check if the multicast address has global scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of global scope, false if it is not
+     *         of global scope or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCGlobal() {
+        // 224.0.1.0 to 238.255.255.255
+        byte[] byteAddr = getAddress();
+        return ((byteAddr[0] & 0xff) >= 224 && (byteAddr[0] & 0xff) <= 238 ) &&
+            !((byteAddr[0] & 0xff) == 224 && byteAddr[1] == 0 &&
+              byteAddr[2] == 0);
+    }
+
+    /**
+     * Utility routine to check if the multicast address has node scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of node-local scope, false if it is not
+     *         of node-local scope or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCNodeLocal() {
+        // unless ttl == 0
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the multicast address has link scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of link-local scope, false if it is not
+     *         of link-local scope or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCLinkLocal() {
+        // 224.0.0/24 prefix and ttl == 1
+        int address = holder().getAddress();
+        return (((address >>> 24) & 0xFF) == 224)
+            && (((address >>> 16) & 0xFF) == 0)
+            && (((address >>> 8) & 0xFF) == 0);
+    }
+
+    /**
+     * Utility routine to check if the multicast address has site scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of site-local scope, false if it is not
+     *         of site-local scope or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCSiteLocal() {
+        // 239.255/16 prefix or ttl < 32
+        int address = holder().getAddress();
+        return (((address >>> 24) & 0xFF) == 239)
+            && (((address >>> 16) & 0xFF) == 255);
+    }
+
+    /**
+     * Utility routine to check if the multicast address has organization scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of organization-local scope,
+     *         false if it is not of organization-local scope
+     *         or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCOrgLocal() {
+        // 239.192 - 239.195
+        int address = holder().getAddress();
+        return (((address >>> 24) & 0xFF) == 239)
+            && (((address >>> 16) & 0xFF) >= 192)
+            && (((address >>> 16) & 0xFF) <= 195);
+    }
+
+    /**
+     * Returns the raw IP address of this {@code InetAddress}
+     * object. The result is in network byte order: the highest order
+     * byte of the address is in {@code getAddress()[0]}.
+     *
+     * @return  the raw IP address of this object.
+     */
+    public byte[] getAddress() {
+        int address = holder().getAddress();
+        byte[] addr = new byte[INADDRSZ];
+
+        addr[0] = (byte) ((address >>> 24) & 0xFF);
+        addr[1] = (byte) ((address >>> 16) & 0xFF);
+        addr[2] = (byte) ((address >>> 8) & 0xFF);
+        addr[3] = (byte) (address & 0xFF);
+        return addr;
+    }
+
+    /**
+     * Returns the IP address string in textual presentation form.
+     *
+     * @return  the raw IP address in a string format.
+     * @since   JDK1.0.2
+     */
+    public String getHostAddress() {
+        return numericToTextFormat(getAddress());
+    }
+
+    /**
+     * Returns a hashcode for this IP address.
+     *
+     * @return  a hash code value for this IP address.
+     */
+    public int hashCode() {
+        return holder().getAddress();
+    }
+
+    /**
+     * Compares this object against the specified object.
+     * The result is {@code true} if and only if the argument is
+     * not {@code null} and it represents the same IP address as
+     * this object.
+     * <p>
+     * Two instances of {@code InetAddress} represent the same IP
+     * address if the length of the byte arrays returned by
+     * {@code getAddress} is the same for both, and each of the
+     * array components is the same for the byte arrays.
+     *
+     * @param   obj   the object to compare against.
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     * @see     java.net.InetAddress#getAddress()
+     */
+    public boolean equals(Object obj) {
+        return (obj != null) && (obj instanceof Inet4Address) &&
+            (((InetAddress)obj).holder().getAddress() == holder().getAddress());
+    }
+
+    // Utilities
+    /*
+     * Converts IPv4 binary address into a string suitable for presentation.
+     *
+     * @param src a byte array representing an IPv4 numeric address
+     * @return a String representing the IPv4 address in
+     *         textual representation format
+     * @since 1.4
+     */
+
+    static String numericToTextFormat(byte[] src)
+    {
+        return (src[0] & 0xff) + "." + (src[1] & 0xff) + "." + (src[2] & 0xff) + "." + (src[3] & 0xff);
+    }
+
+    // BEGIN Android-removed: Android doesn't need to call native init
+    /*
+     * Perform class load-time initializations.
+     *
+    private static native void init();
+    */
+    // END Android-removed: Android doesn't need to call native init
+}
diff --git a/java/net/Inet6Address.annotated.java b/java/net/Inet6Address.annotated.java
new file mode 100644
index 0000000..7888710
--- /dev/null
+++ b/java/net/Inet6Address.annotated.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.net;
+
+
[email protected]
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Inet6Address extends java.net.InetAddress {
+
+Inet6Address() { throw new RuntimeException("Stub!"); }
+
+public static java.net.Inet6Address getByAddress(java.lang.String host, byte[] addr, java.net.NetworkInterface nif) throws java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+
+public static java.net.Inet6Address getByAddress(java.lang.String host, byte[] addr, int scope_id) throws java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+
+public boolean isMulticastAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isAnyLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isLoopbackAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isLinkLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isSiteLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCGlobal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCNodeLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCLinkLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCSiteLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCOrgLocal() { throw new RuntimeException("Stub!"); }
+
+public byte[] getAddress() { throw new RuntimeException("Stub!"); }
+
[email protected]
+public int getScopeId() { throw new RuntimeException("Stub!"); }
+
+public java.net.NetworkInterface getScopedInterface() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getHostAddress() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public boolean isIPv4CompatibleAddress() { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static final java.net.InetAddress ANY;
+static { ANY = null; }
+
[email protected]
+public static final java.net.InetAddress LOOPBACK;
+static { LOOPBACK = null; }
+}
diff --git a/java/net/Inet6Address.java b/java/net/Inet6Address.java
new file mode 100644
index 0000000..c0aadb3
--- /dev/null
+++ b/java/net/Inet6Address.java
@@ -0,0 +1,981 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.util.Enumeration;
+import java.util.Arrays;
+import libcore.io.Libcore;
+import static android.system.OsConstants.*;
+
+/**
+ * This class represents an Internet Protocol version 6 (IPv6) address.
+ * Defined by <a href="http://www.ietf.org/rfc/rfc2373.txt">
+ * <i>RFC&nbsp;2373: IP Version 6 Addressing Architecture</i></a>.
+ *
+ * <h3> <A NAME="format">Textual representation of IP addresses</a> </h3>
+ *
+ * Textual representation of IPv6 address used as input to methods
+ * takes one of the following forms:
+ *
+ * <ol>
+ *   <li><p> <A NAME="lform">The preferred form</a> is x:x:x:x:x:x:x:x,
+ *   where the 'x's are
+ *   the hexadecimal values of the eight 16-bit pieces of the
+ *   address. This is the full form.  For example,
+ *
+ *   <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
+ *   <tr><td>{@code 1080:0:0:0:8:800:200C:417A}<td></tr>
+ *   </table></blockquote>
+ *
+ *   <p> Note that it is not necessary to write the leading zeros in
+ *   an individual field. However, there must be at least one numeral
+ *   in every field, except as described below.</li>
+ *
+ *   <li><p> Due to some methods of allocating certain styles of IPv6
+ *   addresses, it will be common for addresses to contain long
+ *   strings of zero bits. In order to make writing addresses
+ *   containing zero bits easier, a special syntax is available to
+ *   compress the zeros. The use of "::" indicates multiple groups
+ *   of 16-bits of zeros. The "::" can only appear once in an address.
+ *   The "::" can also be used to compress the leading and/or trailing
+ *   zeros in an address. For example,
+ *
+ *   <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
+ *   <tr><td>{@code 1080::8:800:200C:417A}<td></tr>
+ *   </table></blockquote>
+ *
+ *   <li><p> An alternative form that is sometimes more convenient
+ *   when dealing with a mixed environment of IPv4 and IPv6 nodes is
+ *   x:x:x:x:x:x:d.d.d.d, where the 'x's are the hexadecimal values
+ *   of the six high-order 16-bit pieces of the address, and the 'd's
+ *   are the decimal values of the four low-order 8-bit pieces of the
+ *   standard IPv4 representation address, for example,
+ *
+ *   <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
+ *   <tr><td>{@code ::FFFF:129.144.52.38}<td></tr>
+ *   <tr><td>{@code ::129.144.52.38}<td></tr>
+ *   </table></blockquote>
+ *
+ *   <p> where "::FFFF:d.d.d.d" and "::d.d.d.d" are, respectively, the
+ *   general forms of an IPv4-mapped IPv6 address and an
+ *   IPv4-compatible IPv6 address. Note that the IPv4 portion must be
+ *   in the "d.d.d.d" form. The following forms are invalid:
+ *
+ *   <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
+ *   <tr><td>{@code ::FFFF:d.d.d}<td></tr>
+ *   <tr><td>{@code ::FFFF:d.d}<td></tr>
+ *   <tr><td>{@code ::d.d.d}<td></tr>
+ *   <tr><td>{@code ::d.d}<td></tr>
+ *   </table></blockquote>
+ *
+ *   <p> The following form:
+ *
+ *   <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
+ *   <tr><td>{@code ::FFFF:d}<td></tr>
+ *   </table></blockquote>
+ *
+ *   <p> is valid, however it is an unconventional representation of
+ *   the IPv4-compatible IPv6 address,
+ *
+ *   <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
+ *   <tr><td>{@code ::255.255.0.d}<td></tr>
+ *   </table></blockquote>
+ *
+ *   <p> while "::d" corresponds to the general IPv6 address
+ *   "0:0:0:0:0:0:0:d".</li>
+ * </ol>
+ *
+ * <p> For methods that return a textual representation as output
+ * value, the full form is used. Inet6Address will return the full
+ * form because it is unambiguous when used in combination with other
+ * textual data.
+ *
+ * <h4> Special IPv6 address </h4>
+ *
+ * <blockquote>
+ * <table cellspacing=2 summary="Description of IPv4-mapped address">
+ * <tr><th valign=top><i>IPv4-mapped address</i></th>
+ *         <td>Of the form::ffff:w.x.y.z, this IPv6 address is used to
+ *         represent an IPv4 address. It allows the native program to
+ *         use the same address data structure and also the same
+ *         socket when communicating with both IPv4 and IPv6 nodes.
+ *
+ *         <p>In InetAddress and Inet6Address, it is used for internal
+ *         representation; it has no functional role. Java will never
+ *         return an IPv4-mapped address.  These classes can take an
+ *         IPv4-mapped address as input, both in byte array and text
+ *         representation. However, it will be converted into an IPv4
+ *         address.</td></tr>
+ * </table></blockquote>
+ *
+ * <h4><A NAME="scoped">Textual representation of IPv6 scoped addresses</a></h4>
+ *
+ * <p> The textual representation of IPv6 addresses as described above can be
+ * extended to specify IPv6 scoped addresses. This extension to the basic
+ * addressing architecture is described in [draft-ietf-ipngwg-scoping-arch-04.txt].
+ *
+ * <p> Because link-local and site-local addresses are non-global, it is possible
+ * that different hosts may have the same destination address and may be
+ * reachable through different interfaces on the same originating system. In
+ * this case, the originating system is said to be connected to multiple zones
+ * of the same scope. In order to disambiguate which is the intended destination
+ * zone, it is possible to append a zone identifier (or <i>scope_id</i>) to an
+ * IPv6 address.
+ *
+ * <p> The general format for specifying the <i>scope_id</i> is the following:
+ *
+ * <blockquote><i>IPv6-address</i>%<i>scope_id</i></blockquote>
+ * <p> The IPv6-address is a literal IPv6 address as described above.
+ * The <i>scope_id</i> refers to an interface on the local system, and it can be
+ * specified in two ways.
+ * <ol><li><i>As a numeric identifier.</i> This must be a positive integer
+ * that identifies the particular interface and scope as understood by the
+ * system. Usually, the numeric values can be determined through administration
+ * tools on the system. Each interface may have multiple values, one for each
+ * scope. If the scope is unspecified, then the default value used is zero.</li>
+ * <li><i>As a string.</i> This must be the exact string that is returned by
+ * {@link java.net.NetworkInterface#getName()} for the particular interface in
+ * question. When an Inet6Address is created in this way, the numeric scope-id
+ * is determined at the time the object is created by querying the relevant
+ * NetworkInterface.</li></ol>
+ *
+ * <p> Note also, that the numeric <i>scope_id</i> can be retrieved from
+ * Inet6Address instances returned from the NetworkInterface class. This can be
+ * used to find out the current scope ids configured on the system.
+ * @since 1.4
+ */
+
+public final
+class Inet6Address extends InetAddress {
+    final static int INADDRSZ = 16;
+
+    // BEGIN Android-removed: Remove special handling for link-local addresses
+    /*
+    * cached scope_id - for link-local address use only.
+    *
+    private transient int cached_scope_id;  // 0
+    */
+    // END Android-removed: Remove special handling for link-local addresses
+
+    // BEGIN Android-added: Define special-purpose IPv6 address
+    /** @hide */
+    public static final InetAddress ANY =
+            new Inet6Address("::", new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0);
+
+    /** @hide */
+    public static final InetAddress LOOPBACK = new Inet6Address("ip6-localhost",
+            new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 0);
+    // END Android-added: Define special-purpose IPv6 address
+
+    private class Inet6AddressHolder {
+
+        private Inet6AddressHolder() {
+            ipaddress = new byte[INADDRSZ];
+        }
+
+        private Inet6AddressHolder(
+            byte[] ipaddress, int scope_id, boolean scope_id_set,
+            NetworkInterface ifname, boolean scope_ifname_set)
+        {
+            this.ipaddress = ipaddress;
+            this.scope_id = scope_id;
+            this.scope_id_set = scope_id_set;
+            this.scope_ifname_set = scope_ifname_set;
+            this.scope_ifname = ifname;
+        }
+
+        /**
+         * Holds a 128-bit (16 bytes) IPv6 address.
+         */
+        byte[] ipaddress;
+
+        /**
+         * scope_id. The scope specified when the object is created. If the object
+         * is created with an interface name, then the scope_id is not determined
+         * until the time it is needed.
+         */
+        int scope_id;  // 0
+
+        /**
+         * This will be set to true when the scope_id field contains a valid
+         * integer scope_id.
+         */
+        boolean scope_id_set;  // false
+
+        /**
+         * scoped interface. scope_id is derived from this as the scope_id of the first
+         * address whose scope is the same as this address for the named interface.
+         */
+        NetworkInterface scope_ifname;  // null
+
+        /**
+         * set if the object is constructed with a scoped
+         * interface instead of a numeric scope id.
+         */
+        boolean scope_ifname_set; // false;
+
+        void setAddr(byte addr[]) {
+            if (addr.length == INADDRSZ) { // normal IPv6 address
+                System.arraycopy(addr, 0, ipaddress, 0, INADDRSZ);
+            }
+        }
+
+        void init(byte addr[], int scope_id) {
+            setAddr(addr);
+
+            // Android-changed: was >= 0
+            if (scope_id > 0) {
+                this.scope_id = scope_id;
+                this.scope_id_set = true;
+            }
+        }
+
+        void init(byte addr[], NetworkInterface nif)
+            throws UnknownHostException
+        {
+            setAddr(addr);
+
+            if (nif != null) {
+                this.scope_id = deriveNumericScope(ipaddress, nif);
+                this.scope_id_set = true;
+                this.scope_ifname = nif;
+                this.scope_ifname_set = true;
+            }
+        }
+
+        // Android-removed: getnameinfo returns smarter representations than getHostAddress()
+        /*
+        String getHostAddress() {
+            String s = numericToTextFormat(ipaddress);
+            if (scope_ifname != null) { // must check this first
+                s = s + "%" + scope_ifname.getName();
+            } else if (scope_id_set) {
+                s = s + "%" + scope_id;
+            }
+            return s;
+        }
+        */
+
+        public boolean equals(Object o) {
+            if (! (o instanceof Inet6AddressHolder)) {
+                return false;
+            }
+            Inet6AddressHolder that = (Inet6AddressHolder)o;
+
+            return Arrays.equals(this.ipaddress, that.ipaddress);
+        }
+
+        public int hashCode() {
+            if (ipaddress != null) {
+
+                int hash = 0;
+                int i=0;
+                while (i<INADDRSZ) {
+                    int j=0;
+                    int component=0;
+                    while (j<4 && i<INADDRSZ) {
+                        component = (component << 8) + ipaddress[i];
+                        j++;
+                        i++;
+                    }
+                    hash += component;
+                }
+                return hash;
+
+            } else {
+                return 0;
+            }
+        }
+
+        boolean isIPv4CompatibleAddress() {
+            if ((ipaddress[0] == 0x00) && (ipaddress[1] == 0x00) &&
+                (ipaddress[2] == 0x00) && (ipaddress[3] == 0x00) &&
+                (ipaddress[4] == 0x00) && (ipaddress[5] == 0x00) &&
+                (ipaddress[6] == 0x00) && (ipaddress[7] == 0x00) &&
+                (ipaddress[8] == 0x00) && (ipaddress[9] == 0x00) &&
+                (ipaddress[10] == 0x00) && (ipaddress[11] == 0x00))  {
+                return true;
+            }
+            return false;
+        }
+
+        boolean isMulticastAddress() {
+            return ((ipaddress[0] & 0xff) == 0xff);
+        }
+
+        boolean isAnyLocalAddress() {
+            byte test = 0x00;
+            for (int i = 0; i < INADDRSZ; i++) {
+                test |= ipaddress[i];
+            }
+            return (test == 0x00);
+        }
+
+        boolean isLoopbackAddress() {
+            byte test = 0x00;
+            for (int i = 0; i < 15; i++) {
+                test |= ipaddress[i];
+            }
+            return (test == 0x00) && (ipaddress[15] == 0x01);
+        }
+
+        boolean isLinkLocalAddress() {
+            return ((ipaddress[0] & 0xff) == 0xfe
+                    && (ipaddress[1] & 0xc0) == 0x80);
+        }
+
+
+        boolean isSiteLocalAddress() {
+            return ((ipaddress[0] & 0xff) == 0xfe
+                    && (ipaddress[1] & 0xc0) == 0xc0);
+        }
+
+        boolean isMCGlobal() {
+            return ((ipaddress[0] & 0xff) == 0xff
+                    && (ipaddress[1] & 0x0f) == 0x0e);
+        }
+
+        boolean isMCNodeLocal() {
+            return ((ipaddress[0] & 0xff) == 0xff
+                    && (ipaddress[1] & 0x0f) == 0x01);
+        }
+
+        boolean isMCLinkLocal() {
+            return ((ipaddress[0] & 0xff) == 0xff
+                    && (ipaddress[1] & 0x0f) == 0x02);
+        }
+
+        boolean isMCSiteLocal() {
+            return ((ipaddress[0] & 0xff) == 0xff
+                    && (ipaddress[1] & 0x0f) == 0x05);
+        }
+
+        boolean isMCOrgLocal() {
+            return ((ipaddress[0] & 0xff) == 0xff
+                    && (ipaddress[1] & 0x0f) == 0x08);
+        }
+    }
+
+    private final transient Inet6AddressHolder holder6;
+
+    private static final long serialVersionUID = 6880410070516793377L;
+
+    // BEGIN Android-removed: Android doesn't need to call native init
+    /*
+    // Perform native initialization
+    static { init(); }
+    // END Android-removed: Android doesn't need to call native init
+    */
+
+    Inet6Address() {
+        super();
+        holder.init(null, AF_INET6);
+        holder6 = new Inet6AddressHolder();
+    }
+
+    /* checking of value for scope_id should be done by caller
+     * scope_id must be >= 0, or -1 to indicate not being set
+     */
+    Inet6Address(String hostName, byte addr[], int scope_id) {
+        holder.init(hostName, AF_INET6);
+        holder6 = new Inet6AddressHolder();
+        holder6.init(addr, scope_id);
+    }
+
+    Inet6Address(String hostName, byte addr[]) {
+        holder6 = new Inet6AddressHolder();
+        try {
+            initif (hostName, addr, null);
+        } catch (UnknownHostException e) {} /* cant happen if ifname is null */
+    }
+
+    Inet6Address (String hostName, byte addr[], NetworkInterface nif)
+        throws UnknownHostException
+    {
+        holder6 = new Inet6AddressHolder();
+        initif (hostName, addr, nif);
+    }
+
+    Inet6Address (String hostName, byte addr[], String ifname)
+        throws UnknownHostException
+    {
+        holder6 = new Inet6AddressHolder();
+        initstr (hostName, addr, ifname);
+    }
+
+    /**
+     * Create an Inet6Address in the exact manner of {@link
+     * InetAddress#getByAddress(String,byte[])} except that the IPv6 scope_id is
+     * set to the value corresponding to the given interface for the address
+     * type specified in {@code addr}. The call will fail with an
+     * UnknownHostException if the given interface does not have a numeric
+     * scope_id assigned for the given address type (eg. link-local or site-local).
+     * See <a href="Inet6Address.html#scoped">here</a> for a description of IPv6
+     * scoped addresses.
+     *
+     * @param host the specified host
+     * @param addr the raw IP address in network byte order
+     * @param nif an interface this address must be associated with.
+     * @return  an Inet6Address object created from the raw IP address.
+     * @throws  UnknownHostException
+     *          if IP address is of illegal length, or if the interface does not
+     *          have a numeric scope_id assigned for the given address type.
+     *
+     * @since 1.5
+     */
+    public static Inet6Address getByAddress(String host, byte[] addr,
+                                            NetworkInterface nif)
+        throws UnknownHostException
+    {
+        if (host != null && host.length() > 0 && host.charAt(0) == '[') {
+            if (host.charAt(host.length()-1) == ']') {
+                host = host.substring(1, host.length() -1);
+            }
+        }
+        if (addr != null) {
+            if (addr.length == Inet6Address.INADDRSZ) {
+                return new Inet6Address(host, addr, nif);
+            }
+        }
+        throw new UnknownHostException("addr is of illegal length");
+    }
+
+    /**
+     * Create an Inet6Address in the exact manner of {@link
+     * InetAddress#getByAddress(String,byte[])} except that the IPv6 scope_id is
+     * set to the given numeric value. The scope_id is not checked to determine
+     * if it corresponds to any interface on the system.
+     * See <a href="Inet6Address.html#scoped">here</a> for a description of IPv6
+     * scoped addresses.
+     *
+     * @param host the specified host
+     * @param addr the raw IP address in network byte order
+     * @param scope_id the numeric scope_id for the address.
+     * @return  an Inet6Address object created from the raw IP address.
+     * @throws  UnknownHostException  if IP address is of illegal length.
+     *
+     * @since 1.5
+     */
+    public static Inet6Address getByAddress(String host, byte[] addr,
+                                            int scope_id)
+        throws UnknownHostException
+    {
+        if (host != null && host.length() > 0 && host.charAt(0) == '[') {
+            if (host.charAt(host.length()-1) == ']') {
+                host = host.substring(1, host.length() -1);
+            }
+        }
+        if (addr != null) {
+            if (addr.length == Inet6Address.INADDRSZ) {
+                return new Inet6Address(host, addr, scope_id);
+            }
+        }
+        throw new UnknownHostException("addr is of illegal length");
+    }
+
+    private void initstr(String hostName, byte addr[], String ifname)
+        throws UnknownHostException
+    {
+        try {
+            NetworkInterface nif = NetworkInterface.getByName (ifname);
+            if (nif == null) {
+                throw new UnknownHostException ("no such interface " + ifname);
+            }
+            initif (hostName, addr, nif);
+        } catch (SocketException e) {
+            throw new UnknownHostException ("SocketException thrown" + ifname);
+        }
+    }
+
+    private void initif(String hostName, byte addr[], NetworkInterface nif)
+        throws UnknownHostException
+    {
+        int family = -1;
+        holder6.init(addr, nif);
+
+        if (addr.length == INADDRSZ) { // normal IPv6 address
+            family = AF_INET6;
+        }
+        holder.init(hostName, family);
+    }
+
+    /* check the two Ipv6 addresses and return false if they are both
+     * non global address types, but not the same.
+     * (ie. one is sitelocal and the other linklocal)
+     * return true otherwise.
+     */
+
+    private static boolean isDifferentLocalAddressType(
+        byte[] thisAddr, byte[] otherAddr) {
+
+        if (Inet6Address.isLinkLocalAddress(thisAddr) &&
+                !Inet6Address.isLinkLocalAddress(otherAddr)) {
+            return false;
+        }
+        if (Inet6Address.isSiteLocalAddress(thisAddr) &&
+                !Inet6Address.isSiteLocalAddress(otherAddr)) {
+            return false;
+        }
+        return true;
+    }
+
+    private static int deriveNumericScope (byte[] thisAddr, NetworkInterface ifc) throws UnknownHostException {
+        Enumeration<InetAddress> addresses = ifc.getInetAddresses();
+        while (addresses.hasMoreElements()) {
+            InetAddress addr = addresses.nextElement();
+            if (!(addr instanceof Inet6Address)) {
+                continue;
+            }
+            Inet6Address ia6_addr = (Inet6Address)addr;
+            /* check if site or link local prefixes match */
+            if (!isDifferentLocalAddressType(thisAddr, ia6_addr.getAddress())){
+                /* type not the same, so carry on searching */
+                continue;
+            }
+            /* found a matching address - return its scope_id */
+            return ia6_addr.getScopeId();
+        }
+        throw new UnknownHostException ("no scope_id found");
+    }
+
+    private int deriveNumericScope (String ifname) throws UnknownHostException {
+        Enumeration<NetworkInterface> en;
+        try {
+            en = NetworkInterface.getNetworkInterfaces();
+        } catch (SocketException e) {
+            throw new UnknownHostException ("could not enumerate local network interfaces");
+        }
+        while (en.hasMoreElements()) {
+            NetworkInterface ifc = en.nextElement();
+            if (ifc.getName().equals (ifname)) {
+                return deriveNumericScope(holder6.ipaddress, ifc);
+            }
+        }
+        throw new UnknownHostException ("No matching address found for interface : " +ifname);
+    }
+
+    /**
+     * @serialField ipaddress byte[]
+     * @serialField scope_id int
+     * @serialField scope_id_set boolean
+     * @serialField scope_ifname_set boolean
+     * @serialField ifname String
+     */
+
+    private static final ObjectStreamField[] serialPersistentFields = {
+         new ObjectStreamField("ipaddress", byte[].class),
+         new ObjectStreamField("scope_id", int.class),
+         new ObjectStreamField("scope_id_set", boolean.class),
+         new ObjectStreamField("scope_ifname_set", boolean.class),
+         new ObjectStreamField("ifname", String.class)
+    };
+
+    private static final long FIELDS_OFFSET;
+    private static final sun.misc.Unsafe UNSAFE;
+
+    static {
+        try {
+            sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
+            FIELDS_OFFSET = unsafe.objectFieldOffset(
+                    Inet6Address.class.getDeclaredField("holder6"));
+            UNSAFE = unsafe;
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    /**
+     * restore the state of this object from stream
+     * including the scope information, only if the
+     * scoped interface name is valid on this system
+     */
+    private void readObject(ObjectInputStream s)
+        throws IOException, ClassNotFoundException {
+        NetworkInterface scope_ifname = null;
+
+        // Android-changed: was getClass().getClassLoader() != null
+        if (getClass().getClassLoader() != Class.class.getClassLoader()) {
+            throw new SecurityException ("invalid address type");
+        }
+
+        ObjectInputStream.GetField gf = s.readFields();
+        byte[] ipaddress = (byte[])gf.get("ipaddress", null);
+        int scope_id = (int)gf.get("scope_id", -1);
+        boolean scope_id_set = (boolean)gf.get("scope_id_set", false);
+        boolean scope_ifname_set = (boolean)gf.get("scope_ifname_set", false);
+        String ifname = (String)gf.get("ifname", null);
+
+        if (ifname != null && !"".equals (ifname)) {
+            try {
+                scope_ifname = NetworkInterface.getByName(ifname);
+                if (scope_ifname == null) {
+                    /* the interface does not exist on this system, so we clear
+                     * the scope information completely */
+                    scope_id_set = false;
+                    scope_ifname_set = false;
+                    scope_id = 0;
+                } else {
+                    scope_ifname_set = true;
+                    try {
+                        scope_id = deriveNumericScope (ipaddress, scope_ifname);
+                    } catch (UnknownHostException e) {
+                        // typically should not happen, but it may be that
+                        // the machine being used for deserialization has
+                        // the same interface name but without IPv6 configured.
+                    }
+                }
+            } catch (SocketException e) {}
+        }
+
+        /* if ifname was not supplied, then the numeric info is used */
+
+        ipaddress = ipaddress.clone();
+
+        // Check that our invariants are satisfied
+        if (ipaddress.length != INADDRSZ) {
+            throw new InvalidObjectException("invalid address length: "+
+                                             ipaddress.length);
+        }
+
+        if (holder().getFamily() != AF_INET6) {
+            throw new InvalidObjectException("invalid address family type");
+        }
+
+        Inet6AddressHolder h = new Inet6AddressHolder(
+            ipaddress, scope_id, scope_id_set, scope_ifname, scope_ifname_set
+        );
+
+        UNSAFE.putObject(this, FIELDS_OFFSET, h);
+    }
+
+    /**
+     * default behavior is overridden in order to write the
+     * scope_ifname field as a String, rather than a NetworkInterface
+     * which is not serializable
+     */
+    private synchronized void writeObject(ObjectOutputStream s)
+        throws IOException
+    {
+            String ifname = null;
+
+        if (holder6.scope_ifname != null) {
+            ifname = holder6.scope_ifname.getName();
+            holder6.scope_ifname_set = true;
+        }
+        ObjectOutputStream.PutField pfields = s.putFields();
+        pfields.put("ipaddress", holder6.ipaddress);
+        pfields.put("scope_id", holder6.scope_id);
+        pfields.put("scope_id_set", holder6.scope_id_set);
+        pfields.put("scope_ifname_set", holder6.scope_ifname_set);
+        pfields.put("ifname", ifname);
+        s.writeFields();
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is an IP multicast
+     * address. 11111111 at the start of the address identifies the
+     * address as being a multicast address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is an IP
+     *         multicast address
+     *
+     * @since JDK1.1
+     */
+    @Override
+    public boolean isMulticastAddress() {
+        return holder6.isMulticastAddress();
+    }
+
+    /**
+     * Utility routine to check if the InetAddress in a wildcard address.
+     *
+     * @return a {@code boolean} indicating if the Inetaddress is
+     *         a wildcard address.
+     *
+     * @since 1.4
+     */
+    @Override
+    public boolean isAnyLocalAddress() {
+        return holder6.isAnyLocalAddress();
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is a loopback address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is a loopback
+     *         address; or false otherwise.
+     *
+     * @since 1.4
+     */
+    @Override
+    public boolean isLoopbackAddress() {
+        return holder6.isLoopbackAddress();
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is an link local address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is a link local
+     *         address; or false if address is not a link local unicast address.
+     *
+     * @since 1.4
+     */
+    @Override
+    public boolean isLinkLocalAddress() {
+        return holder6.isLinkLocalAddress();
+    }
+
+    /* static version of above */
+    static boolean isLinkLocalAddress(byte[] ipaddress) {
+        return ((ipaddress[0] & 0xff) == 0xfe
+                && (ipaddress[1] & 0xc0) == 0x80);
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is a site local address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is a site local
+     *         address; or false if address is not a site local unicast address.
+     *
+     * @since 1.4
+     */
+    @Override
+    public boolean isSiteLocalAddress() {
+        return holder6.isSiteLocalAddress();
+    }
+
+    /* static version of above */
+    static boolean isSiteLocalAddress(byte[] ipaddress) {
+        return ((ipaddress[0] & 0xff) == 0xfe
+                && (ipaddress[1] & 0xc0) == 0xc0);
+    }
+
+    /**
+     * Utility routine to check if the multicast address has global scope.
+     *
+     * @return a {@code boolean} indicating if the address has is a multicast
+     *         address of global scope, false if it is not of global scope or
+     *         it is not a multicast address
+     *
+     * @since 1.4
+     */
+    @Override
+    public boolean isMCGlobal() {
+        return holder6.isMCGlobal();
+    }
+
+    /**
+     * Utility routine to check if the multicast address has node scope.
+     *
+     * @return a {@code boolean} indicating if the address has is a multicast
+     *         address of node-local scope, false if it is not of node-local
+     *         scope or it is not a multicast address
+     *
+     * @since 1.4
+     */
+    @Override
+    public boolean isMCNodeLocal() {
+        return holder6.isMCNodeLocal();
+    }
+
+    /**
+     * Utility routine to check if the multicast address has link scope.
+     *
+     * @return a {@code boolean} indicating if the address has is a multicast
+     *         address of link-local scope, false if it is not of link-local
+     *         scope or it is not a multicast address
+     *
+     * @since 1.4
+     */
+    @Override
+    public boolean isMCLinkLocal() {
+        return holder6.isMCLinkLocal();
+    }
+
+    /**
+     * Utility routine to check if the multicast address has site scope.
+     *
+     * @return a {@code boolean} indicating if the address has is a multicast
+     *         address of site-local scope, false if it is not  of site-local
+     *         scope or it is not a multicast address
+     *
+     * @since 1.4
+     */
+    @Override
+    public boolean isMCSiteLocal() {
+        return holder6.isMCSiteLocal();
+    }
+
+    /**
+     * Utility routine to check if the multicast address has organization scope.
+     *
+     * @return a {@code boolean} indicating if the address has is a multicast
+     *         address of organization-local scope, false if it is not of
+     *         organization-local scope or it is not a multicast address
+     *
+     * @since 1.4
+     */
+    @Override
+    public boolean isMCOrgLocal() {
+        return holder6.isMCOrgLocal();
+    }
+    /**
+     * Returns the raw IP address of this {@code InetAddress} object. The result
+     * is in network byte order: the highest order byte of the address is in
+     * {@code getAddress()[0]}.
+     *
+     * @return  the raw IP address of this object.
+     */
+    @Override
+    public byte[] getAddress() {
+        return holder6.ipaddress.clone();
+    }
+
+    /**
+     * Returns the numeric scopeId, if this instance is associated with
+     * an interface. If no scoped_id is set, the returned value is zero.
+     *
+     * @return the scopeId, or zero if not set.
+     *
+     * @since 1.5
+     */
+     public int getScopeId() {
+        return holder6.scope_id;
+     }
+
+    /**
+     * Returns the scoped interface, if this instance was created with
+     * with a scoped interface.
+     *
+     * @return the scoped interface, or null if not set.
+     * @since 1.5
+     */
+     public NetworkInterface getScopedInterface() {
+        return holder6.scope_ifname;
+     }
+
+    /**
+     * Returns the IP address string in textual presentation. If the instance
+     * was created specifying a scope identifier then the scope id is appended
+     * to the IP address preceded by a "%" (per-cent) character. This can be
+     * either a numeric value or a string, depending on which was used to create
+     * the instance.
+     *
+     * @return  the raw IP address in a string format.
+     */
+    @Override
+    public String getHostAddress() {
+        // Android-changed: getnameinfo returns smarter representations than getHostAddress()
+        // return holder6.getHostAddress();
+        return Libcore.os.getnameinfo(this, NI_NUMERICHOST); // Can't throw.
+    }
+
+    /**
+     * Returns a hashcode for this IP address.
+     *
+     * @return  a hash code value for this IP address.
+     */
+    @Override
+    public int hashCode() {
+        return holder6.hashCode();
+    }
+
+    /**
+     * Compares this object against the specified object. The result is {@code
+     * true} if and only if the argument is not {@code null} and it represents
+     * the same IP address as this object.
+     *
+     * <p> Two instances of {@code InetAddress} represent the same IP address
+     * if the length of the byte arrays returned by {@code getAddress} is the
+     * same for both, and each of the array components is the same for the byte
+     * arrays.
+     *
+     * @param   obj   the object to compare against.
+     *
+     * @return  {@code true} if the objects are the same; {@code false} otherwise.
+     *
+     * @see     java.net.InetAddress#getAddress()
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null || !(obj instanceof Inet6Address))
+            return false;
+
+        Inet6Address inetAddr = (Inet6Address)obj;
+
+        return holder6.equals(inetAddr.holder6);
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is an
+     * IPv4 compatible IPv6 address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is an IPv4
+     *         compatible IPv6 address; or false if address is IPv4 address.
+     *
+     * @since 1.4
+     */
+    public boolean isIPv4CompatibleAddress() {
+        return holder6.isIPv4CompatibleAddress();
+    }
+
+    // Utilities
+    private final static int INT16SZ = 2;
+
+    /*
+     * Convert IPv6 binary address into presentation (printable) format.
+     *
+     * @param src a byte array representing the IPv6 numeric address
+     * @return a String representing an IPv6 address in
+     *         textual representation format
+     * @since 1.4
+     */
+    static String numericToTextFormat(byte[] src) {
+        StringBuilder sb = new StringBuilder(39);
+        for (int i = 0; i < (INADDRSZ / INT16SZ); i++) {
+            sb.append(Integer.toHexString(((src[i<<1]<<8) & 0xff00)
+                                          | (src[(i<<1)+1] & 0xff)));
+            if (i < (INADDRSZ / INT16SZ) -1 ) {
+               sb.append(":");
+            }
+        }
+        return sb.toString();
+    }
+
+    // BEGIN Android-removed: Android doesn't need to call native init
+    /*
+     * Perform class load-time initializations.
+     *
+    private static native void init();
+    */
+    // END Android-removed: Android doesn't need to call native init
+}
diff --git a/java/net/Inet6AddressImpl.java b/java/net/Inet6AddressImpl.java
new file mode 100644
index 0000000..84bcf17
--- /dev/null
+++ b/java/net/Inet6AddressImpl.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+import android.system.ErrnoException;
+import android.system.GaiException;
+import android.system.StructAddrinfo;
+import android.system.IcmpHeaders;
+
+import dalvik.system.BlockGuard;
+
+import libcore.io.IoBridge;
+import libcore.io.Libcore;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import libcore.net.InetAddressUtils;
+
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.AF_UNSPEC;
+import static android.system.OsConstants.AI_ADDRCONFIG;
+import static android.system.OsConstants.EACCES;
+import static android.system.OsConstants.ECONNREFUSED;
+import static android.system.OsConstants.EPERM;
+import static android.system.OsConstants.NI_NAMEREQD;
+import static android.system.OsConstants.ICMP6_ECHO_REPLY;
+import static android.system.OsConstants.ICMP_ECHOREPLY;
+import static android.system.OsConstants.IPPROTO_ICMP;
+import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOCK_STREAM;
+
+// Android-note: Android-specific behavior and Linux-based implementation
+// http://b/36933260 Implement root-less ICMP for isReachable()
+// http://b/28609551 Rewrite getHostByAddr0 using POSIX library Libcore.os.
+// http://b/25861497 Add BlockGuard checks.
+// http://b/26700324 Fix odd dependency chains of the static InetAddress.
+// anyLocalAddress() Let anyLocalAddress() always return an IPv6 address.
+// Let loopbackAddresses() return both Inet4 and Inet6 loopbacks.
+// Rewrote hostname lookup methods on top of Libcore.os. Merge implementation from InetAddress
+//   and remove native methods in this class
+/*
+ * Package private implementation of InetAddressImpl for dual
+ * IPv4/IPv6 stack. {@code #anyLocalAddress()} will always return an IPv6 address.
+ *
+ * @since 1.4
+ */
+
+class Inet6AddressImpl implements InetAddressImpl {
+
+    // @GuardedBy(Inet6AddressImpl.class)
+    private static InetAddress anyLocalAddress;
+    // @GuardedBy(Inet6AddressImpl.class)
+    private static InetAddress[] loopbackAddresses;
+
+    private static final AddressCache addressCache = new AddressCache();
+
+    // BEGIN Android-changed: Rewrote hostname lookup methods on top of Libcore.os.
+    /*
+    public native String getLocalHostName() throws UnknownHostException;
+    public native InetAddress[]
+        lookupAllHostAddr(String hostname) throws UnknownHostException;
+    public native String getHostByAddr(byte[] addr) throws UnknownHostException;
+    private native boolean isReachable0(byte[] addr, int scope, int timeout, byte[] inf, int ttl, int if_scope) throws IOException;
+    */
+    @Override
+    public InetAddress[] lookupAllHostAddr(String host, int netId) throws UnknownHostException {
+        if (host == null || host.isEmpty()) {
+            // Android-changed: Return both the Inet4 and Inet6 loopback addresses
+            // when host == null or empty.
+            return loopbackAddresses();
+        }
+
+        // Is it a numeric address?
+        InetAddress result = InetAddressUtils.parseNumericAddressNoThrowStripOptionalBrackets(host);
+        if (result != null) {
+            return new InetAddress[] { result };
+        }
+
+        return lookupHostByName(host, netId);
+    }
+
+    /**
+     * Resolves a hostname to its IP addresses using a cache.
+     *
+     * @param host the hostname to resolve.
+     * @param netId the network to perform resolution upon.
+     * @return the IP addresses of the host.
+     */
+    private static InetAddress[] lookupHostByName(String host, int netId)
+            throws UnknownHostException {
+        BlockGuard.getThreadPolicy().onNetwork();
+        // Do we have a result cached?
+        Object cachedResult = addressCache.get(host, netId);
+        if (cachedResult != null) {
+            if (cachedResult instanceof InetAddress[]) {
+                // A cached positive result.
+                return (InetAddress[]) cachedResult;
+            } else {
+                // A cached negative result.
+                throw new UnknownHostException((String) cachedResult);
+            }
+        }
+        try {
+            StructAddrinfo hints = new StructAddrinfo();
+            hints.ai_flags = AI_ADDRCONFIG;
+            hints.ai_family = AF_UNSPEC;
+            // If we don't specify a socket type, every address will appear twice, once
+            // for SOCK_STREAM and one for SOCK_DGRAM. Since we do not return the family
+            // anyway, just pick one.
+            hints.ai_socktype = SOCK_STREAM;
+            InetAddress[] addresses = Libcore.os.android_getaddrinfo(host, hints, netId);
+            // TODO: should getaddrinfo set the hostname of the InetAddresses it returns?
+            for (InetAddress address : addresses) {
+                address.holder().hostName = host;
+                address.holder().originalHostName = host;
+            }
+            addressCache.put(host, netId, addresses);
+            return addresses;
+        } catch (GaiException gaiException) {
+            // If the failure appears to have been a lack of INTERNET permission, throw a clear
+            // SecurityException to aid in debugging this common mistake.
+            // http://code.google.com/p/android/issues/detail?id=15722
+            if (gaiException.getCause() instanceof ErrnoException) {
+                int errno = ((ErrnoException) gaiException.getCause()).errno;
+                if (errno == EACCES || errno == EPERM) {
+                    throw new SecurityException("Permission denied (missing INTERNET permission?)", gaiException);
+                }
+            }
+            // Otherwise, throw an UnknownHostException.
+            String detailMessage = "Unable to resolve host \"" + host + "\": " + Libcore.os.gai_strerror(gaiException.error);
+            addressCache.putUnknownHost(host, netId, detailMessage);
+            throw gaiException.rethrowAsUnknownHostException(detailMessage);
+        }
+    }
+
+    @Override
+    public String getHostByAddr(byte[] addr) throws UnknownHostException {
+        BlockGuard.getThreadPolicy().onNetwork();
+
+        return getHostByAddr0(addr);
+    }
+
+    @Override
+    public void clearAddressCache() {
+        addressCache.clear();
+    }
+    // END Android-changed: Rewrote hostname lookup methods on top of Libcore.os.
+
+    @Override
+    public boolean isReachable(InetAddress addr, int timeout, NetworkInterface netif, int ttl) throws IOException {
+        // Android-changed: rewritten on the top of IoBridge and Libcore.os.
+        InetAddress sourceAddr = null;
+        if (netif != null) {
+            /*
+             * Let's make sure we bind to an address of the proper family.
+             * Which means same family as addr because at this point it could
+             * be either an IPv6 address or an IPv4 address (case of a dual
+             * stack system).
+             */
+            java.util.Enumeration<InetAddress> it = netif.getInetAddresses();
+            InetAddress inetaddr = null;
+            while (it.hasMoreElements()) {
+                inetaddr = it.nextElement();
+                if (inetaddr.getClass().isInstance(addr)) {
+                    sourceAddr = inetaddr;
+                    break;
+                }
+            }
+
+            if (sourceAddr == null) {
+                // Interface doesn't support the address family of
+                // the destination
+                return false;
+            }
+        }
+
+        // Android-changed: http://b/36933260 Implement root-less ICMP for isReachable().
+        /*
+        if (addr instanceof Inet6Address)
+            scope = ((Inet6Address) addr).getScopeId();
+        return isReachable0(addr.getAddress(), scope, timeout, ifaddr, ttl, netif_scope);
+        */
+        // Try ICMP first
+        if (icmpEcho(addr, timeout, sourceAddr, ttl)) {
+            return true;
+        }
+
+        // No good, let's fall back to TCP
+        return tcpEcho(addr, timeout, sourceAddr, ttl);
+    }
+
+    // BEGIN Android-added: http://b/36933260 Implement root-less ICMP for isReachable().
+    private boolean tcpEcho(InetAddress addr, int timeout, InetAddress sourceAddr, int ttl)
+            throws IOException {
+        FileDescriptor fd = null;
+        try {
+            fd = IoBridge.socket(AF_INET6, SOCK_STREAM, 0);
+            if (ttl > 0) {
+                IoBridge.setSocketOption(fd, IoBridge.JAVA_IP_TTL, ttl);
+            }
+            if (sourceAddr != null) {
+                IoBridge.bind(fd, sourceAddr, 0);
+            }
+            IoBridge.connect(fd, addr, 7 /* Echo-protocol port */, timeout);
+            return true;
+        } catch (IOException e) {
+            // Connection refused by remote (ECONNREFUSED) implies reachable. Otherwise silently
+            // ignore the exception and return false.
+            Throwable cause = e.getCause();
+            return cause instanceof ErrnoException
+                    && ((ErrnoException) cause).errno == ECONNREFUSED;
+        } finally {
+            IoBridge.closeAndSignalBlockedThreads(fd);
+        }
+    }
+
+    protected boolean icmpEcho(InetAddress addr, int timeout, InetAddress sourceAddr, int ttl)
+            throws IOException {
+
+        FileDescriptor fd = null;
+        try {
+            boolean isIPv4 = addr instanceof Inet4Address;
+            int domain = isIPv4 ? AF_INET : AF_INET6;
+            int icmpProto = isIPv4 ? IPPROTO_ICMP : IPPROTO_ICMPV6;
+            fd = IoBridge.socket(domain, SOCK_DGRAM, icmpProto);
+
+            if (ttl > 0) {
+                IoBridge.setSocketOption(fd, IoBridge.JAVA_IP_TTL, ttl);
+            }
+            if (sourceAddr != null) {
+                IoBridge.bind(fd, sourceAddr, 0);
+            }
+
+            byte[] packet;
+
+            // ICMP is unreliable, try sending requests every second until timeout.
+            for (int to = timeout, seq = 1; to > 0; ++seq) {
+                int sockTo = to >= 1000 ? 1000 : to;
+
+                IoBridge.setSocketOption(fd, SocketOptions.SO_TIMEOUT, sockTo);
+
+                packet = IcmpHeaders.createIcmpEchoHdr(isIPv4, seq);
+                IoBridge.sendto(fd, packet, 0, packet.length, 0, addr, 0);
+                final int icmpId = IoBridge.getLocalInetSocketAddress(fd).getPort();
+
+                byte[] received = new byte[packet.length];
+                DatagramPacket receivedPacket = new DatagramPacket(received, packet.length);
+                int size = IoBridge
+                        .recvfrom(true, fd, received, 0, received.length, 0, receivedPacket, false);
+                if (size == packet.length) {
+                    byte expectedType = isIPv4 ? (byte) ICMP_ECHOREPLY
+                            : (byte) ICMP6_ECHO_REPLY;
+                    if (receivedPacket.getAddress().equals(addr)
+                            && received[0] == expectedType
+                            && received[4] == (byte) (icmpId >> 8)
+                            && received[5] == (byte) icmpId) {
+                        int receivedSequence = ((received[6] & 0xff) << 8) + (received[7] & 0xff);
+                        if (receivedSequence <= seq) {
+                            return true;
+                        }
+                    }
+                }
+                to -= sockTo;
+            }
+        } catch (IOException e) {
+            // Silently ignore and fall back.
+        } finally {
+            if (fd != null) {
+                try {
+                    Libcore.os.close(fd);
+                } catch (ErrnoException e) { }
+            }
+        }
+
+        return false;
+    }
+    // END Android-added: http://b/36933260 Implement root-less ICMP for isReachable().
+
+    // BEGIN Android-changed: Let anyLocalAddress() always return an IPv6 address.
+    @Override
+    public InetAddress anyLocalAddress() {
+        synchronized (Inet6AddressImpl.class) {
+            // We avoid initializing anyLocalAddress during <clinit> to avoid issues
+            // caused by the dependency chains of these classes. InetAddress depends on
+            // InetAddressImpl, but Inet6Address & Inet4Address are its subclasses.
+            // Also see {@code loopbackAddresses). http://b/26700324
+            if (anyLocalAddress == null) {
+                Inet6Address anyAddress = new Inet6Address();
+                anyAddress.holder().hostName = "::";
+                anyLocalAddress = anyAddress;
+            }
+
+            return anyLocalAddress;
+        }
+    }
+    // END Android-changed: Let anyLocalAddress() always return an IPv6 address.
+
+    // BEGIN Android-changed: Let loopbackAddresses() return both Inet4 and Inet6 loopbacks.
+    @Override
+    public InetAddress[] loopbackAddresses() {
+        synchronized (Inet6AddressImpl.class) {
+            // We avoid initializing anyLocalAddress during <clinit> to avoid issues
+            // caused by the dependency chains of these classes. InetAddress depends on
+            // InetAddressImpl, but Inet6Address & Inet4Address are its subclasses.
+            // Also see {@code anyLocalAddress).
+            if (loopbackAddresses == null) {
+                loopbackAddresses = new InetAddress[]{Inet6Address.LOOPBACK, Inet4Address.LOOPBACK};
+            }
+
+            return loopbackAddresses;
+        }
+    }
+    // END Android-changed: Let loopbackAddresses() return both Inet4 and Inet6 loopbacks.
+
+    // BEGIN Android-changed: b/28609551 Rewrite getHostByAddr0 using POSIX library Libcore.os.
+    private String getHostByAddr0(byte[] addr) throws UnknownHostException {
+        // Android-changed: Rewritten on the top of Libcore.os
+        InetAddress hostaddr = InetAddress.getByAddress(addr);
+        try {
+            return Libcore.os.getnameinfo(hostaddr, NI_NAMEREQD);
+        } catch (GaiException e) {
+            UnknownHostException uhe = new UnknownHostException(hostaddr.toString());
+            uhe.initCause(e);
+            throw uhe;
+        }
+    }
+    // END Android-changed: b/28609551 Rewrite getHostByAddr0 using POSIX library Libcore.os.
+}
diff --git a/java/net/InetAddress.annotated.java b/java/net/InetAddress.annotated.java
new file mode 100644
index 0000000..6f4492d
--- /dev/null
+++ b/java/net/InetAddress.annotated.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.net;
+
+import java.io.ObjectStreamException;
+import java.io.IOException;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class InetAddress implements java.io.Serializable {
+
+InetAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isMulticastAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isAnyLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isLoopbackAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isLinkLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isSiteLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCGlobal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCNodeLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCLinkLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCSiteLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCOrgLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isReachable(int timeout) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public boolean isReachable(java.net.NetworkInterface netif, int ttl, int timeout) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public boolean isReachableByICMP(int timeout) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getHostName() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getCanonicalHostName() { throw new RuntimeException("Stub!"); }
+
+public byte[] getAddress() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getHostAddress() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public static java.net.InetAddress getByAddress(java.lang.String host, byte[] addr) throws java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+
+public static java.net.InetAddress getByName(java.lang.String host) throws java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+
+public static java.net.InetAddress[] getAllByName(java.lang.String host) throws java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+
+public static java.net.InetAddress getLoopbackAddress() { throw new RuntimeException("Stub!"); }
+
+public static java.net.InetAddress getByAddress(byte[] addr) throws java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+
+public static java.net.InetAddress getLocalHost() throws java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static boolean isNumeric(java.lang.String address) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static java.net.InetAddress parseNumericAddress(java.lang.String numericAddress) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static void clearDnsCache() { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static java.net.InetAddress getByNameOnNet(java.lang.String host, int netId) throws java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static java.net.InetAddress[] getAllByNameOnNet(java.lang.String host, int netId) throws java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/net/InetAddress.java b/java/net/InetAddress.java
new file mode 100644
index 0000000..e4f8660
--- /dev/null
+++ b/java/net/InetAddress.java
@@ -0,0 +1,1702 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.ObjectStreamException;
+import java.io.ObjectStreamField;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectInputStream.GetField;
+import java.io.ObjectOutputStream;
+import java.io.ObjectOutputStream.PutField;
+import libcore.net.InetAddressUtils;
+import sun.net.util.IPAddressUtil;
+import sun.net.spi.nameservice.*;
+import libcore.io.Libcore;
+
+/**
+ * This class represents an Internet Protocol (IP) address.
+ *
+ * <p> An IP address is either a 32-bit or 128-bit unsigned number
+ * used by IP, a lower-level protocol on which protocols like UDP and
+ * TCP are built. The IP address architecture is defined by <a
+ * href="http://www.ietf.org/rfc/rfc790.txt"><i>RFC&nbsp;790:
+ * Assigned Numbers</i></a>, <a
+ * href="http://www.ietf.org/rfc/rfc1918.txt"> <i>RFC&nbsp;1918:
+ * Address Allocation for Private Internets</i></a>, <a
+ * href="http://www.ietf.org/rfc/rfc2365.txt"><i>RFC&nbsp;2365:
+ * Administratively Scoped IP Multicast</i></a>, and <a
+ * href="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC&nbsp;2373: IP
+ * Version 6 Addressing Architecture</i></a>. An instance of an
+ * InetAddress consists of an IP address and possibly its
+ * corresponding host name (depending on whether it is constructed
+ * with a host name or whether it has already done reverse host name
+ * resolution).
+ *
+ * <h3> Address types </h3>
+ *
+ * <blockquote><table cellspacing=2 summary="Description of unicast and multicast address types">
+ *   <tr><th valign=top><i>unicast</i></th>
+ *       <td>An identifier for a single interface. A packet sent to
+ *         a unicast address is delivered to the interface identified by
+ *         that address.
+ *
+ *         <p> The Unspecified Address -- Also called anylocal or wildcard
+ *         address. It must never be assigned to any node. It indicates the
+ *         absence of an address. One example of its use is as the target of
+ *         bind, which allows a server to accept a client connection on any
+ *         interface, in case the server host has multiple interfaces.
+ *
+ *         <p> The <i>unspecified</i> address must not be used as
+ *         the destination address of an IP packet.
+ *
+ *         <p> The <i>Loopback</i> Addresses -- This is the address
+ *         assigned to the loopback interface. Anything sent to this
+ *         IP address loops around and becomes IP input on the local
+ *         host. This address is often used when testing a
+ *         client.</td></tr>
+ *   <tr><th valign=top><i>multicast</i></th>
+ *       <td>An identifier for a set of interfaces (typically belonging
+ *         to different nodes). A packet sent to a multicast address is
+ *         delivered to all interfaces identified by that address.</td></tr>
+ * </table></blockquote>
+ *
+ * <h4> IP address scope </h4>
+ *
+ * <p> <i>Link-local</i> addresses are designed to be used for addressing
+ * on a single link for purposes such as auto-address configuration,
+ * neighbor discovery, or when no routers are present.
+ *
+ * <p> <i>Site-local</i> addresses are designed to be used for addressing
+ * inside of a site without the need for a global prefix.
+ *
+ * <p> <i>Global</i> addresses are unique across the internet.
+ *
+ * <h4> Textual representation of IP addresses </h4>
+ *
+ * The textual representation of an IP address is address family specific.
+ *
+ * <p>
+ *
+ * For IPv4 address format, please refer to <A
+ * HREF="Inet4Address.html#format">Inet4Address#format</A>; For IPv6
+ * address format, please refer to <A
+ * HREF="Inet6Address.html#format">Inet6Address#format</A>.
+ *
+ * <P>There is a <a href="doc-files/net-properties.html#Ipv4IPv6">couple of
+ * System Properties</a> affecting how IPv4 and IPv6 addresses are used.</P>
+ *
+ * <h4> Host Name Resolution </h4>
+ *
+ * Host name-to-IP address <i>resolution</i> is accomplished through
+ * the use of a combination of local machine configuration information
+ * and network naming services such as the Domain Name System (DNS)
+ * and Network Information Service(NIS). The particular naming
+ * services(s) being used is by default the local machine configured
+ * one. For any host name, its corresponding IP address is returned.
+ *
+ * <p> <i>Reverse name resolution</i> means that for any IP address,
+ * the host associated with the IP address is returned.
+ *
+ * <p> The InetAddress class provides methods to resolve host names to
+ * their IP addresses and vice versa.
+ *
+ * <h4> InetAddress Caching </h4>
+ *
+ * The InetAddress class has a cache to store successful as well as
+ * unsuccessful host name resolutions.
+ *
+ * <p> By default, when a security manager is installed, in order to
+ * protect against DNS spoofing attacks,
+ * the result of positive host name resolutions are
+ * cached forever. When a security manager is not installed, the default
+ * behavior is to cache entries for a finite (implementation dependent)
+ * period of time. The result of unsuccessful host
+ * name resolution is cached for a very short period of time (10
+ * seconds) to improve performance.
+ *
+ * <p> If the default behavior is not desired, then a Java security property
+ * can be set to a different Time-to-live (TTL) value for positive
+ * caching. Likewise, a system admin can configure a different
+ * negative caching TTL value when needed.
+ *
+ * <p> Two Java security properties control the TTL values used for
+ *  positive and negative host name resolution caching:
+ *
+ * <blockquote>
+ * <dl>
+ * <dt><b>networkaddress.cache.ttl</b></dt>
+ * <dd>Indicates the caching policy for successful name lookups from
+ * the name service. The value is specified as as integer to indicate
+ * the number of seconds to cache the successful lookup. The default
+ * setting is to cache for an implementation specific period of time.
+ * <p>
+ * A value of -1 indicates "cache forever".
+ * </dd>
+ * <dt><b>networkaddress.cache.negative.ttl</b> (default: 10)</dt>
+ * <dd>Indicates the caching policy for un-successful name lookups
+ * from the name service. The value is specified as as integer to
+ * indicate the number of seconds to cache the failure for
+ * un-successful lookups.
+ * <p>
+ * A value of 0 indicates "never cache".
+ * A value of -1 indicates "cache forever".
+ * </dd>
+ * </dl>
+ * </blockquote>
+ *
+ * @author  Chris Warth
+ * @see     java.net.InetAddress#getByAddress(byte[])
+ * @see     java.net.InetAddress#getByAddress(java.lang.String, byte[])
+ * @see     java.net.InetAddress#getAllByName(java.lang.String)
+ * @see     java.net.InetAddress#getByName(java.lang.String)
+ * @see     java.net.InetAddress#getLocalHost()
+ * @since JDK1.0
+ */
+public
+class InetAddress implements java.io.Serializable {
+    // BEGIN Android-removed: Android uses linux-based OsConstants.
+    /*
+     * Specify the address family: Internet Protocol, Version 4
+     * @since 1.4
+     *
+    static final int IPv4 = 1;
+
+    /**
+     * Specify the address family: Internet Protocol, Version 6
+     * @since 1.4
+     *
+    static final int IPv6 = 2;
+    */
+    // END Android-removed: Android uses linux-based OsConstants.
+
+    // Android-removed: Android doesn't support the preference.
+    // /* Specify address family preference */
+    //static transient boolean preferIPv6Address = false;
+
+    static class InetAddressHolder {
+        /**
+         * Reserve the original application specified hostname.
+         *
+         * The original hostname is useful for domain-based endpoint
+         * identification (see RFC 2818 and RFC 6125).  If an address
+         * was created with a raw IP address, a reverse name lookup
+         * may introduce endpoint identification security issue via
+         * DNS forging.
+         *
+         * Oracle JSSE provider is using this original hostname, via
+         * sun.misc.JavaNetAccess, for SSL/TLS endpoint identification.
+         *
+         * Note: May define a new public method in the future if necessary.
+         */
+        String originalHostName;
+
+        InetAddressHolder() {}
+
+        InetAddressHolder(String hostName, int address, int family) {
+            this.originalHostName = hostName;
+            this.hostName = hostName;
+            this.address = address;
+            this.family = family;
+        }
+
+        void init(String hostName, int family) {
+            this.originalHostName = hostName;
+            this.hostName = hostName;
+            if (family != -1) {
+                this.family = family;
+            }
+        }
+
+        String hostName;
+
+        String getHostName() {
+            return hostName;
+        }
+
+        String getOriginalHostName() {
+            return originalHostName;
+        }
+
+        /**
+         * Holds a 32-bit IPv4 address.
+         */
+        int address;
+
+        int getAddress() {
+            return address;
+        }
+
+        // Android-changed: Documentation: use Linux-based OsConstants.
+        /**
+         * Specifies the address family type, for instance, AF_INET for IPv4
+         * addresses, and AF_INET6 for IPv6 addresses.
+         */
+        int family;
+
+        int getFamily() {
+            return family;
+        }
+    }
+
+    transient InetAddressHolder holder;
+
+    InetAddressHolder holder() {
+        return holder;
+    }
+
+    /* The implementation is always dual stack IPv6/IPv4 on android */
+    static final InetAddressImpl impl = new Inet6AddressImpl();
+
+    /* Used to store the name service provider */
+    // Android-changed: Android has only one name service.
+    // Android doesn't allow user to provide custom name services.
+    // private static List<NameService> nameServices = null;
+    private static final NameService nameService = new NameService() {
+        public InetAddress[] lookupAllHostAddr(String host, int netId)
+                throws UnknownHostException {
+            return impl.lookupAllHostAddr(host, netId);
+        }
+        public String getHostByAddr(byte[] addr)
+                throws UnknownHostException {
+            return impl.getHostByAddr(addr);
+        }
+    };
+
+    /* Used to store the best available hostname */
+    private transient String canonicalHostName = null;
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    private static final long serialVersionUID = 3286316764910316507L;
+
+
+    // BEGIN Android-removed: Android doesn't need to load native library.
+    /*
+     * Load net library into runtime, and perform initializations.
+     *
+    static {
+        preferIPv6Address = java.security.AccessController.doPrivileged(
+            new GetBooleanAction("java.net.preferIPv6Addresses")).booleanValue();
+        AccessController.doPrivileged(
+            new java.security.PrivilegedAction<Void>() {
+                public Void run() {
+                    System.loadLibrary("net");
+                    return null;
+                }
+            });
+        init();
+    }
+    */
+    // END Android-removed: Android doesn't need to load native library.
+
+    /**
+     * Constructor for the Socket.accept() method.
+     * This creates an empty InetAddress, which is filled in by
+     * the accept() method.  This InetAddress, however, is not
+     * put in the address cache, since it is not created by name.
+     */
+    InetAddress() {
+        holder = new InetAddressHolder();
+    }
+
+    /**
+     * Replaces the de-serialized object with an Inet4Address object.
+     *
+     * @return the alternate object to the de-serialized object.
+     *
+     * @throws ObjectStreamException if a new object replacing this
+     * object could not be created
+     */
+    private Object readResolve() throws ObjectStreamException {
+        // will replace the deserialized 'this' object
+        return new Inet4Address(holder().getHostName(), holder().getAddress());
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is an
+     * IP multicast address.
+     * @return a {@code boolean} indicating if the InetAddress is
+     * an IP multicast address
+     * @since   JDK1.1
+     */
+    public boolean isMulticastAddress() {
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the InetAddress in a wildcard address.
+     * @return a {@code boolean} indicating if the Inetaddress is
+     *         a wildcard address.
+     * @since 1.4
+     */
+    public boolean isAnyLocalAddress() {
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is a loopback address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is
+     * a loopback address; or false otherwise.
+     * @since 1.4
+     */
+    public boolean isLoopbackAddress() {
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is an link local address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is
+     * a link local address; or false if address is not a link local unicast address.
+     * @since 1.4
+     */
+    public boolean isLinkLocalAddress() {
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is a site local address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is
+     * a site local address; or false if address is not a site local unicast address.
+     * @since 1.4
+     */
+    public boolean isSiteLocalAddress() {
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the multicast address has global scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of global scope, false if it is not
+     *         of global scope or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCGlobal() {
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the multicast address has node scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of node-local scope, false if it is not
+     *         of node-local scope or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCNodeLocal() {
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the multicast address has link scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of link-local scope, false if it is not
+     *         of link-local scope or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCLinkLocal() {
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the multicast address has site scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of site-local scope, false if it is not
+     *         of site-local scope or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCSiteLocal() {
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the multicast address has organization scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of organization-local scope,
+     *         false if it is not of organization-local scope
+     *         or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCOrgLocal() {
+        return false;
+    }
+
+
+    // Android-changed: Document that impl tries ICMP ECHO REQUESTs first.
+    // The sole implementation, Inet6AddressImpl.isReachable(), tries ICMP ECHO REQUESTs before
+    // TCP ECHO REQUESTs on Android. On Android, these are both possible without root access.
+    /**
+     * Test whether that address is reachable. Best effort is made by the
+     * implementation to try to reach the host, but firewalls and server
+     * configuration may block requests resulting in a unreachable status
+     * while some specific ports may be accessible.
+     * <p>
+     * Android implementation attempts ICMP ECHO REQUESTs first, on failure it
+     * will fall back to TCP ECHO REQUESTs. Success on either protocol will
+     * return true.
+     * <p>
+     * The timeout value, in milliseconds, indicates the maximum amount of time
+     * the try should take. If the operation times out before getting an
+     * answer, the host is deemed unreachable. A negative value will result
+     * in an IllegalArgumentException being thrown.
+     *
+     * @param   timeout the time, in milliseconds, before the call aborts
+     * @return a {@code boolean} indicating if the address is reachable.
+     * @throws IOException if a network error occurs
+     * @throws  IllegalArgumentException if {@code timeout} is negative.
+     * @since 1.5
+     */
+    public boolean isReachable(int timeout) throws IOException {
+        return isReachable(null, 0 , timeout);
+    }
+
+    // Android-changed: Document that impl tries ICMP ECHO REQUESTs first.
+    // The sole implementation, Inet6AddressImpl.isReachable(), tries ICMP ECHO REQUESTs before
+    // TCP ECHO REQUESTs on Android. On Android, these are both possible without root access.
+    /**
+     * Test whether that address is reachable. Best effort is made by the
+     * implementation to try to reach the host, but firewalls and server
+     * configuration may block requests resulting in a unreachable status
+     * while some specific ports may be accessible.
+     * <p>
+     * Android implementation attempts ICMP ECHO REQUESTs first, on failure it
+     * will fall back to TCP ECHO REQUESTs. Success on either protocol will
+     * return true.
+     * <p>
+     * The {@code network interface} and {@code ttl} parameters
+     * let the caller specify which network interface the test will go through
+     * and the maximum number of hops the packets should go through.
+     * A negative value for the {@code ttl} will result in an
+     * IllegalArgumentException being thrown.
+     * <p>
+     * The timeout value, in milliseconds, indicates the maximum amount of time
+     * the try should take. If the operation times out before getting an
+     * answer, the host is deemed unreachable. A negative value will result
+     * in an IllegalArgumentException being thrown.
+     *
+     * @param   netif   the NetworkInterface through which the
+     *                    test will be done, or null for any interface
+     * @param   ttl     the maximum numbers of hops to try or 0 for the
+     *                  default
+     * @param   timeout the time, in milliseconds, before the call aborts
+     * @throws  IllegalArgumentException if either {@code timeout}
+     *                          or {@code ttl} are negative.
+     * @return a {@code boolean}indicating if the address is reachable.
+     * @throws IOException if a network error occurs
+     * @since 1.5
+     */
+    public boolean isReachable(NetworkInterface netif, int ttl,
+                               int timeout) throws IOException {
+        if (ttl < 0)
+            throw new IllegalArgumentException("ttl can't be negative");
+        if (timeout < 0)
+            throw new IllegalArgumentException("timeout can't be negative");
+
+        return impl.isReachable(this, timeout, netif, ttl);
+    }
+
+    // BEGIN Android-added: isReachableByICMP(timeout).
+    /**
+     * @hide For testing only
+     */
+    public boolean isReachableByICMP(int timeout) throws IOException {
+        return ((Inet6AddressImpl) impl).icmpEcho(this, timeout, null, 0);
+    }
+    // END Android-added: isReachableByICMP(timeout).
+
+    /**
+     * Gets the host name for this IP address.
+     *
+     * <p>If this InetAddress was created with a host name,
+     * this host name will be remembered and returned;
+     * otherwise, a reverse name lookup will be performed
+     * and the result will be returned based on the system
+     * configured name lookup service. If a lookup of the name service
+     * is required, call
+     * {@link #getCanonicalHostName() getCanonicalHostName}.
+     *
+     * <p>If there is a security manager, its
+     * {@code checkConnect} method is first called
+     * with the hostname and {@code -1}
+     * as its arguments to see if the operation is allowed.
+     * If the operation is not allowed, it will return
+     * the textual representation of the IP address.
+     *
+     * @return  the host name for this IP address, or if the operation
+     *    is not allowed by the security check, the textual
+     *    representation of the IP address.
+     *
+     * @see InetAddress#getCanonicalHostName
+     * @see SecurityManager#checkConnect
+     */
+    public String getHostName() {
+        // Android-changed: Remove SecurityManager check.
+        if (holder().getHostName() == null) {
+            holder().hostName = InetAddress.getHostFromNameService(this);
+        }
+        return holder().getHostName();
+    }
+
+    // BEGIN Android-removed: Android doesn't support SecurityManager.
+    /*
+     * Returns the hostname for this address.
+     * If the host is equal to null, then this address refers to any
+     * of the local machine's available network addresses.
+     * this is package private so SocketPermission can make calls into
+     * here without a security check.
+     *
+     * <p>If there is a security manager, this method first
+     * calls its {@code checkConnect} method
+     * with the hostname and {@code -1}
+     * as its arguments to see if the calling code is allowed to know
+     * the hostname for this IP address, i.e., to connect to the host.
+     * If the operation is not allowed, it will return
+     * the textual representation of the IP address.
+     *
+     * @return  the host name for this IP address, or if the operation
+     *    is not allowed by the security check, the textual
+     *    representation of the IP address.
+     *
+     * @param check make security check if true
+     *
+     * @see SecurityManager#checkConnect
+     *
+    String getHostName(boolean check) {
+        if (holder().getHostName() == null) {
+            holder().hostName = InetAddress.getHostFromNameService(this, check);
+        }
+        return holder().getHostName();
+    }
+    */
+    // END Android-removed: Android doesn't support SecurityManager.
+
+    /**
+     * Gets the fully qualified domain name for this IP address.
+     * Best effort method, meaning we may not be able to return
+     * the FQDN depending on the underlying system configuration.
+     *
+     * <p>If there is a security manager, this method first
+     * calls its {@code checkConnect} method
+     * with the hostname and {@code -1}
+     * as its arguments to see if the calling code is allowed to know
+     * the hostname for this IP address, i.e., to connect to the host.
+     * If the operation is not allowed, it will return
+     * the textual representation of the IP address.
+     *
+     * @return  the fully qualified domain name for this IP address,
+     *    or if the operation is not allowed by the security check,
+     *    the textual representation of the IP address.
+     *
+     * @see SecurityManager#checkConnect
+     *
+     * @since 1.4
+     */
+    public String getCanonicalHostName() {
+        // Android-changed: Remove SecurityManager check.
+        if (canonicalHostName == null) {
+            canonicalHostName = InetAddress.getHostFromNameService(this);
+        }
+        return canonicalHostName;
+    }
+
+    // Android-changed: Remove SecurityManager check.
+    // * @param check make security check if true
+    /**
+     * Returns the hostname for this address.
+     *
+     * <p>If there is a security manager, this method first
+     * calls its {@code checkConnect} method
+     * with the hostname and {@code -1}
+     * as its arguments to see if the calling code is allowed to know
+     * the hostname for this IP address, i.e., to connect to the host.
+     * If the operation is not allowed, it will return
+     * the textual representation of the IP address.
+     *
+     * @return  the host name for this IP address, or if the operation
+     *    is not allowed by the security check, the textual
+     *    representation of the IP address.
+     *
+     * @see SecurityManager#checkConnect
+     */
+    private static String getHostFromNameService(InetAddress addr) {
+        String host = null;
+        try {
+            // first lookup the hostname
+            // Android-changed: Android has only one name service.
+            host = nameService.getHostByAddr(addr.getAddress());
+
+                /* now get all the IP addresses for this hostname,
+                 * and make sure one of them matches the original IP
+                 * address. We do this to try and prevent spoofing.
+                 */
+            InetAddress[] arr = nameService.lookupAllHostAddr(host, NETID_UNSET);
+            boolean ok = false;
+
+            if (arr != null) {
+                for(int i = 0; !ok && i < arr.length; i++) {
+                    ok = addr.equals(arr[i]);
+                }
+            }
+
+            //XXX: if it looks a spoof just return the address?
+            if (!ok) {
+                host = addr.getHostAddress();
+                return host;
+            }
+        } catch (UnknownHostException e) {
+            host = addr.getHostAddress();
+        }
+
+        return host;
+    }
+
+    /**
+     * Returns the raw IP address of this {@code InetAddress}
+     * object. The result is in network byte order: the highest order
+     * byte of the address is in {@code getAddress()[0]}.
+     *
+     * @return  the raw IP address of this object.
+     */
+    public byte[] getAddress() {
+        return null;
+    }
+
+    /**
+     * Returns the IP address string in textual presentation.
+     *
+     * @return  the raw IP address in a string format.
+     * @since   JDK1.0.2
+     */
+    public String getHostAddress() {
+        return null;
+     }
+
+    /**
+     * Returns a hashcode for this IP address.
+     *
+     * @return  a hash code value for this IP address.
+     */
+    public int hashCode() {
+        return -1;
+    }
+
+    /**
+     * Compares this object against the specified object.
+     * The result is {@code true} if and only if the argument is
+     * not {@code null} and it represents the same IP address as
+     * this object.
+     * <p>
+     * Two instances of {@code InetAddress} represent the same IP
+     * address if the length of the byte arrays returned by
+     * {@code getAddress} is the same for both, and each of the
+     * array components is the same for the byte arrays.
+     *
+     * @param   obj   the object to compare against.
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     * @see     java.net.InetAddress#getAddress()
+     */
+    public boolean equals(Object obj) {
+        return false;
+    }
+
+    /**
+     * Converts this IP address to a {@code String}. The
+     * string returned is of the form: hostname / literal IP
+     * address.
+     *
+     * If the host name is unresolved, no reverse name service lookup
+     * is performed. The hostname part will be represented by an empty string.
+     *
+     * @return  a string representation of this IP address.
+     */
+    public String toString() {
+        String hostName = holder().getHostName();
+        return ((hostName != null) ? hostName : "")
+            + "/" + getHostAddress();
+    }
+
+    // BEGIN Android-removed: Resolves a hostname using Libcore.os.
+    /*
+     * Cached addresses - our own litle nis, not!
+     *
+    private static Cache addressCache = new Cache(Cache.Type.Positive);
+
+    private static Cache negativeCache = new Cache(Cache.Type.Negative);
+
+    private static boolean addressCacheInit = false;
+
+    static InetAddress[]    unknown_array; // put THIS in cache
+
+    static InetAddressImpl  impl;
+
+    private static final HashMap<String, Void> lookupTable = new HashMap<>();
+
+    /**
+     * Represents a cache entry
+     *
+    static final class CacheEntry {
+
+        CacheEntry(InetAddress[] addresses, long expiration) {
+            this.addresses = addresses;
+            this.expiration = expiration;
+        }
+
+        InetAddress[] addresses;
+        long expiration;
+    }
+
+    /**
+     * A cache that manages entries based on a policy specified
+     * at creation time.
+     *
+    static final class Cache {
+        private LinkedHashMap<String, CacheEntry> cache;
+        private Type type;
+
+        enum Type {Positive, Negative};
+
+        /**
+         * Create cache
+         *
+        public Cache(Type type) {
+            this.type = type;
+            cache = new LinkedHashMap<String, CacheEntry>();
+        }
+
+        private int getPolicy() {
+            if (type == Type.Positive) {
+                return InetAddressCachePolicy.get();
+            } else {
+                return InetAddressCachePolicy.getNegative();
+            }
+        }
+
+        /**
+         * Add an entry to the cache. If there's already an
+         * entry then for this host then the entry will be
+         * replaced.
+         *
+        public Cache put(String host, InetAddress[] addresses) {
+            int policy = getPolicy();
+            if (policy == InetAddressCachePolicy.NEVER) {
+                return this;
+            }
+
+            // purge any expired entries
+
+            if (policy != InetAddressCachePolicy.FOREVER) {
+
+                // As we iterate in insertion order we can
+                // terminate when a non-expired entry is found.
+                LinkedList<String> expired = new LinkedList<>();
+                long now = System.currentTimeMillis();
+                for (String key : cache.keySet()) {
+                    CacheEntry entry = cache.get(key);
+
+                    if (entry.expiration >= 0 && entry.expiration < now) {
+                        expired.add(key);
+                    } else {
+                        break;
+                    }
+                }
+
+                for (String key : expired) {
+                    cache.remove(key);
+                }
+            }
+
+            // create new entry and add it to the cache
+            // -- as a HashMap replaces existing entries we
+            //    don't need to explicitly check if there is
+            //    already an entry for this host.
+            long expiration;
+            if (policy == InetAddressCachePolicy.FOREVER) {
+                expiration = -1;
+            } else {
+                expiration = System.currentTimeMillis() + (policy * 1000);
+            }
+            CacheEntry entry = new CacheEntry(addresses, expiration);
+            cache.put(host, entry);
+            return this;
+        }
+
+        /**
+         * Query the cache for the specific host. If found then
+         * return its CacheEntry, or null if not found.
+         *
+        public CacheEntry get(String host) {
+            int policy = getPolicy();
+            if (policy == InetAddressCachePolicy.NEVER) {
+                return null;
+            }
+            CacheEntry entry = cache.get(host);
+
+            // check if entry has expired
+            if (entry != null && policy != InetAddressCachePolicy.FOREVER) {
+                if (entry.expiration >= 0 &&
+                        entry.expiration < System.currentTimeMillis()) {
+                    cache.remove(host);
+                    entry = null;
+                }
+            }
+
+            return entry;
+        }
+    }
+
+    /*
+     * Initialize cache and insert anyLocalAddress into the
+     * unknown array with no expiry.
+     *
+    private static void cacheInitIfNeeded() {
+        assert Thread.holdsLock(addressCache);
+        if (addressCacheInit) {
+            return;
+        }
+        unknown_array = new InetAddress[1];
+        unknown_array[0] = impl.anyLocalAddress();
+
+        addressCache.put(impl.anyLocalAddress().getHostName(),
+                         unknown_array);
+
+        addressCacheInit = true;
+    }
+
+    /*
+     * Cache the given hostname and addresses.
+     *
+    private static void cacheAddresses(String hostname,
+                                       InetAddress[] addresses,
+                                       boolean success) {
+        hostname = hostname.toLowerCase();
+        synchronized (addressCache) {
+            cacheInitIfNeeded();
+            if (success) {
+                addressCache.put(hostname, addresses);
+            } else {
+                negativeCache.put(hostname, addresses);
+            }
+        }
+    }
+
+    /*
+     * Lookup hostname in cache (positive & negative cache). If
+     * found return addresses, null if not found.
+     *
+    private static InetAddress[] getCachedAddresses(String hostname) {
+        hostname = hostname.toLowerCase();
+
+        // search both positive & negative caches
+
+        synchronized (addressCache) {
+            cacheInitIfNeeded();
+
+            CacheEntry entry = addressCache.get(hostname);
+            if (entry == null) {
+                entry = negativeCache.get(hostname);
+            }
+
+            if (entry != null) {
+                return entry.addresses;
+            }
+        }
+
+        // not found
+        return null;
+    }
+
+    private static NameService createNSProvider(String provider) {
+        if (provider == null)
+            return null;
+
+        NameService nameService = null;
+        if (provider.equals("default")) {
+            // initialize the default name service
+            nameService = new NameService() {
+                public InetAddress[] lookupAllHostAddr(String host)
+                    throws UnknownHostException {
+                    return impl.lookupAllHostAddr(host);
+                }
+                public String getHostByAddr(byte[] addr)
+                    throws UnknownHostException {
+                    return impl.getHostByAddr(addr);
+                }
+            };
+        } else {
+            final String providerName = provider;
+            try {
+                nameService = java.security.AccessController.doPrivileged(
+                    new java.security.PrivilegedExceptionAction<NameService>() {
+                        public NameService run() {
+                            Iterator<NameServiceDescriptor> itr =
+                                ServiceLoader.load(NameServiceDescriptor.class)
+                                    .iterator();
+                            while (itr.hasNext()) {
+                                NameServiceDescriptor nsd = itr.next();
+                                if (providerName.
+                                    equalsIgnoreCase(nsd.getType()+","
+                                        +nsd.getProviderName())) {
+                                    try {
+                                        return nsd.createNameService();
+                                    } catch (Exception e) {
+                                        e.printStackTrace();
+                                        System.err.println(
+                                            "Cannot create name service:"
+                                             +providerName+": " + e);
+                                    }
+                                }
+                            }
+
+                            return null;
+                        }
+                    }
+                );
+            } catch (java.security.PrivilegedActionException e) {
+            }
+        }
+
+        return nameService;
+    }
+
+    static {
+        // create the impl
+        impl = InetAddressImplFactory.create();
+
+        // get name service if provided and requested
+        String provider = null;;
+        String propPrefix = "sun.net.spi.nameservice.provider.";
+        int n = 1;
+        nameServices = new ArrayList<NameService>();
+        provider = AccessController.doPrivileged(
+                new GetPropertyAction(propPrefix + n));
+        while (provider != null) {
+            NameService ns = createNSProvider(provider);
+            if (ns != null)
+                nameServices.add(ns);
+
+            n++;
+            provider = AccessController.doPrivileged(
+                    new GetPropertyAction(propPrefix + n));
+        }
+
+        // if not designate any name services provider,
+        // create a default one
+        if (nameServices.size() == 0) {
+            NameService ns = createNSProvider("default");
+            nameServices.add(ns);
+        }
+    }
+    */
+    // END Android-removed: Resolves a hostname using Libcore.os.
+
+    /**
+     * Creates an InetAddress based on the provided host name and IP address.
+     * No name service is checked for the validity of the address.
+     *
+     * <p> The host name can either be a machine name, such as
+     * "{@code java.sun.com}", or a textual representation of its IP
+     * address.
+     * <p> No validity checking is done on the host name either.
+     *
+     * <p> If addr specifies an IPv4 address an instance of Inet4Address
+     * will be returned; otherwise, an instance of Inet6Address
+     * will be returned.
+     *
+     * <p> IPv4 address byte array must be 4 bytes long and IPv6 byte array
+     * must be 16 bytes long
+     *
+     * @param host the specified host
+     * @param addr the raw IP address in network byte order
+     * @return  an InetAddress object created from the raw IP address.
+     * @exception  UnknownHostException  if IP address is of illegal length
+     * @since 1.4
+     */
+    public static InetAddress getByAddress(String host, byte[] addr) throws UnknownHostException {
+        return getByAddress(host, addr, -1 /* scopeId */);
+    }
+
+    // Android-added: Called by native code in Libcore.io.
+    // Do not delete. Called from native code.
+    private static InetAddress getByAddress(String host, byte[] addr, int scopeId)
+        throws UnknownHostException {
+        if (host != null && host.length() > 0 && host.charAt(0) == '[') {
+            if (host.charAt(host.length()-1) == ']') {
+                host = host.substring(1, host.length() -1);
+            }
+        }
+        if (addr != null) {
+            if (addr.length == Inet4Address.INADDRSZ) {
+                return new Inet4Address(host, addr);
+            } else if (addr.length == Inet6Address.INADDRSZ) {
+                byte[] newAddr
+                    = IPAddressUtil.convertFromIPv4MappedAddress(addr);
+                if (newAddr != null) {
+                    return new Inet4Address(host, newAddr);
+                } else {
+                    return new Inet6Address(host, addr, scopeId);
+                }
+            }
+        }
+        throw new UnknownHostException("addr is of illegal length");
+    }
+
+
+    /**
+     * Determines the IP address of a host, given the host's name.
+     *
+     * <p> The host name can either be a machine name, such as
+     * "{@code java.sun.com}", or a textual representation of its
+     * IP address. If a literal IP address is supplied, only the
+     * validity of the address format is checked.
+     *
+     * <p> For {@code host} specified in literal IPv6 address,
+     * either the form defined in RFC 2732 or the literal IPv6 address
+     * format defined in RFC 2373 is accepted. IPv6 scoped addresses are also
+     * supported. See <a href="Inet6Address.html#scoped">here</a> for a description of IPv6
+     * scoped addresses.
+     *
+     * <p> If the host is {@code null} then an {@code InetAddress}
+     * representing an address of the loopback interface is returned.
+     * See <a href="http://www.ietf.org/rfc/rfc3330.txt">RFC&nbsp;3330</a>
+     * section&nbsp;2 and <a href="http://www.ietf.org/rfc/rfc2373.txt">RFC&nbsp;2373</a>
+     * section&nbsp;2.5.3. </p>
+     *
+     * @param      host   the specified host, or {@code null}.
+     * @return     an IP address for the given host name.
+     * @exception  UnknownHostException  if no IP address for the
+     *               {@code host} could be found, or if a scope_id was specified
+     *               for a global IPv6 address.
+     * @exception  SecurityException if a security manager exists
+     *             and its checkConnect method doesn't allow the operation
+     */
+    public static InetAddress getByName(String host)
+        throws UnknownHostException {
+        // Android-changed: Rewritten on the top of Libcore.os.
+        return impl.lookupAllHostAddr(host, NETID_UNSET)[0];
+    }
+
+    /**
+     * Given the name of a host, returns an array of its IP addresses,
+     * based on the configured name service on the system.
+     *
+     * <p> The host name can either be a machine name, such as
+     * "{@code java.sun.com}", or a textual representation of its IP
+     * address. If a literal IP address is supplied, only the
+     * validity of the address format is checked.
+     *
+     * <p> For {@code host} specified in <i>literal IPv6 address</i>,
+     * either the form defined in RFC 2732 or the literal IPv6 address
+     * format defined in RFC 2373 is accepted. A literal IPv6 address may
+     * also be qualified by appending a scoped zone identifier or scope_id.
+     * The syntax and usage of scope_ids is described
+     * <a href="Inet6Address.html#scoped">here</a>.
+     * <p> If the host is {@code null} then an {@code InetAddress}
+     * representing an address of the loopback interface is returned.
+     * See <a href="http://www.ietf.org/rfc/rfc3330.txt">RFC&nbsp;3330</a>
+     * section&nbsp;2 and <a href="http://www.ietf.org/rfc/rfc2373.txt">RFC&nbsp;2373</a>
+     * section&nbsp;2.5.3. </p>
+     *
+     * <p> If there is a security manager and {@code host} is not
+     * null and {@code host.length() } is not equal to zero, the
+     * security manager's
+     * {@code checkConnect} method is called
+     * with the hostname and {@code -1}
+     * as its arguments to see if the operation is allowed.
+     *
+     * @param      host   the name of the host, or {@code null}.
+     * @return     an array of all the IP addresses for a given host name.
+     *
+     * @exception  UnknownHostException  if no IP address for the
+     *               {@code host} could be found, or if a scope_id was specified
+     *               for a global IPv6 address.
+     * @exception  SecurityException  if a security manager exists and its
+     *               {@code checkConnect} method doesn't allow the operation.
+     *
+     * @see SecurityManager#checkConnect
+     */
+    public static InetAddress[] getAllByName(String host)
+        throws UnknownHostException {
+        // Android-changed: Resolves a hostname using Libcore.os.
+        // Also, returns both the Inet4 and Inet6 loopback for null/empty host
+        return impl.lookupAllHostAddr(host, NETID_UNSET).clone();
+    }
+
+    /**
+     * Returns the loopback address.
+     * <p>
+     * The InetAddress returned will represent the IPv4
+     * loopback address, 127.0.0.1, or the IPv6 loopback
+     * address, ::1. The IPv4 loopback address returned
+     * is only one of many in the form 127.*.*.*
+     *
+     * @return  the InetAddress loopback instance.
+     * @since 1.7
+     */
+    public static InetAddress getLoopbackAddress() {
+        // Android-changed: Always returns IPv6 loopback address in Android.
+        return impl.loopbackAddresses()[0];
+    }
+
+    // BEGIN Android-removed: Resolves a hostname using Libcore.os.
+    /*
+     * check if the literal address string has %nn appended
+     * returns -1 if not, or the numeric value otherwise.
+     *
+     * %nn may also be a string that represents the displayName of
+     * a currently available NetworkInterface.
+     *
+    private static int checkNumericZone (String s) throws UnknownHostException {
+        int percent = s.indexOf ('%');
+        int slen = s.length();
+        int digit, zone=0;
+        if (percent == -1) {
+            return -1;
+        }
+        for (int i=percent+1; i<slen; i++) {
+            char c = s.charAt(i);
+            if (c == ']') {
+                if (i == percent+1) {
+                    /* empty per-cent field *
+                    return -1;
+                }
+                break;
+            }
+            if ((digit = Character.digit (c, 10)) < 0) {
+                return -1;
+            }
+            zone = (zone * 10) + digit;
+        }
+        return zone;
+    }
+
+    private static InetAddress[] getAllByName0 (String host)
+        throws UnknownHostException
+    {
+        return getAllByName0(host, true);
+    }
+
+    /**
+     * package private so SocketPermission can call it
+     *
+    static InetAddress[] getAllByName0 (String host, boolean check)
+        throws UnknownHostException  {
+        return getAllByName0 (host, null, check);
+    }
+
+    private static InetAddress[] getAllByName0 (String host, InetAddress reqAddr, boolean check)
+        throws UnknownHostException  {
+
+        /* If it gets here it is presumed to be a hostname */
+        /* Cache.get can return: null, unknownAddress, or InetAddress[] */
+
+        /* make sure the connection to the host is allowed, before we
+         * give out a hostname
+         *
+        if (check) {
+            SecurityManager security = System.getSecurityManager();
+            if (security != null) {
+                security.checkConnect(host, -1);
+            }
+        }
+
+        InetAddress[] addresses = getCachedAddresses(host);
+
+        /* If no entry in cache, then do the host lookup *
+        if (addresses == null) {
+            addresses = getAddressesFromNameService(host, reqAddr);
+        }
+
+        if (addresses == unknown_array)
+            throw new UnknownHostException(host);
+
+        return addresses.clone();
+    }
+
+    private static InetAddress[] getAddressesFromNameService(String host, InetAddress reqAddr)
+        throws UnknownHostException
+    {
+        InetAddress[] addresses = null;
+        boolean success = false;
+        UnknownHostException ex = null;
+
+        // Check whether the host is in the lookupTable.
+        // 1) If the host isn't in the lookupTable when
+        //    checkLookupTable() is called, checkLookupTable()
+        //    would add the host in the lookupTable and
+        //    return null. So we will do the lookup.
+        // 2) If the host is in the lookupTable when
+        //    checkLookupTable() is called, the current thread
+        //    would be blocked until the host is removed
+        //    from the lookupTable. Then this thread
+        //    should try to look up the addressCache.
+        //     i) if it found the addresses in the
+        //        addressCache, checkLookupTable()  would
+        //        return the addresses.
+        //     ii) if it didn't find the addresses in the
+        //         addressCache for any reason,
+        //         it should add the host in the
+        //         lookupTable and return null so the
+        //         following code would do  a lookup itself.
+        if ((addresses = checkLookupTable(host)) == null) {
+            try {
+                // This is the first thread which looks up the addresses
+                // this host or the cache entry for this host has been
+                // expired so this thread should do the lookup.
+                for (NameService nameService : nameServices) {
+                    try {
+                        /*
+                         * Do not put the call to lookup() inside the
+                         * constructor.  if you do you will still be
+                         * allocating space when the lookup fails.
+                         *
+
+                        addresses = nameService.lookupAllHostAddr(host);
+                        success = true;
+                        break;
+                    } catch (UnknownHostException uhe) {
+                        if (host.equalsIgnoreCase("localhost")) {
+                            InetAddress[] local = new InetAddress[] { impl.loopbackAddress() };
+                            addresses = local;
+                            success = true;
+                            break;
+                        }
+                        else {
+                            addresses = unknown_array;
+                            success = false;
+                            ex = uhe;
+                        }
+                    }
+                }
+
+                // More to do?
+                if (reqAddr != null && addresses.length > 1 && !addresses[0].equals(reqAddr)) {
+                    // Find it?
+                    int i = 1;
+                    for (; i < addresses.length; i++) {
+                        if (addresses[i].equals(reqAddr)) {
+                            break;
+                        }
+                    }
+                    // Rotate
+                    if (i < addresses.length) {
+                        InetAddress tmp, tmp2 = reqAddr;
+                        for (int j = 0; j < i; j++) {
+                            tmp = addresses[j];
+                            addresses[j] = tmp2;
+                            tmp2 = tmp;
+                        }
+                        addresses[i] = tmp2;
+                    }
+                }
+                // Cache the address.
+                cacheAddresses(host, addresses, success);
+
+                if (!success && ex != null)
+                    throw ex;
+
+            } finally {
+                // Delete host from the lookupTable and notify
+                // all threads waiting on the lookupTable monitor.
+                updateLookupTable(host);
+            }
+        }
+
+        return addresses;
+    }
+
+
+    private static InetAddress[] checkLookupTable(String host) {
+        synchronized (lookupTable) {
+            // If the host isn't in the lookupTable, add it in the
+            // lookuptable and return null. The caller should do
+            // the lookup.
+            if (lookupTable.containsKey(host) == false) {
+                lookupTable.put(host, null);
+                return null;
+            }
+
+            // If the host is in the lookupTable, it means that another
+            // thread is trying to look up the addresses of this host.
+            // This thread should wait.
+            while (lookupTable.containsKey(host)) {
+                try {
+                    lookupTable.wait();
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+
+        // The other thread has finished looking up the addresses of
+        // the host. This thread should retry to get the addresses
+        // from the addressCache. If it doesn't get the addresses from
+        // the cache, it will try to look up the addresses itself.
+        InetAddress[] addresses = getCachedAddresses(host);
+        if (addresses == null) {
+            synchronized (lookupTable) {
+                lookupTable.put(host, null);
+                return null;
+            }
+        }
+
+        return addresses;
+    }
+
+    private static void updateLookupTable(String host) {
+        synchronized (lookupTable) {
+            lookupTable.remove(host);
+            lookupTable.notifyAll();
+        }
+    }
+    */
+    // END Android-removed: Resolves a hostname using Libcore.os.
+
+    /**
+     * Returns an {@code InetAddress} object given the raw IP address .
+     * The argument is in network byte order: the highest order
+     * byte of the address is in {@code getAddress()[0]}.
+     *
+     * <p> This method doesn't block, i.e. no reverse name service lookup
+     * is performed.
+     *
+     * <p> IPv4 address byte array must be 4 bytes long and IPv6 byte array
+     * must be 16 bytes long
+     *
+     * @param addr the raw IP address in network byte order
+     * @return  an InetAddress object created from the raw IP address.
+     * @exception  UnknownHostException  if IP address is of illegal length
+     * @since 1.4
+     */
+    public static InetAddress getByAddress(byte[] addr)
+        throws UnknownHostException {
+        return getByAddress(null, addr);
+    }
+
+    // BEGIN Android-removed: Resolves a hostname using Libcore.os.
+    /*
+    private static InetAddress cachedLocalHost = null;
+    private static long cacheTime = 0;
+    private static final long maxCacheTime = 5000L;
+    private static final Object cacheLock = new Object();
+    */
+    // END Android-removed: Resolves a hostname using Libcore.os.
+
+    /**
+     * Returns the address of the local host. This is achieved by retrieving
+     * the name of the host from the system, then resolving that name into
+     * an {@code InetAddress}.
+     *
+     * <P>Note: The resolved address may be cached for a short period of time.
+     * </P>
+     *
+     * <p>If there is a security manager, its
+     * {@code checkConnect} method is called
+     * with the local host name and {@code -1}
+     * as its arguments to see if the operation is allowed.
+     * If the operation is not allowed, an InetAddress representing
+     * the loopback address is returned.
+     *
+     * @return     the address of the local host.
+     *
+     * @exception  UnknownHostException  if the local host name could not
+     *             be resolved into an address.
+     *
+     * @see SecurityManager#checkConnect
+     * @see java.net.InetAddress#getByName(java.lang.String)
+     */
+    public static InetAddress getLocalHost() throws UnknownHostException {
+        // BEGIN Android-changed: Resolves a hostname using Libcore.os.
+        /*
+        SecurityManager security = System.getSecurityManager();
+        try {
+            String local = impl.getLocalHostName();
+
+            if (security != null) {
+                security.checkConnect(local, -1);
+            }
+
+            if (local.equals("localhost")) {
+                return impl.loopbackAddress();
+            }
+
+            InetAddress ret = null;
+            synchronized (cacheLock) {
+                long now = System.currentTimeMillis();
+                if (cachedLocalHost != null) {
+                    if ((now - cacheTime) < maxCacheTime) // Less than 5s old?
+                        ret = cachedLocalHost;
+                    else
+                        cachedLocalHost = null;
+                }
+
+                // we are calling getAddressesFromNameService directly
+                // to avoid getting localHost from cache
+                if (ret == null) {
+                    InetAddress[] localAddrs;
+                    try {
+                        localAddrs =
+                            InetAddress.getAddressesFromNameService(local, null);
+                    } catch (UnknownHostException uhe) {
+                        // Rethrow with a more informative error message.
+                        UnknownHostException uhe2 =
+                            new UnknownHostException(local + ": " +
+                                                     uhe.getMessage());
+                        uhe2.initCause(uhe);
+                        throw uhe2;
+                    }
+                    cachedLocalHost = localAddrs[0];
+                    cacheTime = now;
+                    ret = localAddrs[0];
+                }
+            }
+            return ret;
+        } catch (java.lang.SecurityException e) {
+            return impl.loopbackAddress();
+        }
+        */
+        String local = Libcore.os.uname().nodename;
+        return impl.lookupAllHostAddr(local, NETID_UNSET)[0];
+        // END Android-changed: Resolves a hostname using Libcore.os.
+    }
+
+    // BEGIN Android-removed: Android doesn't need to call native init.
+    /**
+     * Perform class load-time initializations.
+     *
+    private static native void init();
+    */
+    // END Android-removed: Android doesn't need to call native init.
+
+    /*
+     * Returns the InetAddress representing anyLocalAddress
+     * (typically 0.0.0.0 or ::0)
+     */
+    static InetAddress anyLocalAddress() {
+        return impl.anyLocalAddress();
+    }
+
+    // BEGIN Android-removed: Android doesn't load user-provided implementation.
+    /*
+     * Load and instantiate an underlying impl class
+     *
+    static InetAddressImpl loadImpl(String implName) {
+        Object impl = null;
+
+        /*
+         * Property "impl.prefix" will be prepended to the classname
+         * of the implementation object we instantiate, to which we
+         * delegate the real work (like native methods).  This
+         * property can vary across implementations of the java.
+         * classes.  The default is an empty String "".
+         *
+        String prefix = AccessController.doPrivileged(
+                      new GetPropertyAction("impl.prefix", ""));
+        try {
+            impl = Class.forName("java.net." + prefix + implName).newInstance();
+        } catch (ClassNotFoundException e) {
+            System.err.println("Class not found: java.net." + prefix +
+                               implName + ":\ncheck impl.prefix property " +
+                               "in your properties file.");
+        } catch (InstantiationException e) {
+            System.err.println("Could not instantiate: java.net." + prefix +
+                               implName + ":\ncheck impl.prefix property " +
+                               "in your properties file.");
+        } catch (IllegalAccessException e) {
+            System.err.println("Cannot access class: java.net." + prefix +
+                               implName + ":\ncheck impl.prefix property " +
+                               "in your properties file.");
+        }
+
+        if (impl == null) {
+            try {
+                impl = Class.forName(implName).newInstance();
+            } catch (Exception e) {
+                throw new Error("System property impl.prefix incorrect");
+            }
+        }
+
+        return (InetAddressImpl) impl;
+    }
+    */
+    // END Android-removed: Android doesn't load user-provided implementation.
+
+    private void readObjectNoData (ObjectInputStream s) throws
+                         IOException, ClassNotFoundException {
+        // Android-changed: Don't use null to mean the boot classloader.
+        if (getClass().getClassLoader() != BOOT_CLASSLOADER) {
+            throw new SecurityException ("invalid address type");
+        }
+    }
+
+    // Android-changed: Don't use null to mean the boot classloader.
+    private static final ClassLoader BOOT_CLASSLOADER = Object.class.getClassLoader();
+
+    private void readObject (ObjectInputStream s) throws
+                         IOException, ClassNotFoundException {
+        // Android-changed: Don't use null to mean the boot classloader.
+        if (getClass().getClassLoader() != BOOT_CLASSLOADER) {
+            throw new SecurityException ("invalid address type");
+        }
+        GetField gf = s.readFields();
+        String host = (String)gf.get("hostName", null);
+        int address= gf.get("address", 0);
+        int family= gf.get("family", 0);
+        holder = new InetAddressHolder(host, address, family);
+    }
+
+    /* needed because the serializable fields no longer exist */
+
+    /**
+     * @serialField hostName String
+     * @serialField address int
+     * @serialField family int
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("hostName", String.class),
+        new ObjectStreamField("address", int.class),
+        new ObjectStreamField("family", int.class),
+    };
+
+    private void writeObject (ObjectOutputStream s) throws
+                        IOException {
+        // Android-changed: Don't use null to mean the boot classloader.
+        if (getClass().getClassLoader() != BOOT_CLASSLOADER) {
+            throw new SecurityException ("invalid address type");
+        }
+        PutField pf = s.putFields();
+        pf.put("hostName", holder().hostName);
+        pf.put("address", holder().address);
+        pf.put("family", holder().family);
+        s.writeFields();
+        s.flush();
+    }
+
+    static final int NETID_UNSET = 0;
+
+    // BEGIN Android-added: Add methods required by frameworks/base.
+    // Particularly those required to deal with scope ids.
+    /**
+     * Returns true if the string is a valid numeric IPv4 or IPv6 address (such as "192.168.0.1").
+     *
+     * <p>This copes with all forms of address that Java supports, detailed in the
+     * {@link InetAddress} class documentation. An empty string is not treated as numeric.
+     *
+     * @hide used by frameworks/base to ensure that a getAllByName won't cause a DNS lookup.
+     * @deprecated Use {@link InetAddressUtils#isNumericAddress(String)} instead, if possible.
+     * @throws NullPointerException if the {@code address} is {@code null}.
+     */
+    @Deprecated
+    public static boolean isNumeric(String address) {
+        return InetAddressUtils.parseNumericAddressNoThrowStripOptionalBrackets(address) != null;
+    }
+
+    /**
+     * Returns an InetAddress corresponding to the given numeric address (such
+     * as {@code "192.168.0.1"} or {@code "2001:4860:800d::68"}).
+     *
+     * <p>This method will never do a DNS lookup. Non-numeric addresses are errors. Passing either
+     * an empty string or a {@code null} as the {@code numericAddress} will return the
+     * {@link Inet6Address#LOOPBACK} address.
+     *
+     * @hide used by frameworks/base's NetworkUtils.numericToInetAddress
+     * @throws IllegalArgumentException if {@code numericAddress} is not a numeric address
+     * @deprecated Use {@link InetAddressUtils#parseNumericAddress(String)} instead, if possible.
+     */
+    @Deprecated
+    public static InetAddress parseNumericAddress(String numericAddress) {
+        if (numericAddress == null || numericAddress.isEmpty()) {
+            return Inet6Address.LOOPBACK;
+        }
+        InetAddress result = InetAddressUtils
+                .parseNumericAddressNoThrowStripOptionalBrackets(numericAddress);
+        if (result == null) {
+            throw new IllegalArgumentException("Not a numeric address: " + numericAddress);
+        }
+        return result;
+    }
+
+    /**
+     * Removes all entries from the VM's DNS cache. This does not affect the C library's DNS
+     * cache, nor any caching DNS servers between you and the canonical server.
+     * @hide
+     */
+    public static void clearDnsCache() {
+        impl.clearAddressCache();
+    }
+    // END Android-added: Add methods required by frameworks/base.
+    // BEGIN Android-added: Support for network (netId)-specific DNS resolution.
+    /**
+     * Operates identically to {@code getByName} except host resolution is
+     * performed on the network designated by {@code netId}.
+     *
+     * @param host
+     *            the hostName to be resolved to an address or {@code null}.
+     * @param netId the network to use for host resolution.
+     * @return the {@code InetAddress} instance representing the host.
+     * @throws UnknownHostException if the address lookup fails.
+     * @hide internal use only
+     */
+    public static InetAddress getByNameOnNet(String host, int netId) throws UnknownHostException {
+        return impl.lookupAllHostAddr(host, netId)[0];
+    }
+
+    /**
+     * Operates identically to {@code getAllByName} except host resolution is
+     * performed on the network designated by {@code netId}.
+     *
+     * @param host the hostname or literal IP string to be resolved.
+     * @param netId the network to use for host resolution.
+     * @return the array of addresses associated with the specified host.
+     * @throws UnknownHostException if the address lookup fails.
+     * @hide internal use only
+     */
+    public static InetAddress[] getAllByNameOnNet(String host, int netId) throws UnknownHostException {
+        return impl.lookupAllHostAddr(host, netId).clone();
+    }
+    // END Android-added: Support for network (netId)-specific DNS resolution.
+}
+// BEGIN Android-removed: Android doesn't load user-provided implementation.
+/*
+ * Simple factory to create the impl
+ *
+class InetAddressImplFactory {
+
+    static InetAddressImpl create() {
+        return InetAddress.loadImpl(isIPv6Supported() ?
+                                    "Inet6AddressImpl" : "Inet4AddressImpl");
+    }
+
+    static native boolean isIPv6Supported();
+}
+*/
+// END Android-removed: Android doesn't load user-provided implementation.
diff --git a/java/net/InetAddressContainer.java b/java/net/InetAddressContainer.java
new file mode 100644
index 0000000..28b6402
--- /dev/null
+++ b/java/net/InetAddressContainer.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+class InetAddressContainer {
+    InetAddress addr;
+}
diff --git a/java/net/InetAddressImpl.java b/java/net/InetAddressImpl.java
new file mode 100644
index 0000000..a636c1e
--- /dev/null
+++ b/java/net/InetAddressImpl.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+import java.io.IOException;
+/*
+ * Package private interface to "implementation" used by
+ * {@link InetAddress}.
+ * <p>
+ * See {@link java.net.Inet4AddressImp} and
+ * {@link java.net.Inet6AddressImp}.
+ *
+ * @since 1.4
+ */
+interface InetAddressImpl {
+
+    // BEGIN Android-changed: Rewrote hostname lookup methods on top of Libcore.os.
+    /*
+    String getLocalHostName() throws UnknownHostException;
+    InetAddress[]
+        lookupAllHostAddr(String hostname) throws UnknownHostException;
+     */
+    /**
+     * Lookup all addresses for {@code hostname} on the given {@code netId}.
+     */
+    InetAddress[] lookupAllHostAddr(String hostname, int netId) throws UnknownHostException;
+
+    /**
+     * Reverse-lookup the host name for a given {@code addr}.
+     */
+    String getHostByAddr(byte[] addr) throws UnknownHostException;
+
+    /**
+     * Clear address caches (if any).
+     */
+    public void clearAddressCache();
+    // END Android-changed: Rewrote hostname lookup methods on top of Libcore.os.
+
+    /**
+     * Return the "any" local address.
+     */
+    InetAddress anyLocalAddress();
+
+    // Android-changed: Let loopbackAddresses() return both Inet4 and Inet6 loopbacks.
+    // InetAddress loopbackAddress();
+    /**
+     * Return a list of loop back adresses for this implementation.
+     */
+    InetAddress[] loopbackAddresses();
+
+    /**
+     * Whether {@code addr} is reachable over {@code netif}.
+     */
+    boolean isReachable(InetAddress addr, int timeout, NetworkInterface netif,
+                        int ttl) throws IOException;
+}
diff --git a/java/net/InetSocketAddress.annotated.java b/java/net/InetSocketAddress.annotated.java
new file mode 100644
index 0000000..554b8e3
--- /dev/null
+++ b/java/net/InetSocketAddress.annotated.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class InetSocketAddress extends java.net.SocketAddress {
+
[email protected]
+public InetSocketAddress() { throw new RuntimeException("Stub!"); }
+
+public InetSocketAddress(int port) { throw new RuntimeException("Stub!"); }
+
+public InetSocketAddress(java.net.InetAddress addr, int port) { throw new RuntimeException("Stub!"); }
+
+public InetSocketAddress(java.lang.String hostname, int port) { throw new RuntimeException("Stub!"); }
+
+public static java.net.InetSocketAddress createUnresolved(java.lang.String host, int port) { throw new RuntimeException("Stub!"); }
+
+public final int getPort() { throw new RuntimeException("Stub!"); }
+
+public final java.net.InetAddress getAddress() { throw new RuntimeException("Stub!"); }
+
+public final java.lang.String getHostName() { throw new RuntimeException("Stub!"); }
+
+public final java.lang.String getHostString() { throw new RuntimeException("Stub!"); }
+
+public final boolean isUnresolved() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public final boolean equals(java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public final int hashCode() { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/net/InetSocketAddress.java b/java/net/InetSocketAddress.java
new file mode 100644
index 0000000..74b559b
--- /dev/null
+++ b/java/net/InetSocketAddress.java
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
+import java.io.ObjectStreamField;
+
+/**
+ *
+ * This class implements an IP Socket Address (IP address + port number)
+ * It can also be a pair (hostname + port number), in which case an attempt
+ * will be made to resolve the hostname. If resolution fails then the address
+ * is said to be <I>unresolved</I> but can still be used on some circumstances
+ * like connecting through a proxy.
+ * <p>
+ * It provides an immutable object used by sockets for binding, connecting, or
+ * as returned values.
+ * <p>
+ * The <i>wildcard</i> is a special local IP address. It usually means "any"
+ * and can only be used for {@code bind} operations.
+ *
+ * @see java.net.Socket
+ * @see java.net.ServerSocket
+ * @since 1.4
+ */
+public class InetSocketAddress
+    extends SocketAddress
+{
+    // Private implementation class pointed to by all public methods.
+    private static class InetSocketAddressHolder {
+        // The hostname of the Socket Address
+        private String hostname;
+        // The IP address of the Socket Address
+        private InetAddress addr;
+        // The port number of the Socket Address
+        private int port;
+
+        private InetSocketAddressHolder(String hostname, InetAddress addr, int port) {
+            this.hostname = hostname;
+            this.addr = addr;
+            this.port = port;
+        }
+
+        private int getPort() {
+            return port;
+        }
+
+        private InetAddress getAddress() {
+            return addr;
+        }
+
+        private String getHostName() {
+            if (hostname != null)
+                return hostname;
+            if (addr != null)
+                return addr.getHostName();
+            return null;
+        }
+
+        private String getHostString() {
+            if (hostname != null)
+                return hostname;
+            if (addr != null) {
+                if (addr.holder().getHostName() != null)
+                    return addr.holder().getHostName();
+                else
+                    return addr.getHostAddress();
+            }
+            return null;
+        }
+
+        private boolean isUnresolved() {
+            return addr == null;
+        }
+
+        @Override
+        public String toString() {
+            if (isUnresolved()) {
+                return hostname + ":" + port;
+            } else {
+                return addr.toString() + ":" + port;
+            }
+        }
+
+        @Override
+        public final boolean equals(Object obj) {
+            if (obj == null || !(obj instanceof InetSocketAddressHolder))
+                return false;
+            InetSocketAddressHolder that = (InetSocketAddressHolder)obj;
+            boolean sameIP;
+            if (addr != null)
+                sameIP = addr.equals(that.addr);
+            else if (hostname != null)
+                sameIP = (that.addr == null) &&
+                    hostname.equalsIgnoreCase(that.hostname);
+            else
+                sameIP = (that.addr == null) && (that.hostname == null);
+            return sameIP && (port == that.port);
+        }
+
+        @Override
+        public final int hashCode() {
+            if (addr != null)
+                return addr.hashCode() + port;
+            if (hostname != null)
+                return hostname.toLowerCase().hashCode() + port;
+            return port;
+        }
+    }
+
+    private final transient InetSocketAddressHolder holder;
+
+    private static final long serialVersionUID = 5076001401234631237L;
+
+    private static int checkPort(int port) {
+        if (port < 0 || port > 0xFFFF)
+            throw new IllegalArgumentException("port out of range:" + port);
+        return port;
+    }
+
+    private static String checkHost(String hostname) {
+        if (hostname == null)
+            throw new IllegalArgumentException("hostname can't be null");
+        return hostname;
+    }
+
+    // BEGIN Android-added: InetSocketAddress() ctor used by IoBridge.
+    /**
+     * @hide internal use only
+     */
+    public InetSocketAddress() {
+        // These will be filled in the native implementation of recvfrom.
+        holder = new InetSocketAddressHolder(null, null, 0);
+    }
+    // END Android-added: InetSocketAddress() ctor used by IoBridge.
+
+    /**
+     * Creates a socket address where the IP address is the wildcard address
+     * and the port number a specified value.
+     * <p>
+     * A valid port value is between 0 and 65535.
+     * A port number of {@code zero} will let the system pick up an
+     * ephemeral port in a {@code bind} operation.
+     * <p>
+     * @param   port    The port number
+     * @throws IllegalArgumentException if the port parameter is outside the specified
+     * range of valid port values.
+     */
+    public InetSocketAddress(int port) {
+        // Android-changed: Defaults to IPv6.
+        // this(InetAddress.anyLocalAddress(), port);
+        this((InetAddress)null, port);
+    }
+
+    /**
+     *
+     * Creates a socket address from an IP address and a port number.
+     * <p>
+     * A valid port value is between 0 and 65535.
+     * A port number of {@code zero} will let the system pick up an
+     * ephemeral port in a {@code bind} operation.
+     * <P>
+     * A {@code null} address will assign the <i>wildcard</i> address.
+     * <p>
+     * @param   addr    The IP address
+     * @param   port    The port number
+     * @throws IllegalArgumentException if the port parameter is outside the specified
+     * range of valid port values.
+     */
+    public InetSocketAddress(InetAddress addr, int port) {
+        holder = new InetSocketAddressHolder(
+                        null,
+                        // Android-changed: Defaults to IPv6 if addr is null.
+                        // addr == null ? InetAddress.anyLocalAddress() : addr,
+                        addr == null ? Inet6Address.ANY : addr,
+                        checkPort(port));
+    }
+
+    /**
+     *
+     * Creates a socket address from a hostname and a port number.
+     * <p>
+     * An attempt will be made to resolve the hostname into an InetAddress.
+     * If that attempt fails, the address will be flagged as <I>unresolved</I>.
+     * <p>
+     * If there is a security manager, its {@code checkConnect} method
+     * is called with the host name as its argument to check the permission
+     * to resolve it. This could result in a SecurityException.
+     * <P>
+     * A valid port value is between 0 and 65535.
+     * A port number of {@code zero} will let the system pick up an
+     * ephemeral port in a {@code bind} operation.
+     * <P>
+     * @param   hostname the Host name
+     * @param   port    The port number
+     * @throws IllegalArgumentException if the port parameter is outside the range
+     * of valid port values, or if the hostname parameter is <TT>null</TT>.
+     * @throws SecurityException if a security manager is present and
+     *                           permission to resolve the host name is
+     *                           denied.
+     * @see     #isUnresolved()
+     */
+    public InetSocketAddress(String hostname, int port) {
+        checkHost(hostname);
+        InetAddress addr = null;
+        String host = null;
+        try {
+            addr = InetAddress.getByName(hostname);
+        } catch(UnknownHostException e) {
+            host = hostname;
+        }
+        holder = new InetSocketAddressHolder(host, addr, checkPort(port));
+    }
+
+    // private constructor for creating unresolved instances
+    private InetSocketAddress(int port, String hostname) {
+        holder = new InetSocketAddressHolder(hostname, null, port);
+    }
+
+    /**
+     *
+     * Creates an unresolved socket address from a hostname and a port number.
+     * <p>
+     * No attempt will be made to resolve the hostname into an InetAddress.
+     * The address will be flagged as <I>unresolved</I>.
+     * <p>
+     * A valid port value is between 0 and 65535.
+     * A port number of {@code zero} will let the system pick up an
+     * ephemeral port in a {@code bind} operation.
+     * <P>
+     * @param   host    the Host name
+     * @param   port    The port number
+     * @throws IllegalArgumentException if the port parameter is outside
+     *                  the range of valid port values, or if the hostname
+     *                  parameter is <TT>null</TT>.
+     * @see     #isUnresolved()
+     * @return  a {@code InetSocketAddress} representing the unresolved
+     *          socket address
+     * @since 1.5
+     */
+    public static InetSocketAddress createUnresolved(String host, int port) {
+        return new InetSocketAddress(checkPort(port), checkHost(host));
+    }
+
+    /**
+     * @serialField hostname String
+     * @serialField addr InetAddress
+     * @serialField port int
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+         new ObjectStreamField("hostname", String.class),
+         new ObjectStreamField("addr", InetAddress.class),
+         new ObjectStreamField("port", int.class)};
+
+    private void writeObject(ObjectOutputStream out)
+        throws IOException
+    {
+        // Don't call defaultWriteObject()
+         ObjectOutputStream.PutField pfields = out.putFields();
+         pfields.put("hostname", holder.hostname);
+         pfields.put("addr", holder.addr);
+         pfields.put("port", holder.port);
+         out.writeFields();
+     }
+
+    private void readObject(ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        // Don't call defaultReadObject()
+        ObjectInputStream.GetField oisFields = in.readFields();
+        final String oisHostname = (String)oisFields.get("hostname", null);
+        final InetAddress oisAddr = (InetAddress)oisFields.get("addr", null);
+        final int oisPort = oisFields.get("port", -1);
+
+        // Check that our invariants are satisfied
+        checkPort(oisPort);
+        if (oisHostname == null && oisAddr == null)
+            throw new InvalidObjectException("hostname and addr " +
+                                             "can't both be null");
+
+        InetSocketAddressHolder h = new InetSocketAddressHolder(oisHostname,
+                                                                oisAddr,
+                                                                oisPort);
+        UNSAFE.putObject(this, FIELDS_OFFSET, h);
+    }
+
+    private void readObjectNoData()
+        throws ObjectStreamException
+    {
+        throw new InvalidObjectException("Stream data required");
+    }
+
+    private static final long FIELDS_OFFSET;
+    private static final sun.misc.Unsafe UNSAFE;
+    static {
+        try {
+            sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
+            FIELDS_OFFSET = unsafe.objectFieldOffset(
+                    InetSocketAddress.class.getDeclaredField("holder"));
+            UNSAFE = unsafe;
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    /**
+     * Gets the port number.
+     *
+     * @return the port number.
+     */
+    public final int getPort() {
+        return holder.getPort();
+    }
+
+    /**
+     *
+     * Gets the {@code InetAddress}.
+     *
+     * @return the InetAdress or {@code null} if it is unresolved.
+     */
+    public final InetAddress getAddress() {
+        return holder.getAddress();
+    }
+
+    /**
+     * Gets the {@code hostname}.
+     * Note: This method may trigger a name service reverse lookup if the
+     * address was created with a literal IP address.
+     *
+     * @return  the hostname part of the address.
+     */
+    public final String getHostName() {
+        return holder.getHostName();
+    }
+
+    /**
+     * Returns the hostname, or the String form of the address if it
+     * doesn't have a hostname (it was created using a literal).
+     * This has the benefit of <b>not</b> attempting a reverse lookup.
+     *
+     * @return the hostname, or String representation of the address.
+     * @since 1.7
+     */
+    public final String getHostString() {
+        return holder.getHostString();
+    }
+
+    /**
+     * Checks whether the address has been resolved or not.
+     *
+     * @return {@code true} if the hostname couldn't be resolved into
+     *          an {@code InetAddress}.
+     */
+    public final boolean isUnresolved() {
+        return holder.isUnresolved();
+    }
+
+    /**
+     * Constructs a string representation of this InetSocketAddress.
+     * This String is constructed by calling toString() on the InetAddress
+     * and concatenating the port number (with a colon). If the address
+     * is unresolved then the part before the colon will only contain the hostname.
+     *
+     * @return  a string representation of this object.
+     */
+    @Override
+    public String toString() {
+        return holder.toString();
+    }
+
+    /**
+     * Compares this object against the specified object.
+     * The result is {@code true} if and only if the argument is
+     * not {@code null} and it represents the same address as
+     * this object.
+     * <p>
+     * Two instances of {@code InetSocketAddress} represent the same
+     * address if both the InetAddresses (or hostnames if it is unresolved) and port
+     * numbers are equal.
+     * If both addresses are unresolved, then the hostname and the port number
+     * are compared.
+     *
+     * Note: Hostnames are case insensitive. e.g. "FooBar" and "foobar" are
+     * considered equal.
+     *
+     * @param   obj   the object to compare against.
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     * @see java.net.InetAddress#equals(java.lang.Object)
+     */
+    @Override
+    public final boolean equals(Object obj) {
+        if (obj == null || !(obj instanceof InetSocketAddress))
+            return false;
+        return holder.equals(((InetSocketAddress) obj).holder);
+    }
+
+    /**
+     * Returns a hashcode for this socket address.
+     *
+     * @return  a hash code value for this socket address.
+     */
+    @Override
+    public final int hashCode() {
+        return holder.hashCode();
+    }
+}
diff --git a/java/net/InterfaceAddress.java b/java/net/InterfaceAddress.java
new file mode 100644
index 0000000..85f9e58
--- /dev/null
+++ b/java/net/InterfaceAddress.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * This class represents a Network Interface address. In short it's an
+ * IP address, a subnet mask and a broadcast address when the address is
+ * an IPv4 one. An IP address and a network prefix length in the case
+ * of IPv6 address.
+ *
+ * @see java.net.NetworkInterface
+ * @since 1.6
+ */
+public class InterfaceAddress {
+    private InetAddress address = null;
+    private Inet4Address broadcast = null;
+    private short        maskLength = 0;
+
+    /*
+     * Package private constructor. Can't be built directly, instances are
+     * obtained through the NetworkInterface class.
+     */
+    InterfaceAddress() {
+    }
+
+    // BEGIN Android-added: Rewrote NetworkInterface on top of Libcore.io.
+    InterfaceAddress(InetAddress address, Inet4Address broadcast, InetAddress netmask) {
+        this.address = address;
+        this.broadcast = broadcast;
+        this.maskLength = countPrefixLength(netmask);
+    }
+
+    /**
+     * Counts the prefix length for the netmask address.
+     *
+     * A valid netmask address must start with a continuous sequence of 1, followed by a continuous
+     * sequence of 0.
+     */
+    private short countPrefixLength(InetAddress netmask) {
+        short count = 0;
+        for (byte b : netmask.getAddress()) {
+            for (; b != 0; b <<= 1, ++count);
+        }
+        return count;
+    }
+    // END Android-added: Rewrote NetworkInterface on top of Libcore.io.
+
+    /**
+     * Returns an {@code InetAddress} for this address.
+     *
+     * @return the {@code InetAddress} for this address.
+     */
+    public InetAddress getAddress() {
+        return address;
+    }
+
+    /**
+     * Returns an {@code InetAddress} for the broadcast address
+     * for this InterfaceAddress.
+     * <p>
+     * Only IPv4 networks have broadcast address therefore, in the case
+     * of an IPv6 network, {@code null} will be returned.
+     *
+     * @return the {@code InetAddress} representing the broadcast
+     *         address or {@code null} if there is no broadcast address.
+     */
+    public InetAddress getBroadcast() {
+        return broadcast;
+    }
+
+    /**
+     * Returns the network prefix length for this address. This is also known
+     * as the subnet mask in the context of IPv4 addresses.
+     * Typical IPv4 values would be 8 (255.0.0.0), 16 (255.255.0.0)
+     * or 24 (255.255.255.0). <p>
+     * Typical IPv6 values would be 128 (::1/128) or 10 (fe80::203:baff:fe27:1243/10)
+     *
+     * @return a {@code short} representing the prefix length for the
+     *         subnet of that address.
+     */
+     public short getNetworkPrefixLength() {
+        return maskLength;
+    }
+
+    /**
+     * Compares this object against the specified object.
+     * The result is {@code true} if and only if the argument is
+     * not {@code null} and it represents the same interface address as
+     * this object.
+     * <p>
+     * Two instances of {@code InterfaceAddress} represent the same
+     * address if the InetAddress, the prefix length and the broadcast are
+     * the same for both.
+     *
+     * @param   obj   the object to compare against.
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     * @see     java.net.InterfaceAddress#hashCode()
+     */
+    public boolean equals(Object obj) {
+        if (!(obj instanceof InterfaceAddress)) {
+            return false;
+        }
+        InterfaceAddress cmp = (InterfaceAddress) obj;
+        if ( !(address == null ? cmp.address == null : address.equals(cmp.address)) )
+            return false;
+        if ( !(broadcast  == null ? cmp.broadcast == null : broadcast.equals(cmp.broadcast)) )
+            return false;
+        if (maskLength != cmp.maskLength)
+            return false;
+        return true;
+    }
+
+    /**
+     * Returns a hashcode for this Interface address.
+     *
+     * @return  a hash code value for this Interface address.
+     */
+    public int hashCode() {
+        return address.hashCode() + ((broadcast != null) ? broadcast.hashCode() : 0) + maskLength;
+    }
+
+    /**
+     * Converts this Interface address to a {@code String}. The
+     * string returned is of the form: InetAddress / prefix length [ broadcast address ].
+     *
+     * @return  a string representation of this Interface address.
+     */
+    public String toString() {
+        return address + "/" + maskLength + " [" + broadcast + "]";
+    }
+
+}
diff --git a/java/net/JarURLConnection.java b/java/net/JarURLConnection.java
new file mode 100644
index 0000000..70dedec
--- /dev/null
+++ b/java/net/JarURLConnection.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.util.jar.JarFile;
+import java.util.jar.JarEntry;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import java.security.Permission;
+import sun.net.www.ParseUtil;
+
+/**
+ * A URL Connection to a Java ARchive (JAR) file or an entry in a JAR
+ * file.
+ *
+ * <p>The syntax of a JAR URL is:
+ *
+ * <pre>
+ * jar:&lt;url&gt;!/{entry}
+ * </pre>
+ *
+ * <p>for example:
+ *
+ * <p>{@code jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class}
+ *
+ * <p>Jar URLs should be used to refer to a JAR file or entries in
+ * a JAR file. The example above is a JAR URL which refers to a JAR
+ * entry. If the entry name is omitted, the URL refers to the whole
+ * JAR file:
+ *
+ * {@code jar:http://www.foo.com/bar/baz.jar!/}
+ *
+ * <p>Users should cast the generic URLConnection to a
+ * JarURLConnection when they know that the URL they created is a JAR
+ * URL, and they need JAR-specific functionality. For example:
+ *
+ * <pre>
+ * URL url = new URL("jar:file:/home/duke/duke.jar!/");
+ * JarURLConnection jarConnection = (JarURLConnection)url.openConnection();
+ * Manifest manifest = jarConnection.getManifest();
+ * </pre>
+ *
+ * <p>JarURLConnection instances can only be used to read from JAR files.
+ * It is not possible to get a {@link java.io.OutputStream} to modify or write
+ * to the underlying JAR file using this class.
+ * <p>Examples:
+ *
+ * <dl>
+ *
+ * <dt>A Jar entry
+ * <dd>{@code jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class}
+ *
+ * <dt>A Jar file
+ * <dd>{@code jar:http://www.foo.com/bar/baz.jar!/}
+ *
+ * <dt>A Jar directory
+ * <dd>{@code jar:http://www.foo.com/bar/baz.jar!/COM/foo/}
+ *
+ * </dl>
+ *
+ * <p>{@code !/} is referred to as the <em>separator</em>.
+ *
+ * <p>When constructing a JAR url via {@code new URL(context, spec)},
+ * the following rules apply:
+ *
+ * <ul>
+ *
+ * <li>if there is no context URL and the specification passed to the
+ * URL constructor doesn't contain a separator, the URL is considered
+ * to refer to a JarFile.
+ *
+ * <li>if there is a context URL, the context URL is assumed to refer
+ * to a JAR file or a Jar directory.
+ *
+ * <li>if the specification begins with a '/', the Jar directory is
+ * ignored, and the spec is considered to be at the root of the Jar
+ * file.
+ *
+ * <p>Examples:
+ *
+ * <dl>
+ *
+ * <dt>context: <b>jar:http://www.foo.com/bar/jar.jar!/</b>,
+ * spec:<b>baz/entry.txt</b>
+ *
+ * <dd>url:<b>jar:http://www.foo.com/bar/jar.jar!/baz/entry.txt</b>
+ *
+ * <dt>context: <b>jar:http://www.foo.com/bar/jar.jar!/baz</b>,
+ * spec:<b>entry.txt</b>
+ *
+ * <dd>url:<b>jar:http://www.foo.com/bar/jar.jar!/baz/entry.txt</b>
+ *
+ * <dt>context: <b>jar:http://www.foo.com/bar/jar.jar!/baz</b>,
+ * spec:<b>/entry.txt</b>
+ *
+ * <dd>url:<b>jar:http://www.foo.com/bar/jar.jar!/entry.txt</b>
+ *
+ * </dl>
+ *
+ * </ul>
+ *
+ * @see java.net.URL
+ * @see java.net.URLConnection
+ *
+ * @see java.util.jar.JarFile
+ * @see java.util.jar.JarInputStream
+ * @see java.util.jar.Manifest
+ * @see java.util.zip.ZipEntry
+ *
+ * @author Benjamin Renaud
+ * @since 1.2
+ */
+public abstract class JarURLConnection extends URLConnection {
+
+    private URL jarFileURL;
+    private String entryName;
+
+    /**
+     * The connection to the JAR file URL, if the connection has been
+     * initiated. This should be set by connect.
+     */
+    protected URLConnection jarFileURLConnection;
+
+    /**
+     * Creates the new JarURLConnection to the specified URL.
+     * @param url the URL
+     * @throws MalformedURLException if no legal protocol
+     * could be found in a specification string or the
+     * string could not be parsed.
+     */
+
+    protected JarURLConnection(URL url) throws MalformedURLException {
+        super(url);
+        parseSpecs(url);
+    }
+
+    /* get the specs for a given url out of the cache, and compute and
+     * cache them if they're not there.
+     */
+    private void parseSpecs(URL url) throws MalformedURLException {
+        String spec = url.getFile();
+
+        int separator = spec.indexOf("!/");
+        /*
+         * REMIND: we don't handle nested JAR URLs
+         */
+        if (separator == -1) {
+            throw new MalformedURLException("no !/ found in url spec:" + spec);
+        }
+
+        jarFileURL = new URL(spec.substring(0, separator++));
+        entryName = null;
+
+        /* if ! is the last letter of the innerURL, entryName is null */
+        if (++separator != spec.length()) {
+            entryName = spec.substring(separator, spec.length());
+            entryName = ParseUtil.decode (entryName);
+        }
+    }
+
+    /**
+     * Returns the URL for the Jar file for this connection.
+     *
+     * @return the URL for the Jar file for this connection.
+     */
+    public URL getJarFileURL() {
+        return jarFileURL;
+    }
+
+    /**
+     * Return the entry name for this connection. This method
+     * returns null if the JAR file URL corresponding to this
+     * connection points to a JAR file and not a JAR file entry.
+     *
+     * @return the entry name for this connection, if any.
+     */
+    public String getEntryName() {
+        return entryName;
+    }
+
+    /**
+     * Return the JAR file for this connection.
+     *
+     * @return the JAR file for this connection. If the connection is
+     * a connection to an entry of a JAR file, the JAR file object is
+     * returned
+     *
+     * @exception IOException if an IOException occurs while trying to
+     * connect to the JAR file for this connection.
+     *
+     * @see #connect
+     */
+    public abstract JarFile getJarFile() throws IOException;
+
+    /**
+     * Returns the Manifest for this connection, or null if none.
+     *
+     * @return the manifest object corresponding to the JAR file object
+     * for this connection.
+     *
+     * @exception IOException if getting the JAR file for this
+     * connection causes an IOException to be thrown.
+     *
+     * @see #getJarFile
+     */
+    public Manifest getManifest() throws IOException {
+        return getJarFile().getManifest();
+    }
+
+    /**
+     * Return the JAR entry object for this connection, if any. This
+     * method returns null if the JAR file URL corresponding to this
+     * connection points to a JAR file and not a JAR file entry.
+     *
+     * @return the JAR entry object for this connection, or null if
+     * the JAR URL for this connection points to a JAR file.
+     *
+     * @exception IOException if getting the JAR file for this
+     * connection causes an IOException to be thrown.
+     *
+     * @see #getJarFile
+     * @see #getJarEntry
+     */
+    public JarEntry getJarEntry() throws IOException {
+        return getJarFile().getJarEntry(entryName);
+    }
+
+    /**
+     * Return the Attributes object for this connection if the URL
+     * for it points to a JAR file entry, null otherwise.
+     *
+     * @return the Attributes object for this connection if the URL
+     * for it points to a JAR file entry, null otherwise.
+     *
+     * @exception IOException if getting the JAR entry causes an
+     * IOException to be thrown.
+     *
+     * @see #getJarEntry
+     */
+    public Attributes getAttributes() throws IOException {
+        JarEntry e = getJarEntry();
+        return e != null ? e.getAttributes() : null;
+    }
+
+    /**
+     * Returns the main Attributes for the JAR file for this
+     * connection.
+     *
+     * @return the main Attributes for the JAR file for this
+     * connection.
+     *
+     * @exception IOException if getting the manifest causes an
+     * IOException to be thrown.
+     *
+     * @see #getJarFile
+     * @see #getManifest
+     */
+    public Attributes getMainAttributes() throws IOException {
+        Manifest man = getManifest();
+        return man != null ? man.getMainAttributes() : null;
+    }
+
+    /**
+     * Return the Certificate object for this connection if the URL
+     * for it points to a JAR file entry, null otherwise. This method
+     * can only be called once
+     * the connection has been completely verified by reading
+     * from the input stream until the end of the stream has been
+     * reached. Otherwise, this method will return {@code null}
+     *
+     * @return the Certificate object for this connection if the URL
+     * for it points to a JAR file entry, null otherwise.
+     *
+     * @exception IOException if getting the JAR entry causes an
+     * IOException to be thrown.
+     *
+     * @see #getJarEntry
+     */
+    public java.security.cert.Certificate[] getCertificates()
+         throws IOException
+    {
+        JarEntry e = getJarEntry();
+        return e != null ? e.getCertificates() : null;
+    }
+}
diff --git a/java/net/MalformedURLException.java b/java/net/MalformedURLException.java
new file mode 100644
index 0000000..7aef75c
--- /dev/null
+++ b/java/net/MalformedURLException.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * Thrown to indicate that a malformed URL has occurred. Either no
+ * legal protocol could be found in a specification string or the
+ * string could not be parsed.
+ *
+ * @author  Arthur van Hoff
+ * @since   JDK1.0
+ */
+public class MalformedURLException extends IOException {
+    private static final long serialVersionUID = -182787522200415866L;
+
+    /**
+     * Constructs a {@code MalformedURLException} with no detail message.
+     */
+    public MalformedURLException() {
+    }
+
+    /**
+     * Constructs a {@code MalformedURLException} with the
+     * specified detail message.
+     *
+     * @param   msg   the detail message.
+     */
+    public MalformedURLException(String msg) {
+        super(msg);
+    }
+}
diff --git a/java/net/MulticastSocket.java b/java/net/MulticastSocket.java
new file mode 100644
index 0000000..83a18c3
--- /dev/null
+++ b/java/net/MulticastSocket.java
@@ -0,0 +1,712 @@
+/*
+ * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+// Android-changed: Updated example code to handle non-ASCII characters
+/**
+ * The multicast datagram socket class is useful for sending
+ * and receiving IP multicast packets.  A MulticastSocket is
+ * a (UDP) DatagramSocket, with additional capabilities for
+ * joining "groups" of other multicast hosts on the internet.
+ * <P>
+ * A multicast group is specified by a class D IP address
+ * and by a standard UDP port number. Class D IP addresses
+ * are in the range <CODE>224.0.0.0</CODE> to <CODE>239.255.255.255</CODE>,
+ * inclusive. The address 224.0.0.0 is reserved and should not be used.
+ * <P>
+ * One would join a multicast group by first creating a MulticastSocket
+ * with the desired port, then invoking the
+ * <CODE>joinGroup(InetAddress groupAddr)</CODE>
+ * method:
+ * <PRE>
+ * // join a Multicast group and send the group salutations
+ * ...
+ * String msg = "Hello";
+ * InetAddress group = InetAddress.getByName("228.5.6.7");
+ * MulticastSocket s = new MulticastSocket(6789);
+ * s.joinGroup(group);
+ * byte[] bytes = msg.getBytes(StandardCharsets.UTF_8);
+ * DatagramPacket hi = new DatagramPacket(bytes, bytes.length,
+ *                             group, 6789);
+ * s.send(hi);
+ * // get their responses!
+ * byte[] buf = new byte[1000];
+ * DatagramPacket recv = new DatagramPacket(buf, buf.length);
+ * s.receive(recv);
+ * ...
+ * // OK, I'm done talking - leave the group...
+ * s.leaveGroup(group);
+ * </PRE>
+ *
+ * When one sends a message to a multicast group, <B>all</B> subscribing
+ * recipients to that host and port receive the message (within the
+ * time-to-live range of the packet, see below).  The socket needn't
+ * be a member of the multicast group to send messages to it.
+ * <P>
+ * When a socket subscribes to a multicast group/port, it receives
+ * datagrams sent by other hosts to the group/port, as do all other
+ * members of the group and port.  A socket relinquishes membership
+ * in a group by the leaveGroup(InetAddress addr) method.  <B>
+ * Multiple MulticastSocket's</B> may subscribe to a multicast group
+ * and port concurrently, and they will all receive group datagrams.
+ * <P>
+ * Currently applets are not allowed to use multicast sockets.
+ *
+ * @author Pavani Diwanji
+ * @since  JDK1.1
+ */
+public
+class MulticastSocket extends DatagramSocket {
+
+    /**
+     * Used on some platforms to record if an outgoing interface
+     * has been set for this socket.
+     */
+    private boolean interfaceSet;
+
+    /**
+     * Create a multicast socket.
+     *
+     * <p>If there is a security manager,
+     * its {@code checkListen} method is first called
+     * with 0 as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     * <p>
+     * When the socket is created the
+     * {@link DatagramSocket#setReuseAddress(boolean)} method is
+     * called to enable the SO_REUSEADDR socket option.
+     *
+     * @exception IOException if an I/O exception occurs
+     * while creating the MulticastSocket
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkListen} method doesn't allow the operation.
+     * @see SecurityManager#checkListen
+     * @see java.net.DatagramSocket#setReuseAddress(boolean)
+     */
+    public MulticastSocket() throws IOException {
+        this(new InetSocketAddress(0));
+    }
+
+    /**
+     * Create a multicast socket and bind it to a specific port.
+     *
+     * <p>If there is a security manager,
+     * its {@code checkListen} method is first called
+     * with the {@code port} argument
+     * as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     * <p>
+     * When the socket is created the
+     * {@link DatagramSocket#setReuseAddress(boolean)} method is
+     * called to enable the SO_REUSEADDR socket option.
+     *
+     * @param port port to use
+     * @exception IOException if an I/O exception occurs
+     * while creating the MulticastSocket
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkListen} method doesn't allow the operation.
+     * @see SecurityManager#checkListen
+     * @see java.net.DatagramSocket#setReuseAddress(boolean)
+     */
+    public MulticastSocket(int port) throws IOException {
+        this(new InetSocketAddress(port));
+    }
+
+    /**
+     * Create a MulticastSocket bound to the specified socket address.
+     * <p>
+     * Or, if the address is {@code null}, create an unbound socket.
+     *
+     * <p>If there is a security manager,
+     * its {@code checkListen} method is first called
+     * with the SocketAddress port as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     * <p>
+     * When the socket is created the
+     * {@link DatagramSocket#setReuseAddress(boolean)} method is
+     * called to enable the SO_REUSEADDR socket option.
+     *
+     * @param bindaddr Socket address to bind to, or {@code null} for
+     *                 an unbound socket.
+     * @exception IOException if an I/O exception occurs
+     * while creating the MulticastSocket
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkListen} method doesn't allow the operation.
+     * @see SecurityManager#checkListen
+     * @see java.net.DatagramSocket#setReuseAddress(boolean)
+     *
+     * @since 1.4
+     */
+    public MulticastSocket(SocketAddress bindaddr) throws IOException {
+        super((SocketAddress) null);
+
+        // Enable SO_REUSEADDR before binding
+        setReuseAddress(true);
+
+        if (bindaddr != null) {
+            try {
+                bind(bindaddr);
+            } finally {
+                if (!isBound())
+                    close();
+            }
+        }
+    }
+
+    /**
+     * The lock on the socket's TTL. This is for set/getTTL and
+     * send(packet,ttl).
+     */
+    private Object ttlLock = new Object();
+
+    /**
+     * The lock on the socket's interface - used by setInterface
+     * and getInterface
+     */
+    private Object infLock = new Object();
+
+    /**
+     * The "last" interface set by setInterface on this MulticastSocket
+     */
+    private InetAddress infAddress = null;
+
+
+    /**
+     * Set the default time-to-live for multicast packets sent out
+     * on this {@code MulticastSocket} in order to control the
+     * scope of the multicasts.
+     *
+     * <p>The ttl is an <b>unsigned</b> 8-bit quantity, and so <B>must</B> be
+     * in the range {@code 0 <= ttl <= 0xFF }.
+     *
+     * @param ttl the time-to-live
+     * @exception IOException if an I/O exception occurs
+     * while setting the default time-to-live value
+     * @deprecated use the setTimeToLive method instead, which uses
+     * <b>int</b> instead of <b>byte</b> as the type for ttl.
+     * @see #getTTL()
+     */
+    @Deprecated
+    public void setTTL(byte ttl) throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setTTL(ttl);
+    }
+
+    /**
+     * Set the default time-to-live for multicast packets sent out
+     * on this {@code MulticastSocket} in order to control the
+     * scope of the multicasts.
+     *
+     * <P> The ttl <B>must</B> be in the range {@code  0 <= ttl <=
+     * 255} or an {@code IllegalArgumentException} will be thrown.
+     * Multicast packets sent with a TTL of {@code 0} are not transmitted
+     * on the network but may be delivered locally.
+     *
+     * @param  ttl
+     *         the time-to-live
+     *
+     * @throws  IOException
+     *          if an I/O exception occurs while setting the
+     *          default time-to-live value
+     *
+     * @see #getTimeToLive()
+     */
+    public void setTimeToLive(int ttl) throws IOException {
+        if (ttl < 0 || ttl > 255) {
+            throw new IllegalArgumentException("ttl out of range");
+        }
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setTimeToLive(ttl);
+    }
+
+    /**
+     * Get the default time-to-live for multicast packets sent out on
+     * the socket.
+     *
+     * @exception IOException if an I/O exception occurs
+     * while getting the default time-to-live value
+     * @return the default time-to-live value
+     * @deprecated use the getTimeToLive method instead, which returns
+     * an <b>int</b> instead of a <b>byte</b>.
+     * @see #setTTL(byte)
+     */
+    @Deprecated
+    public byte getTTL() throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        return getImpl().getTTL();
+    }
+
+    /**
+     * Get the default time-to-live for multicast packets sent out on
+     * the socket.
+     * @exception IOException if an I/O exception occurs while
+     * getting the default time-to-live value
+     * @return the default time-to-live value
+     * @see #setTimeToLive(int)
+     */
+    public int getTimeToLive() throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        return getImpl().getTimeToLive();
+    }
+
+    /**
+     * Joins a multicast group. Its behavior may be affected by
+     * {@code setInterface} or {@code setNetworkInterface}.
+     *
+     * <p>If there is a security manager, this method first
+     * calls its {@code checkMulticast} method
+     * with the {@code mcastaddr} argument
+     * as its argument.
+     *
+     * @param mcastaddr is the multicast address to join
+     *
+     * @exception IOException if there is an error joining
+     * or when the address is not a multicast address.
+     * @exception  SecurityException  if a security manager exists and its
+     * {@code checkMulticast} method doesn't allow the join.
+     *
+     * @see SecurityManager#checkMulticast(InetAddress)
+     */
+    public void joinGroup(InetAddress mcastaddr) throws IOException {
+        if (isClosed()) {
+            throw new SocketException("Socket is closed");
+        }
+
+        checkAddress(mcastaddr, "joinGroup");
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkMulticast(mcastaddr);
+        }
+
+        if (!mcastaddr.isMulticastAddress()) {
+            throw new SocketException("Not a multicast address");
+        }
+
+        /**
+         * required for some platforms where it's not possible to join
+         * a group without setting the interface first.
+         */
+        NetworkInterface defaultInterface = NetworkInterface.getDefault();
+
+        if (!interfaceSet && defaultInterface != null) {
+            setNetworkInterface(defaultInterface);
+        }
+
+        getImpl().join(mcastaddr);
+    }
+
+    /**
+     * Leave a multicast group. Its behavior may be affected by
+     * {@code setInterface} or {@code setNetworkInterface}.
+     *
+     * <p>If there is a security manager, this method first
+     * calls its {@code checkMulticast} method
+     * with the {@code mcastaddr} argument
+     * as its argument.
+     *
+     * @param mcastaddr is the multicast address to leave
+     * @exception IOException if there is an error leaving
+     * or when the address is not a multicast address.
+     * @exception  SecurityException  if a security manager exists and its
+     * {@code checkMulticast} method doesn't allow the operation.
+     *
+     * @see SecurityManager#checkMulticast(InetAddress)
+     */
+    public void leaveGroup(InetAddress mcastaddr) throws IOException {
+        if (isClosed()) {
+            throw new SocketException("Socket is closed");
+        }
+
+        checkAddress(mcastaddr, "leaveGroup");
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkMulticast(mcastaddr);
+        }
+
+        if (!mcastaddr.isMulticastAddress()) {
+            throw new SocketException("Not a multicast address");
+        }
+
+        getImpl().leave(mcastaddr);
+    }
+
+    /**
+     * Joins the specified multicast group at the specified interface.
+     *
+     * <p>If there is a security manager, this method first
+     * calls its {@code checkMulticast} method
+     * with the {@code mcastaddr} argument
+     * as its argument.
+     *
+     * @param mcastaddr is the multicast address to join
+     * @param netIf specifies the local interface to receive multicast
+     *        datagram packets, or <i>null</i> to defer to the interface set by
+     *       {@link MulticastSocket#setInterface(InetAddress)} or
+     *       {@link MulticastSocket#setNetworkInterface(NetworkInterface)}
+     *
+     * @exception IOException if there is an error joining
+     * or when the address is not a multicast address.
+     * @exception  SecurityException  if a security manager exists and its
+     * {@code checkMulticast} method doesn't allow the join.
+     * @throws  IllegalArgumentException if mcastaddr is null or is a
+     *          SocketAddress subclass not supported by this socket
+     *
+     * @see SecurityManager#checkMulticast(InetAddress)
+     * @since 1.4
+     */
+    public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf)
+        throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+
+        if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress))
+            throw new IllegalArgumentException("Unsupported address type");
+
+        if (oldImpl)
+            throw new UnsupportedOperationException();
+
+        checkAddress(((InetSocketAddress)mcastaddr).getAddress(), "joinGroup");
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkMulticast(((InetSocketAddress)mcastaddr).getAddress());
+        }
+
+        if (!((InetSocketAddress)mcastaddr).getAddress().isMulticastAddress()) {
+            throw new SocketException("Not a multicast address");
+        }
+
+        getImpl().joinGroup(mcastaddr, netIf);
+    }
+
+    /**
+     * Leave a multicast group on a specified local interface.
+     *
+     * <p>If there is a security manager, this method first
+     * calls its {@code checkMulticast} method
+     * with the {@code mcastaddr} argument
+     * as its argument.
+     *
+     * @param mcastaddr is the multicast address to leave
+     * @param netIf specifies the local interface or <i>null</i> to defer
+     *             to the interface set by
+     *             {@link MulticastSocket#setInterface(InetAddress)} or
+     *             {@link MulticastSocket#setNetworkInterface(NetworkInterface)}
+     * @exception IOException if there is an error leaving
+     * or when the address is not a multicast address.
+     * @exception  SecurityException  if a security manager exists and its
+     * {@code checkMulticast} method doesn't allow the operation.
+     * @throws  IllegalArgumentException if mcastaddr is null or is a
+     *          SocketAddress subclass not supported by this socket
+     *
+     * @see SecurityManager#checkMulticast(InetAddress)
+     * @since 1.4
+     */
+    public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf)
+        throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+
+        if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress))
+            throw new IllegalArgumentException("Unsupported address type");
+
+        if (oldImpl)
+            throw new UnsupportedOperationException();
+
+        checkAddress(((InetSocketAddress)mcastaddr).getAddress(), "leaveGroup");
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkMulticast(((InetSocketAddress)mcastaddr).getAddress());
+        }
+
+        if (!((InetSocketAddress)mcastaddr).getAddress().isMulticastAddress()) {
+            throw new SocketException("Not a multicast address");
+        }
+
+        getImpl().leaveGroup(mcastaddr, netIf);
+     }
+
+    /**
+     * Set the multicast network interface used by methods
+     * whose behavior would be affected by the value of the
+     * network interface. Useful for multihomed hosts.
+     * @param inf the InetAddress
+     * @exception SocketException if there is an error in
+     * the underlying protocol, such as a TCP error.
+     * @see #getInterface()
+     */
+    public void setInterface(InetAddress inf) throws SocketException {
+        if (isClosed()) {
+            throw new SocketException("Socket is closed");
+        }
+        checkAddress(inf, "setInterface");
+        synchronized (infLock) {
+            getImpl().setOption(SocketOptions.IP_MULTICAST_IF, inf);
+            infAddress = inf;
+            interfaceSet = true;
+        }
+    }
+
+    /**
+     * Retrieve the address of the network interface used for
+     * multicast packets.
+     *
+     * @return An {@code InetAddress} representing
+     *  the address of the network interface used for
+     *  multicast packets.
+     *
+     * @exception SocketException if there is an error in
+     * the underlying protocol, such as a TCP error.
+     *
+     * @see #setInterface(java.net.InetAddress)
+     */
+    public InetAddress getInterface() throws SocketException {
+        if (isClosed()) {
+            throw new SocketException("Socket is closed");
+        }
+        synchronized (infLock) {
+            InetAddress ia =
+                (InetAddress)getImpl().getOption(SocketOptions.IP_MULTICAST_IF);
+
+            /**
+             * No previous setInterface or interface can be
+             * set using setNetworkInterface
+             */
+            if (infAddress == null) {
+                return ia;
+            }
+
+            /**
+             * Same interface set with setInterface?
+             */
+            if (ia.equals(infAddress)) {
+                return ia;
+            }
+
+            /**
+             * Different InetAddress from what we set with setInterface
+             * so enumerate the current interface to see if the
+             * address set by setInterface is bound to this interface.
+             */
+            try {
+                NetworkInterface ni = NetworkInterface.getByInetAddress(ia);
+                Enumeration<InetAddress> addrs = ni.getInetAddresses();
+                while (addrs.hasMoreElements()) {
+                    InetAddress addr = addrs.nextElement();
+                    if (addr.equals(infAddress)) {
+                        return infAddress;
+                    }
+                }
+
+                /**
+                 * No match so reset infAddress to indicate that the
+                 * interface has changed via means
+                 */
+                infAddress = null;
+                return ia;
+            } catch (Exception e) {
+                return ia;
+            }
+        }
+    }
+
+    /**
+     * Specify the network interface for outgoing multicast datagrams
+     * sent on this socket.
+     *
+     * @param netIf the interface
+     * @exception SocketException if there is an error in
+     * the underlying protocol, such as a TCP error.
+     * @see #getNetworkInterface()
+     * @since 1.4
+     */
+    public void setNetworkInterface(NetworkInterface netIf)
+        throws SocketException {
+
+        synchronized (infLock) {
+            getImpl().setOption(SocketOptions.IP_MULTICAST_IF2, netIf);
+            infAddress = null;
+            interfaceSet = true;
+        }
+    }
+
+    /**
+     * Get the multicast network interface set.
+     *
+     * @exception SocketException if there is an error in
+     * the underlying protocol, such as a TCP error.
+     * @return the multicast {@code NetworkInterface} currently set
+     * @see #setNetworkInterface(NetworkInterface)
+     * @since 1.4
+     */
+    public NetworkInterface getNetworkInterface() throws SocketException {
+        // Android-changed: Support Integer IP_MULTICAST_IF2 values for app compat.
+        Integer niIndex
+            = (Integer)getImpl().getOption(SocketOptions.IP_MULTICAST_IF2);
+        if (niIndex == 0) {
+            InetAddress[] addrs = new InetAddress[1];
+            addrs[0] = InetAddress.anyLocalAddress();
+            return new NetworkInterface(addrs[0].getHostName(), 0, addrs);
+        } else {
+            return NetworkInterface.getByIndex(niIndex);
+        }
+    }
+
+    /**
+     * Disable/Enable local loopback of multicast datagrams
+     * The option is used by the platform's networking code as a hint
+     * for setting whether multicast data will be looped back to
+     * the local socket.
+     *
+     * <p>Because this option is a hint, applications that want to
+     * verify what loopback mode is set to should call
+     * {@link #getLoopbackMode()}
+     * @param disable {@code true} to disable the LoopbackMode
+     * @throws SocketException if an error occurs while setting the value
+     * @since 1.4
+     * @see #getLoopbackMode
+     */
+    public void setLoopbackMode(boolean disable) throws SocketException {
+        getImpl().setOption(SocketOptions.IP_MULTICAST_LOOP, Boolean.valueOf(disable));
+    }
+
+    /**
+     * Get the setting for local loopback of multicast datagrams.
+     *
+     * @throws SocketException  if an error occurs while getting the value
+     * @return true if the LoopbackMode has been disabled
+     * @since 1.4
+     * @see #setLoopbackMode
+     */
+    public boolean getLoopbackMode() throws SocketException {
+        return ((Boolean)getImpl().getOption(SocketOptions.IP_MULTICAST_LOOP)).booleanValue();
+    }
+
+    /**
+     * Sends a datagram packet to the destination, with a TTL (time-
+     * to-live) other than the default for the socket.  This method
+     * need only be used in instances where a particular TTL is desired;
+     * otherwise it is preferable to set a TTL once on the socket, and
+     * use that default TTL for all packets.  This method does <B>not
+     * </B> alter the default TTL for the socket. Its behavior may be
+     * affected by {@code setInterface}.
+     *
+     * <p>If there is a security manager, this method first performs some
+     * security checks. First, if {@code p.getAddress().isMulticastAddress()}
+     * is true, this method calls the
+     * security manager's {@code checkMulticast} method
+     * with {@code p.getAddress()} and {@code ttl} as its arguments.
+     * If the evaluation of that expression is false,
+     * this method instead calls the security manager's
+     * {@code checkConnect} method with arguments
+     * {@code p.getAddress().getHostAddress()} and
+     * {@code p.getPort()}. Each call to a security manager method
+     * could result in a SecurityException if the operation is not allowed.
+     *
+     * @param p is the packet to be sent. The packet should contain
+     * the destination multicast ip address and the data to be sent.
+     * One does not need to be the member of the group to send
+     * packets to a destination multicast address.
+     * @param ttl optional time to live for multicast packet.
+     * default ttl is 1.
+     *
+     * @exception IOException is raised if an error occurs i.e
+     * error while setting ttl.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkMulticast} or {@code checkConnect}
+     *             method doesn't allow the send.
+     *
+     * @deprecated Use the following code or its equivalent instead:
+     *  ......
+     *  int ttl = mcastSocket.getTimeToLive();
+     *  mcastSocket.setTimeToLive(newttl);
+     *  mcastSocket.send(p);
+     *  mcastSocket.setTimeToLive(ttl);
+     *  ......
+     *
+     * @see DatagramSocket#send
+     * @see DatagramSocket#receive
+     * @see SecurityManager#checkMulticast(java.net.InetAddress, byte)
+     * @see SecurityManager#checkConnect
+     */
+    @Deprecated
+    public void send(DatagramPacket p, byte ttl)
+        throws IOException {
+            if (isClosed())
+                throw new SocketException("Socket is closed");
+            checkAddress(p.getAddress(), "send");
+            synchronized(ttlLock) {
+                synchronized(p) {
+                    if (connectState == ST_NOT_CONNECTED) {
+                        // Security manager makes sure that the multicast address
+                        // is allowed one and that the ttl used is less
+                        // than the allowed maxttl.
+                        SecurityManager security = System.getSecurityManager();
+                        if (security != null) {
+                            if (p.getAddress().isMulticastAddress()) {
+                                security.checkMulticast(p.getAddress(), ttl);
+                            } else {
+                                security.checkConnect(p.getAddress().getHostAddress(),
+                                                      p.getPort());
+                            }
+                        }
+                    } else {
+                        // we're connected
+                        InetAddress packetAddress = null;
+                        packetAddress = p.getAddress();
+                        if (packetAddress == null) {
+                            p.setAddress(connectedAddress);
+                            p.setPort(connectedPort);
+                        } else if ((!packetAddress.equals(connectedAddress)) ||
+                                   p.getPort() != connectedPort) {
+                            throw new SecurityException("connected address and packet address" +
+                                                        " differ");
+                        }
+                    }
+                    byte dttl = getTTL();
+                    try {
+                        if (ttl != dttl) {
+                            // set the ttl
+                            getImpl().setTTL(ttl);
+                        }
+                        // call the datagram method to send
+                        getImpl().send(p);
+                    } finally {
+                        // set it back to default
+                        if (ttl != dttl) {
+                            getImpl().setTTL(dttl);
+                        }
+                    }
+                } // synch p
+            }  //synch ttl
+    } //method
+}
diff --git a/java/net/NetPermission.java b/java/net/NetPermission.java
new file mode 100644
index 0000000..b5a0eab
--- /dev/null
+++ b/java/net/NetPermission.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.security.*;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public final class NetPermission extends BasicPermission {
+
+    public NetPermission(String name)
+    {
+        super("");
+    }
+
+    public NetPermission(String name, String actions)
+    {
+        super("", "");
+    }
+}
diff --git a/java/net/NetworkInterface.java b/java/net/NetworkInterface.java
new file mode 100644
index 0000000..a30b6bf
--- /dev/null
+++ b/java/net/NetworkInterface.java
@@ -0,0 +1,748 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import android.system.ErrnoException;
+
+import java.io.FileDescriptor;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import android.system.StructIfaddrs;
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+import sun.security.action.*;
+import java.security.AccessController;
+
+import static android.system.OsConstants.*;
+
+// Android-note: NetworkInterface has been rewritten to avoid native code.
+// Fix upstream bug not returning link-down interfaces. http://b/26238832
+// Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
+/**
+ * This class represents a Network Interface made up of a name,
+ * and a list of IP addresses assigned to this interface.
+ * It is used to identify the local interface on which a multicast group
+ * is joined.
+ *
+ * Interfaces are normally known by names such as "le0".
+ * <p>
+ * <a name="access-restrictions"></a>Note that information about
+ * {@link NetworkInterface}s may be restricted. For example, non-system apps
+ * with {@code targetSdkVersion >= android.os.Build.VERSION_CODES.R} will only
+ * have access to information about {@link NetworkInterface}s that are
+ * associated with an {@link InetAddress}.
+ *
+ * @since 1.4
+ */
+public final class NetworkInterface {
+    private String name;
+    private String displayName;
+    private int index;
+    private InetAddress addrs[];
+    private InterfaceAddress bindings[];
+    // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+    // private NetworkInterface childs[];
+    private List<NetworkInterface> childs;
+    private NetworkInterface parent = null;
+    private boolean virtual = false;
+    private static final NetworkInterface defaultInterface;
+    private static final int defaultIndex; /* index of defaultInterface */
+
+    // Android-changed: Fix upstream bug not returning link-down interfaces. http://b/26238832
+    private byte[] hardwareAddr;
+
+    static {
+        // Android-removed: Android doesn't need to call native init.
+        /*
+        AccessController.doPrivileged(
+            new java.security.PrivilegedAction<Void>() {
+                public Void run() {
+                    System.loadLibrary("net");
+                    return null;
+                }
+            });
+
+        init();
+        */
+        defaultInterface = DefaultInterface.getDefault();
+        if (defaultInterface != null) {
+            defaultIndex = defaultInterface.getIndex();
+        } else {
+            defaultIndex = 0;
+        }
+    }
+
+    /**
+     * Returns an NetworkInterface object with index set to 0 and name to null.
+     * Setting such an interface on a MulticastSocket will cause the
+     * kernel to choose one interface for sending multicast packets.
+     *
+     */
+    NetworkInterface() {
+    }
+
+    NetworkInterface(String name, int index, InetAddress[] addrs) {
+        this.name = name;
+        this.index = index;
+        this.addrs = addrs;
+    }
+
+    /**
+     * Get the name of this network interface.
+     *
+     * @return the name of this network interface
+     */
+    public String getName() {
+            return name;
+    }
+
+    /**
+     * Convenience method to return an Enumeration with all or a
+     * subset of the InetAddresses bound to this network interface.
+     * <p>
+     * If there is a security manager, its {@code checkConnect}
+     * method is called for each InetAddress. Only InetAddresses where
+     * the {@code checkConnect} doesn't throw a SecurityException
+     * will be returned in the Enumeration. However, if the caller has the
+     * {@link NetPermission}("getNetworkInformation") permission, then all
+     * InetAddresses are returned.
+     * @return an Enumeration object with all or a subset of the InetAddresses
+     * bound to this network interface
+     */
+    public Enumeration<InetAddress> getInetAddresses() {
+
+        class checkedAddresses implements Enumeration<InetAddress> {
+
+            private int i=0, count=0;
+            private InetAddress local_addrs[];
+
+            checkedAddresses() {
+                local_addrs = new InetAddress[addrs.length];
+                boolean trusted = true;
+
+                SecurityManager sec = System.getSecurityManager();
+                if (sec != null) {
+                    try {
+                        sec.checkPermission(new NetPermission("getNetworkInformation"));
+                    } catch (SecurityException e) {
+                        trusted = false;
+                    }
+                }
+                for (int j=0; j<addrs.length; j++) {
+                    try {
+                        if (sec != null && !trusted) {
+                            sec.checkConnect(addrs[j].getHostAddress(), -1);
+                        }
+                        local_addrs[count++] = addrs[j];
+                    } catch (SecurityException e) { }
+                }
+
+            }
+
+            public InetAddress nextElement() {
+                if (i < count) {
+                    return local_addrs[i++];
+                } else {
+                    throw new NoSuchElementException();
+                }
+            }
+
+            public boolean hasMoreElements() {
+                return (i < count);
+            }
+        }
+        return new checkedAddresses();
+
+    }
+
+    /**
+     * Get a List of all or a subset of the {@code InterfaceAddresses}
+     * of this network interface.
+     * <p>
+     * If there is a security manager, its {@code checkConnect}
+     * method is called with the InetAddress for each InterfaceAddress.
+     * Only InterfaceAddresses where the {@code checkConnect} doesn't throw
+     * a SecurityException will be returned in the List.
+     *
+     * @return a {@code List} object with all or a subset of the
+     *         InterfaceAddresss of this network interface
+     * @since 1.6
+     */
+    public java.util.List<InterfaceAddress> getInterfaceAddresses() {
+        java.util.List<InterfaceAddress> lst = new java.util.ArrayList<InterfaceAddress>(1);
+        // BEGIN Android-changed: Cherry-picked upstream OpenJDK9 change rev 59a110a38cea
+        // http://b/30628919
+        if (bindings != null) {
+            SecurityManager sec = System.getSecurityManager();
+            for (int j=0; j<bindings.length; j++) {
+                try {
+                    if (sec != null) {
+                        sec.checkConnect(bindings[j].getAddress().getHostAddress(), -1);
+                    }
+                    lst.add(bindings[j]);
+                } catch (SecurityException e) { }
+            }
+        }
+        // END Android-changed: Cherry-picked upstream OpenJDK9 change rev 59a110a38cea
+        return lst;
+    }
+
+    /**
+     * Get an Enumeration with all the subinterfaces (also known as virtual
+     * interfaces) attached to this network interface.
+     * <p>
+     * For instance eth0:1 will be a subinterface to eth0.
+     *
+     * @return an Enumeration object with all of the subinterfaces
+     * of this network interface
+     * @since 1.6
+     */
+    public Enumeration<NetworkInterface> getSubInterfaces() {
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        return Collections.enumeration(childs);
+    }
+
+    /**
+     * Returns the parent NetworkInterface of this interface if this is
+     * a subinterface, or {@code null} if it is a physical
+     * (non virtual) interface or has no parent.
+     *
+     * @return The {@code NetworkInterface} this interface is attached to.
+     * @since 1.6
+     */
+    public NetworkInterface getParent() {
+        return parent;
+    }
+
+    /**
+     * Returns the index of this network interface. The index is an integer greater
+     * or equal to zero, or {@code -1} for unknown. This is a system specific value
+     * and interfaces with the same name can have different indexes on different
+     * machines.
+     *
+     * @return the index of this network interface or {@code -1} if the index is
+     *         unknown
+     * @see #getByIndex(int)
+     * @since 1.7
+     */
+    public int getIndex() {
+        return index;
+    }
+
+    /**
+     * Get the display name of this network interface.
+     * A display name is a human readable String describing the network
+     * device.
+     *
+     * @return a non-empty string representing the display name of this network
+     *         interface, or null if no display name is available.
+     */
+    public String getDisplayName() {
+        /* strict TCK conformance */
+        return "".equals(displayName) ? null : displayName;
+    }
+
+    // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
+    /**
+     * Searches for the network interface with the specified name.
+     *
+     * @param   name
+     *          The name of the network interface.
+     *
+     * @return  A {@code NetworkInterface} with the specified name,
+     *          or {@code null} if the network interface with the specified
+     *          name does not exist or <a href="#access-restrictions">can't be
+     *          accessed</a>.
+     *
+     * @throws  SocketException
+     *          If an I/O error occurs.
+     *
+     * @throws  NullPointerException
+     *          If the specified name is {@code null}.
+     */
+    public static NetworkInterface getByName(String name) throws SocketException {
+        if (name == null)
+            throw new NullPointerException();
+
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        NetworkInterface[] nis = getAll();
+        for (NetworkInterface ni : nis) {
+            if (ni.getName().equals(name)) {
+                return ni;
+            }
+        }
+        return null;
+    }
+
+    // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
+    /**
+     * Get a network interface given its index.
+     *
+     * @param index an integer, the index of the interface
+     * @return the NetworkInterface obtained from its index, or {@code null} if
+     *         an interface with the specified index does not exist or
+     *         <a href="#access-restrictions">can't be accessed</a>.
+     * @throws  SocketException  if an I/O error occurs.
+     * @throws  IllegalArgumentException if index has a negative value
+     * @see #getIndex()
+     * @since 1.7
+     */
+    public static NetworkInterface getByIndex(int index) throws SocketException {
+        if (index < 0)
+            throw new IllegalArgumentException("Interface index can't be negative");
+
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        NetworkInterface[] nis = getAll();
+        for (NetworkInterface ni : nis) {
+            if (ni.getIndex() == index) {
+                return ni;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Convenience method to search for a network interface that
+     * has the specified Internet Protocol (IP) address bound to
+     * it.
+     * <p>
+     * If the specified IP address is bound to multiple network
+     * interfaces it is not defined which network interface is
+     * returned.
+     *
+     * @param   addr
+     *          The {@code InetAddress} to search with.
+     *
+     * @return  A {@code NetworkInterface}
+     *          or {@code null} if there is no network interface
+     *          with the specified IP address.
+     *
+     * @throws  SocketException
+     *          If an I/O error occurs.
+     *
+     * @throws  NullPointerException
+     *          If the specified address is {@code null}.
+     */
+    public static NetworkInterface getByInetAddress(InetAddress addr) throws SocketException {
+        if (addr == null) {
+            throw new NullPointerException();
+        }
+        if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) {
+            throw new IllegalArgumentException ("invalid address type");
+        }
+
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        NetworkInterface[] nis = getAll();
+        for (NetworkInterface ni : nis) {
+            for (InetAddress inetAddress : Collections.list(ni.getInetAddresses())) {
+                if (inetAddress.equals(addr)) {
+                    return ni;
+                }
+            }
+        }
+        return null;
+    }
+
+    // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
+    /**
+     * Returns all the interfaces on this machine. The {@code Enumeration}
+     * contains at least one element, possibly representing a loopback
+     * interface that only supports communication between entities on
+     * this machine.
+     *
+     * NOTE: can use getNetworkInterfaces()+getInetAddresses()
+     *       to obtain all IP addresses for this node
+     * <p>
+     * For non-system apps with
+     * {@code targetSdkVersion >= android.os.Build.VERSION_CODES.R}, this
+     * method will only return information for {@link NetworkInterface}s that
+     * are associated with an {@link InetAddress}.
+     *
+     * @return an Enumeration of NetworkInterfaces found on this machine
+     *         that <a href="#access-restrictions">are accessible</a>.
+     * @exception  SocketException  if an I/O error occurs.
+     */
+
+    public static Enumeration<NetworkInterface> getNetworkInterfaces()
+        throws SocketException {
+        final NetworkInterface[] netifs = getAll();
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        // // specified to return null if no network interfaces
+        // if (netifs == null)
+        if (netifs.length == 0)
+            return null;
+
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        /*
+        return new Enumeration<NetworkInterface>() {
+            private int i = 0;
+            public NetworkInterface nextElement() {
+                if (netifs != null && i < netifs.length) {
+                    NetworkInterface netif = netifs[i++];
+                    return netif;
+                } else {
+                    throw new NoSuchElementException();
+                }
+            }
+
+            public boolean hasMoreElements() {
+                return (netifs != null && i < netifs.length);
+            }
+        };
+        */
+        return Collections.enumeration(Arrays.asList(netifs));
+    }
+
+    // BEGIN Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+    // private native static NetworkInterface[] getAll()
+    //    throws SocketException;
+    private static NetworkInterface[] getAll() throws SocketException {
+        // Group Ifaddrs by interface name.
+        Map<String, List<StructIfaddrs>> inetMap = new HashMap<>();
+
+        StructIfaddrs[] ifaddrs;
+        try {
+            ifaddrs = Libcore.os.getifaddrs();
+        } catch (ErrnoException e) {
+            throw e.rethrowAsSocketException();
+        }
+
+        for (StructIfaddrs ifa : ifaddrs) {
+            String name = ifa.ifa_name;
+
+            List<StructIfaddrs> ifas;
+            if ((ifas = inetMap.get(name)) == null) {
+                ifas = new ArrayList<>();
+                inetMap.put(name, ifas);
+            }
+
+            ifas.add(ifa);
+        }
+
+        // Populate NetworkInterface instances.
+        Map<String, NetworkInterface> nis = new HashMap<>(inetMap.size());
+        for (Map.Entry<String, List<StructIfaddrs>> e : inetMap.entrySet()) {
+            String name = e.getKey();
+            int index = Libcore.os.if_nametoindex(e.getKey());
+            if (index == 0) {
+                // This interface has gone away between getifaddrs and if_nametoindex
+                continue;
+            }
+
+            NetworkInterface ni = new NetworkInterface(name, index, null);
+            ni.displayName = name;
+
+            List<InetAddress> addrs = new ArrayList<>();
+            List<InterfaceAddress> binds = new ArrayList<>();
+
+            for (StructIfaddrs ifa : e.getValue()) {
+                if (ifa.ifa_addr != null) {
+                    addrs.add(ifa.ifa_addr);
+                    binds.add(new InterfaceAddress(ifa.ifa_addr, (Inet4Address) ifa.ifa_broadaddr,
+                                                   ifa.ifa_netmask));
+                }
+
+                if (ifa.hwaddr != null) {
+                    ni.hardwareAddr = ifa.hwaddr;
+                }
+            }
+
+            ni.addrs = addrs.toArray(new InetAddress[addrs.size()]);
+            ni.bindings = binds.toArray(new InterfaceAddress[binds.size()]);
+            ni.childs = new ArrayList<>(0);
+            nis.put(name, ni);
+        }
+
+        // Populate childs/parent.
+        for (Map.Entry<String, NetworkInterface> e : nis.entrySet()) {
+            NetworkInterface ni = e.getValue();
+            String niName = ni.getName();
+            int colonIdx = niName.indexOf(':');
+            if (colonIdx != -1) {
+                // This is a virtual interface.
+                String parentName = niName.substring(0, colonIdx);
+                NetworkInterface parent = nis.get(parentName);
+
+                ni.virtual = true;
+                ni.parent = parent;
+                parent.childs.add(ni);
+            }
+        }
+
+        return nis.values().toArray(new NetworkInterface[nis.size()]);
+    }
+    // END Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+
+    /**
+     * Returns whether a network interface is up and running.
+     *
+     * @return  {@code true} if the interface is up and running.
+     * @exception       SocketException if an I/O error occurs.
+     * @since 1.6
+     */
+
+    public boolean isUp() throws SocketException {
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        final int mask = IFF_UP | IFF_RUNNING;
+        return (getFlags() & mask) == mask;
+    }
+
+    /**
+     * Returns whether a network interface is a loopback interface.
+     *
+     * @return  {@code true} if the interface is a loopback interface.
+     * @exception       SocketException if an I/O error occurs.
+     * @since 1.6
+     */
+
+    public boolean isLoopback() throws SocketException {
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        return (getFlags() & IFF_LOOPBACK) != 0;
+    }
+
+    /**
+     * Returns whether a network interface is a point to point interface.
+     * A typical point to point interface would be a PPP connection through
+     * a modem.
+     *
+     * @return  {@code true} if the interface is a point to point
+     *          interface.
+     * @exception       SocketException if an I/O error occurs.
+     * @since 1.6
+     */
+
+    public boolean isPointToPoint() throws SocketException {
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        return (getFlags() & IFF_POINTOPOINT) != 0;
+    }
+
+    /**
+     * Returns whether a network interface supports multicasting or not.
+     *
+     * @return  {@code true} if the interface supports Multicasting.
+     * @exception       SocketException if an I/O error occurs.
+     * @since 1.6
+     */
+
+    public boolean supportsMulticast() throws SocketException {
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        return (getFlags() & IFF_MULTICAST) != 0;
+    }
+
+    // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
+    /**
+     * Returns the hardware address (usually MAC) of the interface if it
+     * has one and if it can be accessed given the current privileges.
+     * If a security manager is set, then the caller must have
+     * the permission {@link NetPermission}("getNetworkInformation").
+     *
+     * @return  a byte array containing the address, or {@code null} if
+     *          the address doesn't exist, is not accessible or a security
+     *          manager is set and the caller does not have the permission
+     *          NetPermission("getNetworkInformation"). For example, this
+     *          method will generally return {@code null} when called by
+     *          non-system apps having
+     *          {@code targetSdkVersion >= android.os.Build.VERSION_CODES.R}.
+     *
+     * @exception       SocketException if an I/O error occurs.
+     * @since 1.6
+     */
+    public byte[] getHardwareAddress() throws SocketException {
+        // BEGIN Android-changed: Fix upstream not returning link-down interfaces. http://b/26238832
+        /*
+        for (InetAddress addr : addrs) {
+            if (addr instanceof Inet4Address) {
+                return getMacAddr0(((Inet4Address)addr).getAddress(), name, index);
+            }
+        }
+        return getMacAddr0(null, name, index);
+         */
+        NetworkInterface ni = getByName(name);
+        if (ni == null) {
+            throw new SocketException("NetworkInterface doesn't exist anymore");
+        }
+        return ni.hardwareAddr;
+        // END Android-changed: Fix upstream not returning link-down interfaces. http://b/26238832
+    }
+
+    /**
+     * Returns the Maximum Transmission Unit (MTU) of this interface.
+     *
+     * @return the value of the MTU for that interface.
+     * @exception       SocketException if an I/O error occurs.
+     * @since 1.6
+     */
+    public int getMTU() throws SocketException {
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        // return getMTU0(name, index);
+        FileDescriptor fd = null;
+        try {
+            fd = Libcore.rawOs.socket(AF_INET, SOCK_DGRAM, 0);
+            return Libcore.rawOs.ioctlMTU(fd, name);
+        } catch (ErrnoException e) {
+            throw e.rethrowAsSocketException();
+        } catch (Exception ex) {
+            throw new SocketException(ex);
+        } finally {
+            IoUtils.closeQuietly(fd);
+        }
+    }
+
+    /**
+     * Returns whether this interface is a virtual interface (also called
+     * subinterface).
+     * Virtual interfaces are, on some systems, interfaces created as a child
+     * of a physical interface and given different settings (like address or
+     * MTU). Usually the name of the interface will the name of the parent
+     * followed by a colon (:) and a number identifying the child since there
+     * can be several virtual interfaces attached to a single physical
+     * interface.
+     *
+     * @return {@code true} if this interface is a virtual interface.
+     * @since 1.6
+     */
+    public boolean isVirtual() {
+        return virtual;
+    }
+
+    // BEGIN Android-removed: Rewrote NetworkInterface on top of Libcore.io.
+    /*
+    private native static boolean isUp0(String name, int ind) throws SocketException;
+    private native static boolean isLoopback0(String name, int ind) throws SocketException;
+    private native static boolean supportsMulticast0(String name, int ind) throws SocketException;
+    private native static boolean isP2P0(String name, int ind) throws SocketException;
+    private native static byte[] getMacAddr0(byte[] inAddr, String name, int ind) throws SocketException;
+    private native static int getMTU0(String name, int ind) throws SocketException;
+    */
+    // END Android-removed: Rewrote NetworkInterface on top of Libcore.io.
+
+    // BEGIN Android-added: Rewrote NetworkInterface on top of Libcore.io.
+    private int getFlags() throws SocketException {
+        FileDescriptor fd = null;
+        try {
+            fd = Libcore.rawOs.socket(AF_INET, SOCK_DGRAM, 0);
+            return Libcore.rawOs.ioctlFlags(fd, name);
+        } catch (ErrnoException e) {
+            throw e.rethrowAsSocketException();
+        } catch (Exception ex) {
+            throw new SocketException(ex);
+        } finally {
+            IoUtils.closeQuietly(fd);
+        }
+    }
+    // END Android-added: Rewrote NetworkInterface on top of Libcore.io.
+
+    /**
+     * Compares this object against the specified object.
+     * The result is {@code true} if and only if the argument is
+     * not {@code null} and it represents the same NetworkInterface
+     * as this object.
+     * <p>
+     * Two instances of {@code NetworkInterface} represent the same
+     * NetworkInterface if both name and addrs are the same for both.
+     *
+     * @param   obj   the object to compare against.
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     * @see     java.net.InetAddress#getAddress()
+     */
+    public boolean equals(Object obj) {
+        if (!(obj instanceof NetworkInterface)) {
+            return false;
+        }
+        NetworkInterface that = (NetworkInterface)obj;
+        if (this.name != null ) {
+            if (!this.name.equals(that.name)) {
+                return false;
+            }
+        } else {
+            if (that.name != null) {
+                return false;
+            }
+        }
+
+        if (this.addrs == null) {
+            return that.addrs == null;
+        } else if (that.addrs == null) {
+            return false;
+        }
+
+        /* Both addrs not null. Compare number of addresses */
+
+        if (this.addrs.length != that.addrs.length) {
+            return false;
+        }
+
+        InetAddress[] thatAddrs = that.addrs;
+        int count = thatAddrs.length;
+
+        for (int i=0; i<count; i++) {
+            boolean found = false;
+            for (int j=0; j<count; j++) {
+                if (addrs[i].equals(thatAddrs[j])) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public int hashCode() {
+        return name == null? 0: name.hashCode();
+    }
+
+    public String toString() {
+        String result = "name:";
+        result += name == null? "null": name;
+        if (displayName != null) {
+            result += " (" + displayName + ")";
+        }
+        return result;
+    }
+
+    // Android-removed: Android doesn't need to call native init.
+    // private static native void init();
+
+    /**
+     * Returns the default network interface of this system
+     *
+     * @return the default interface
+     */
+    static NetworkInterface getDefault() {
+        return defaultInterface;
+    }
+}
diff --git a/java/net/NoRouteToHostException.java b/java/net/NoRouteToHostException.java
new file mode 100644
index 0000000..76f0814
--- /dev/null
+++ b/java/net/NoRouteToHostException.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * Signals that an error occurred while attempting to connect a
+ * socket to a remote address and port.  Typically, the remote
+ * host cannot be reached because of an intervening firewall, or
+ * if an intermediate router is down.
+ *
+ * @since   JDK1.1
+ */
+public class NoRouteToHostException extends SocketException {
+    private static final long serialVersionUID = -1897550894873493790L;
+
+    /**
+     * Constructs a new NoRouteToHostException with the specified detail
+     * message as to why the remote host cannot be reached.
+     * A detail message is a String that gives a specific
+     * description of this error.
+     * @param msg the detail message
+     */
+    public NoRouteToHostException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Construct a new NoRouteToHostException with no detailed message.
+     */
+    public NoRouteToHostException() {}
+}
diff --git a/java/net/PasswordAuthentication.java b/java/net/PasswordAuthentication.java
new file mode 100644
index 0000000..5529568
--- /dev/null
+++ b/java/net/PasswordAuthentication.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+
+/**
+ * The class PasswordAuthentication is a data holder that is used by
+ * Authenticator.  It is simply a repository for a user name and a password.
+ *
+ * @see java.net.Authenticator
+ * @see java.net.Authenticator#getPasswordAuthentication()
+ *
+ * @author  Bill Foote
+ * @since   1.2
+ */
+
+public final class PasswordAuthentication {
+
+    private String userName;
+    private char[] password;
+
+    /**
+     * Creates a new {@code PasswordAuthentication} object from the given
+     * user name and password.
+     *
+     * <p> Note that the given user password is cloned before it is stored in
+     * the new {@code PasswordAuthentication} object.
+     *
+     * @param userName the user name
+     * @param password the user's password
+     */
+    public PasswordAuthentication(String userName, char[] password) {
+        this.userName = userName;
+        this.password = password.clone();
+    }
+
+    /**
+     * Returns the user name.
+     *
+     * @return the user name
+     */
+    public String getUserName() {
+        return userName;
+    }
+
+    /**
+     * Returns the user password.
+     *
+     * <p> Note that this method returns a reference to the password. It is
+     * the caller's responsibility to zero out the password information after
+     * it is no longer needed.
+     *
+     * @return the password
+     */
+    public char[] getPassword() {
+        return password;
+    }
+}
diff --git a/java/net/PlainDatagramSocketImpl.java b/java/net/PlainDatagramSocketImpl.java
new file mode 100644
index 0000000..d4b1f2c
--- /dev/null
+++ b/java/net/PlainDatagramSocketImpl.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2007,2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+
+import android.system.ErrnoException;
+import android.system.StructGroupReq;
+
+import java.io.IOException;
+import libcore.io.IoBridge;
+import libcore.io.Libcore;
+import libcore.util.EmptyArray;
+
+import jdk.net.*;
+
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.AF_UNSPEC;
+import static android.system.OsConstants.IPPROTO_IP;
+import static android.system.OsConstants.IP_MULTICAST_ALL;
+import static android.system.OsConstants.MSG_PEEK;
+import static android.system.OsConstants.POLLERR;
+import static android.system.OsConstants.POLLIN;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static libcore.io.IoBridge.JAVA_IP_MULTICAST_TTL;
+import static libcore.io.IoBridge.JAVA_MCAST_JOIN_GROUP;
+import static libcore.io.IoBridge.JAVA_MCAST_LEAVE_GROUP;
+import static sun.net.ExtendedOptionsImpl.*;
+
+/*
+ * On Unix systems we simply delegate to native methods.
+ *
+ * @author Chris Hegarty
+ */
+
+class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
+{
+    // Android-removed: init method has been removed
+    // static {
+    //     init();
+    // }
+
+    protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
+        if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
+            super.setOption(name, value);
+        } else {
+            if (isClosed()) {
+                throw new SocketException("Socket closed");
+            }
+            checkSetOptionPermission(name);
+            checkValueType(value, SocketFlow.class);
+            setFlowOption(getFileDescriptor(), (SocketFlow)value);
+        }
+    }
+
+    protected <T> T getOption(SocketOption<T> name) throws IOException {
+        if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
+            return super.getOption(name);
+        }
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+        checkGetOptionPermission(name);
+        SocketFlow flow = SocketFlow.create();
+        getFlowOption(getFileDescriptor(), flow);
+        return (T)flow;
+    }
+
+    protected void socketSetOption(int opt, Object val) throws SocketException {
+        try {
+            socketSetOption0(opt, val);
+        } catch (SocketException se) {
+            if (!connected)
+                throw se;
+        }
+    }
+
+    // BEGIN Android-changed: Rewrote on top of Libcore.io.
+    protected synchronized void bind0(int lport, InetAddress laddr) throws SocketException {
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+
+        IoBridge.bind(fd, laddr, lport);
+
+        if (lport == 0) {
+            // Now that we're a connected socket, let's extract the port number that the system
+            // chose for us and store it in the Socket object.
+            localPort = IoBridge.getLocalInetSocketAddress(fd).getPort();
+        } else {
+            localPort = lport;
+        }
+    }
+
+    protected void send(DatagramPacket p) throws IOException {
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+        if (p.getData() == null || p.getAddress() == null) {
+            throw new NullPointerException("null buffer || null address");
+        }
+
+        int port = connected ? 0 : p.getPort();
+        InetAddress address = connected ? null : p.getAddress();
+        IoBridge.sendto(fd, p.getData(), p.getOffset(), p.getLength(), 0, address, port);
+    }
+
+    protected synchronized int peek(InetAddress i) throws IOException {
+        DatagramPacket p = new DatagramPacket(EmptyArray.BYTE, 0);
+        doRecv(p, MSG_PEEK);
+        i.holder().address = p.getAddress().holder().address;
+        return p.getPort();
+    }
+
+    protected synchronized int peekData(DatagramPacket p) throws IOException {
+        doRecv(p, MSG_PEEK);
+        return p.getPort();
+    }
+
+    protected synchronized void receive0(DatagramPacket p) throws IOException {
+        doRecv(p, 0);
+    }
+
+    private void doRecv(DatagramPacket p, int flags) throws IOException {
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+
+        if (timeout != 0) {
+            IoBridge.poll(fd, POLLIN | POLLERR, timeout);
+        }
+
+        IoBridge.recvfrom(false, fd, p.getData(), p.getOffset(), p.bufLength, flags, p,
+                connected);
+    }
+
+    protected void setTimeToLive(int ttl) throws IOException {
+        IoBridge.setSocketOption(fd, JAVA_IP_MULTICAST_TTL, ttl);
+    }
+
+    protected int getTimeToLive() throws IOException {
+        return (Integer) IoBridge.getSocketOption(fd, JAVA_IP_MULTICAST_TTL);
+    }
+
+    protected void setTTL(byte ttl) throws IOException {
+        setTimeToLive((int) ttl & 0xff);
+    }
+
+    protected byte getTTL() throws IOException {
+        return (byte) getTimeToLive();
+    }
+
+    private static StructGroupReq makeGroupReq(InetAddress gr_group,
+            NetworkInterface networkInterface) {
+        int gr_interface = (networkInterface != null) ? networkInterface.getIndex() : 0;
+        return new StructGroupReq(gr_interface, gr_group);
+    }
+
+    protected void join(InetAddress inetaddr, NetworkInterface netIf) throws IOException {
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+
+        IoBridge.setSocketOption(fd, JAVA_MCAST_JOIN_GROUP, makeGroupReq(inetaddr, netIf));
+    }
+
+    protected void leave(InetAddress inetaddr, NetworkInterface netIf)
+        throws IOException {
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+
+        IoBridge.setSocketOption(fd, JAVA_MCAST_LEAVE_GROUP, makeGroupReq(inetaddr, netIf));
+    }
+
+    protected void datagramSocketCreate() throws SocketException {
+        fd = IoBridge.socket(AF_INET6, SOCK_DGRAM, 0);
+        IoBridge.setSocketOption(fd, SO_BROADCAST, true);
+
+        try {
+            Libcore.os.setsockoptInt(fd, IPPROTO_IP, IP_MULTICAST_ALL, 0);
+        } catch (ErrnoException errnoException) {
+            throw errnoException.rethrowAsSocketException();
+        }
+    }
+
+    protected void datagramSocketClose() {
+        try {
+            IoBridge.closeAndSignalBlockedThreads(fd);
+        } catch (IOException ignored) { }
+    }
+
+    protected void socketSetOption0(int opt, Object val) throws SocketException {
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+
+        IoBridge.setSocketOption(fd, opt, val);
+    }
+
+    protected Object socketGetOption(int opt) throws SocketException {
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+
+        return IoBridge.getSocketOption(fd, opt);
+    }
+
+    protected void connect0(InetAddress address, int port) throws SocketException {
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+
+        IoBridge.connect(fd, address, port);
+    }
+
+    protected void disconnect0(int family) {
+        if (isClosed()) {
+            return;
+        }
+
+        InetAddress inetAddressUnspec = new InetAddress();
+        inetAddressUnspec.holder().family = AF_UNSPEC;
+
+        try {
+            IoBridge.connect(fd, inetAddressUnspec, 0);
+        } catch (SocketException ignored) { }
+    }
+    // END Android-changed: Rewrote on top of Libcore.io.
+
+    // Android-removed: JNI has been removed
+    // /**
+    //  * Perform class load-time initializations.
+    //  */
+    // private native static void init();
+}
diff --git a/java/net/PlainSocketImpl.java b/java/net/PlainSocketImpl.java
new file mode 100644
index 0000000..89ee53e
--- /dev/null
+++ b/java/net/PlainSocketImpl.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+
+import android.system.ErrnoException;
+
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
+import libcore.io.AsynchronousCloseMonitor;
+import libcore.io.IoBridge;
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+
+import jdk.net.*;
+
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.AF_UNIX;
+import static android.system.OsConstants.EAGAIN;
+import static android.system.OsConstants.EBADF;
+import static android.system.OsConstants.EINVAL;
+import static android.system.OsConstants.MSG_OOB;
+import static android.system.OsConstants.POLLERR;
+import static android.system.OsConstants.POLLIN;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOCK_STREAM;
+import static android.system.OsConstants.SHUT_RDWR;
+import static sun.net.ExtendedOptionsImpl.*;
+
+// Android-changed: Rewritten to use android.system POSIX calls and assume AF_INET6.
+/*
+ * On Unix systems we simply delegate to native methods.
+ *
+ * @author Chris Hegarty
+ */
+
+class PlainSocketImpl extends AbstractPlainSocketImpl
+{
+    // Android-removed: Android doesn't need to call native initProto.
+    /*
+    static {
+        initProto();
+    }
+    */
+
+    /**
+     * Constructs an empty instance.
+     */
+    PlainSocketImpl() {
+        // Android-changed: Let PlainSocketImpl construct its own FileDescriptor.
+        this.fd = new FileDescriptor();
+    }
+
+    /**
+     * Constructs an instance with the given file descriptor.
+     */
+    // Android-removed: Let PlainSocketImpl construct its own FileDescriptor.
+    /*
+    PlainSocketImpl(FileDescriptor fd) {
+        this.fd = fd;
+    }
+    */
+
+    protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
+        if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
+            super.setOption(name, value);
+        } else {
+            if (isClosedOrPending()) {
+                throw new SocketException("Socket closed");
+            }
+            checkSetOptionPermission(name);
+            checkValueType(value, SocketFlow.class);
+            setFlowOption(getFileDescriptor(), (SocketFlow)value);
+        }
+    }
+
+    protected <T> T getOption(SocketOption<T> name) throws IOException {
+        if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
+            return super.getOption(name);
+        }
+        if (isClosedOrPending()) {
+            throw new SocketException("Socket closed");
+        }
+        checkGetOptionPermission(name);
+        SocketFlow flow = SocketFlow.create();
+        getFlowOption(getFileDescriptor(), flow);
+        return (T)flow;
+    }
+
+    // BEGIN Android-changed: Rewrote on top of Libcore.io.
+    protected void socketSetOption(int opt, Object val) throws SocketException {
+        try {
+            socketSetOption0(opt, val);
+        } catch (SocketException se) {
+            if (socket == null || !socket.isConnected())
+                throw se;
+        }
+    }
+
+    void socketCreate(boolean isStream) throws IOException {
+        // The fd object must not change after calling bind, because we rely on this undocumented
+        // behaviour. See libcore.java.net.SocketTest#testFileDescriptorStaysSame.
+        fd.setInt$(IoBridge.socket(AF_INET6, isStream ? SOCK_STREAM : SOCK_DGRAM, 0).getInt$());
+        IoUtils.setFdOwner(fd, this);
+
+        if (serverSocket != null) {
+            IoUtils.setBlocking(fd, false);
+            IoBridge.setSocketOption(fd, SO_REUSEADDR, true);
+        }
+    }
+
+    void socketConnect(InetAddress address, int port, int timeout) throws IOException {
+        if (fd == null || !fd.valid()) {
+            throw new SocketException("Socket closed");
+        }
+
+        IoBridge.connect(fd, address, port, timeout);
+
+        this.address = address;
+        this.port = port;
+
+        if (localport == 0) {
+            // If socket is pending close, fd becomes an AF_UNIX socket and calling
+            // getLocalInetSocketAddress will fail.
+            // http://b/34645743
+            if (!isClosedOrPending()) {
+                localport = IoBridge.getLocalInetSocketAddress(fd).getPort();
+            }
+        }
+    }
+
+    void socketBind(InetAddress address, int port) throws IOException {
+        if (fd == null || !fd.valid()) {
+            throw new SocketException("Socket closed");
+        }
+
+        IoBridge.bind(fd, address, port);
+
+        this.address = address;
+        if (port == 0) {
+            // Now that we're a connected socket, let's extract the port number that the system
+            // chose for us and store it in the Socket object.
+            localport = IoBridge.getLocalInetSocketAddress(fd).getPort();
+        } else {
+            localport = port;
+        }
+    }
+
+    void socketListen(int count) throws IOException {
+        if (fd == null || !fd.valid()) {
+            throw new SocketException("Socket closed");
+        }
+
+        try {
+            Libcore.os.listen(fd, count);
+        } catch (ErrnoException errnoException) {
+            throw errnoException.rethrowAsSocketException();
+        }
+    }
+
+    void socketAccept(SocketImpl s) throws IOException {
+        if (fd == null || !fd.valid()) {
+            throw new SocketException("Socket closed");
+        }
+
+        // poll() with a timeout of 0 means "poll for zero millis", but a Socket timeout == 0 means
+        // "wait forever". When timeout == 0 we pass -1 to poll.
+        if (timeout <= 0) {
+            IoBridge.poll(fd, POLLIN | POLLERR, -1);
+        } else {
+            IoBridge.poll(fd, POLLIN | POLLERR, timeout);
+        }
+
+        InetSocketAddress peerAddress = new InetSocketAddress();
+        try {
+            FileDescriptor newfd = Libcore.os.accept(fd, peerAddress);
+
+            s.fd.setInt$(newfd.getInt$());
+            IoUtils.setFdOwner(s.fd, s);
+            s.address = peerAddress.getAddress();
+            s.port = peerAddress.getPort();
+        } catch (ErrnoException errnoException) {
+            if (errnoException.errno == EAGAIN) {
+                SocketTimeoutException e = new SocketTimeoutException();
+                e.initCause(errnoException);
+                throw e;
+            } else if (errnoException.errno == EINVAL || errnoException.errno == EBADF) {
+                throw new SocketException("Socket closed");
+            }
+            errnoException.rethrowAsSocketException();
+        }
+
+        s.localport = IoBridge.getLocalInetSocketAddress(s.fd).getPort();
+    }
+
+    int socketAvailable() throws IOException {
+        return IoBridge.available(fd);
+    }
+
+    void socketClose0(boolean useDeferredClose) throws IOException {
+        if (fd == null || !fd.valid()) {
+            throw new SocketException("socket already closed");
+        }
+
+        FileDescriptor markerFD = null;
+        if (useDeferredClose) {
+            markerFD = getMarkerFD();
+        }
+
+        if (useDeferredClose && markerFD != null) {
+            try {
+                Libcore.os.dup2(markerFD, fd.getInt$());
+                Libcore.os.close(markerFD);
+
+                // This effectively closes the socket, needs to signal threads that blocks on this
+                // file descriptor.
+                AsynchronousCloseMonitor.signalBlockedThreads(fd);
+            } catch (ErrnoException errnoException) {
+                // close should not throw
+            }
+        } else {
+            // If requested or a markerFD cannot be created, a non-deferred close is performed
+            // instead.
+            IoBridge.closeAndSignalBlockedThreads(fd);
+        }
+    }
+
+    /*
+     * Create the marker file descriptor by establishing a loopback connection which we shutdown but
+     * do not close the fd. The result is an fd that can be used for read/write.
+     *
+     * The purpose is to keep hold of the raw fd handle until we are sure it is not used in any
+     * thread. Otherwise if we close the file descriptor directly, the system might reuse the raw fd
+     * number and threads holding old fd value might behave incorrectly.
+     */
+    private FileDescriptor getMarkerFD() throws SocketException {
+        FileDescriptor fd1 = new FileDescriptor();
+        FileDescriptor fd2 = new FileDescriptor();
+        try {
+            Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd1, fd2);
+
+            // Shutdown fd1, any reads to this fd will get EOF; any writes will get an error.
+            Libcore.os.shutdown(fd1, SHUT_RDWR);
+            Libcore.os.close(fd2);
+        } catch (ErrnoException errnoException) {
+            // We might have reached the maximum file descriptor number and socketpair(2) would
+            // fail. In this case, return null and let caller to fall back to an alternative method
+            // that does not allocate more file descriptors.
+            return null;
+        }
+        return fd1;
+    }
+
+    void socketShutdown(int howto) throws IOException {
+        try {
+            Libcore.os.shutdown(fd, howto);
+        } catch (ErrnoException errnoException) {
+            throw errnoException.rethrowAsIOException();
+        }
+    }
+
+    void socketSetOption0(int cmd, Object value) throws SocketException {
+        // OpenJDK does not set SO_TIMEOUT on Linux.
+        if (cmd == SO_TIMEOUT) {
+            return;
+        }
+
+        IoBridge.setSocketOption(fd, cmd, value);
+    }
+
+    Object socketGetOption(int opt) throws SocketException {
+        return IoBridge.getSocketOption(fd, opt);
+    }
+
+    void socketSendUrgentData(int data) throws IOException {
+        if (fd == null || !fd.valid()) {
+            throw new SocketException("Socket closed");
+        }
+
+        try {
+            byte[] buffer = new byte[] { (byte) data };
+            Libcore.os.sendto(fd, buffer, 0, 1, MSG_OOB, null, 0);
+        } catch (ErrnoException errnoException) {
+            throw errnoException.rethrowAsSocketException();
+        }
+    }
+    // END Android-changed: Rewrote on top of Libcore.io.
+
+}
diff --git a/java/net/PortUnreachableException.java b/java/net/PortUnreachableException.java
new file mode 100644
index 0000000..3e7558b
--- /dev/null
+++ b/java/net/PortUnreachableException.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * Signals that an ICMP Port Unreachable message has been
+ * received on a connected datagram.
+ *
+ * @since   1.4
+ */
+
+public class PortUnreachableException extends SocketException {
+    private static final long serialVersionUID = 8462541992376507323L;
+
+    /**
+     * Constructs a new {@code PortUnreachableException} with a
+     * detail message.
+     * @param msg the detail message
+     */
+    public PortUnreachableException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Construct a new {@code PortUnreachableException} with no
+     * detailed message.
+     */
+    public PortUnreachableException() {}
+
+    // Android-added: PortUnreachableException ctor used by IoBridge.
+    /** @hide */
+    public PortUnreachableException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+}
diff --git a/java/net/ProtocolException.java b/java/net/ProtocolException.java
new file mode 100644
index 0000000..5944282
--- /dev/null
+++ b/java/net/ProtocolException.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * Thrown to indicate that there is an error in the underlying
+ * protocol, such as a TCP error.
+ *
+ * @author  Chris Warth
+ * @since   JDK1.0
+ */
+public
+class ProtocolException extends IOException {
+    private static final long serialVersionUID = -6098449442062388080L;
+
+    /**
+     * Constructs a new {@code ProtocolException} with the
+     * specified detail message.
+     *
+     * @param   host   the detail message.
+     */
+    public ProtocolException(String host) {
+        super(host);
+    }
+
+    /**
+     * Constructs a new {@code ProtocolException} with no detail message.
+     */
+    public ProtocolException() {
+    }
+}
diff --git a/java/net/ProtocolFamily.java b/java/net/ProtocolFamily.java
new file mode 100644
index 0000000..5d02326
--- /dev/null
+++ b/java/net/ProtocolFamily.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * Represents a family of communication protocols.
+ *
+ * @since 1.7
+ */
+
+public interface ProtocolFamily {
+    /**
+     * Returns the name of the protocol family.
+     *
+     * @return the name of the protocol family
+     */
+    String name();
+}
diff --git a/java/net/Proxy.java b/java/net/Proxy.java
new file mode 100644
index 0000000..8ba020e
--- /dev/null
+++ b/java/net/Proxy.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * This class represents a proxy setting, typically a type (http, socks) and
+ * a socket address.
+ * A {@code Proxy} is an immutable object.
+ *
+ * @see     java.net.ProxySelector
+ * @author Yingxian Wang
+ * @author Jean-Christophe Collet
+ * @since   1.5
+ */
+public class Proxy {
+
+    /**
+     * Represents the proxy type.
+     *
+     * @since 1.5
+     */
+    public enum Type {
+        /**
+         * Represents a direct connection, or the absence of a proxy.
+         */
+        DIRECT,
+        /**
+         * Represents proxy for high level protocols such as HTTP or FTP.
+         */
+        HTTP,
+        /**
+         * Represents a SOCKS (V4 or V5) proxy.
+         */
+        SOCKS
+    };
+
+    private Type type;
+    private SocketAddress sa;
+
+    /**
+     * A proxy setting that represents a {@code DIRECT} connection,
+     * basically telling the protocol handler not to use any proxying.
+     * Used, for instance, to create sockets bypassing any other global
+     * proxy settings (like SOCKS):
+     * <P>
+     * {@code Socket s = new Socket(Proxy.NO_PROXY);}
+     *
+     */
+    public final static Proxy NO_PROXY = new Proxy();
+
+    // Creates the proxy that represents a {@code DIRECT} connection.
+    private Proxy() {
+        type = Type.DIRECT;
+        sa = null;
+    }
+
+    /**
+     * Creates an entry representing a PROXY connection.
+     * Certain combinations are illegal. For instance, for types Http, and
+     * Socks, a SocketAddress <b>must</b> be provided.
+     * <P>
+     * Use the {@code Proxy.NO_PROXY} constant
+     * for representing a direct connection.
+     *
+     * @param type the {@code Type} of the proxy
+     * @param sa the {@code SocketAddress} for that proxy
+     * @throws IllegalArgumentException when the type and the address are
+     * incompatible
+     */
+    public Proxy(Type type, SocketAddress sa) {
+        if ((type == Type.DIRECT) || !(sa instanceof InetSocketAddress))
+            throw new IllegalArgumentException("type " + type + " is not compatible with address " + sa);
+        this.type = type;
+        this.sa = sa;
+    }
+
+    /**
+     * Returns the proxy type.
+     *
+     * @return a Type representing the proxy type
+     */
+    public Type type() {
+        return type;
+    }
+
+    /**
+     * Returns the socket address of the proxy, or
+     * {@code null} if its a direct connection.
+     *
+     * @return a {@code SocketAddress} representing the socket end
+     *         point of the proxy
+     */
+    public SocketAddress address() {
+        return sa;
+    }
+
+    /**
+     * Constructs a string representation of this Proxy.
+     * This String is constructed by calling toString() on its type
+     * and concatenating " @ " and the toString() result from its address
+     * if its type is not {@code DIRECT}.
+     *
+     * @return  a string representation of this object.
+     */
+    public String toString() {
+        if (type() == Type.DIRECT)
+            return "DIRECT";
+        return type() + " @ " + address();
+    }
+
+        /**
+     * Compares this object against the specified object.
+     * The result is {@code true} if and only if the argument is
+     * not {@code null} and it represents the same proxy as
+     * this object.
+     * <p>
+     * Two instances of {@code Proxy} represent the same
+     * address if both the SocketAddresses and type are equal.
+     *
+     * @param   obj   the object to compare against.
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     * @see java.net.InetSocketAddress#equals(java.lang.Object)
+     */
+    public final boolean equals(Object obj) {
+        if (obj == null || !(obj instanceof Proxy))
+            return false;
+        Proxy p = (Proxy) obj;
+        if (p.type() == type()) {
+            if (address() == null) {
+                return (p.address() == null);
+            } else
+                return address().equals(p.address());
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hashcode for this Proxy.
+     *
+     * @return  a hash code value for this Proxy.
+     */
+    public final int hashCode() {
+        if (address() == null)
+            return type().hashCode();
+        return type().hashCode() + address().hashCode();
+    }
+}
diff --git a/java/net/ProxySelector.java b/java/net/ProxySelector.java
new file mode 100644
index 0000000..d6bb536
--- /dev/null
+++ b/java/net/ProxySelector.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.util.List;
+import sun.security.util.SecurityConstants;
+
+/**
+ * Selects the proxy server to use, if any, when connecting to the
+ * network resource referenced by a URL. A proxy selector is a
+ * concrete sub-class of this class and is registered by invoking the
+ * {@link java.net.ProxySelector#setDefault setDefault} method. The
+ * currently registered proxy selector can be retrieved by calling
+ * {@link java.net.ProxySelector#getDefault getDefault} method.
+ *
+ * <p> When a proxy selector is registered, for instance, a subclass
+ * of URLConnection class should call the {@link #select select}
+ * method for each URL request so that the proxy selector can decide
+ * if a direct, or proxied connection should be used. The {@link
+ * #select select} method returns an iterator over a collection with
+ * the preferred connection approach.
+ *
+ * <p> If a connection cannot be established to a proxy (PROXY or
+ * SOCKS) servers then the caller should call the proxy selector's
+ * {@link #connectFailed connectFailed} method to notify the proxy
+ * selector that the proxy server is unavailable. </p>
+ *
+ * <P>The default proxy selector does enforce a
+ * <a href="doc-files/net-properties.html#Proxies">set of System Properties</a>
+ * related to proxy settings.</P>
+ *
+ * @author Yingxian Wang
+ * @author Jean-Christophe Collet
+ * @since 1.5
+ */
+public abstract class ProxySelector {
+    /**
+     * The system wide proxy selector that selects the proxy server to
+     * use, if any, when connecting to a remote object referenced by
+     * an URL.
+     *
+     * @see #setDefault(ProxySelector)
+     */
+    private static ProxySelector theProxySelector;
+
+    static {
+        try {
+            Class<?> c = Class.forName("sun.net.spi.DefaultProxySelector");
+            if (c != null && ProxySelector.class.isAssignableFrom(c)) {
+                theProxySelector = (ProxySelector) c.newInstance();
+            }
+        } catch (Exception e) {
+            theProxySelector = null;
+        }
+    }
+
+    /**
+     * Gets the system-wide proxy selector.
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     * {@link NetPermission}{@code ("getProxySelector")}
+     * @see #setDefault(ProxySelector)
+     * @return the system-wide {@code ProxySelector}
+     * @since 1.5
+     */
+    public static ProxySelector getDefault() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(SecurityConstants.GET_PROXYSELECTOR_PERMISSION);
+        }
+        return theProxySelector;
+    }
+
+    /**
+     * Sets (or unsets) the system-wide proxy selector.
+     *
+     * Note: non-standard protocol handlers may ignore this setting.
+     *
+     * @param ps The HTTP proxy selector, or
+     *          {@code null} to unset the proxy selector.
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     * {@link NetPermission}{@code ("setProxySelector")}
+     *
+     * @see #getDefault()
+     * @since 1.5
+     */
+    public static void setDefault(ProxySelector ps) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(SecurityConstants.SET_PROXYSELECTOR_PERMISSION);
+        }
+        theProxySelector = ps;
+    }
+
+    /**
+     * Selects all the applicable proxies based on the protocol to
+     * access the resource with and a destination address to access
+     * the resource at.
+     * The format of the URI is defined as follow:
+     * <UL>
+     * <LI>http URI for http connections</LI>
+     * <LI>https URI for https connections
+     * <LI>{@code socket://host:port}<br>
+     *     for tcp client sockets connections</LI>
+     * </UL>
+     *
+     * @param   uri
+     *          The URI that a connection is required to
+     *
+     * @return  a List of Proxies. Each element in the
+     *          the List is of type
+     *          {@link java.net.Proxy Proxy};
+     *          when no proxy is available, the list will
+     *          contain one element of type
+     *          {@link java.net.Proxy Proxy}
+     *          that represents a direct connection.
+     * @throws IllegalArgumentException if the argument is null
+     */
+    public abstract List<Proxy> select(URI uri);
+
+    /**
+     * Called to indicate that a connection could not be established
+     * to a proxy/socks server. An implementation of this method can
+     * temporarily remove the proxies or reorder the sequence of
+     * proxies returned by {@link #select(URI)}, using the address
+     * and the IOException caught when trying to connect.
+     *
+     * @param   uri
+     *          The URI that the proxy at sa failed to serve.
+     * @param   sa
+     *          The socket address of the proxy/SOCKS server
+     *
+     * @param   ioe
+     *          The I/O exception thrown when the connect failed.
+     * @throws IllegalArgumentException if either argument is null
+     */
+    public abstract void connectFailed(URI uri, SocketAddress sa, IOException ioe);
+}
diff --git a/java/net/ResponseCache.java b/java/net/ResponseCache.java
new file mode 100644
index 0000000..2dfaf4a
--- /dev/null
+++ b/java/net/ResponseCache.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.List;
+import sun.security.util.SecurityConstants;
+
+/**
+ * Represents implementations of URLConnection caches. An instance of
+ * such a class can be registered with the system by doing
+ * ResponseCache.setDefault(ResponseCache), and the system will call
+ * this object in order to:
+ *
+ *    <ul><li>store resource data which has been retrieved from an
+ *            external source into the cache</li>
+ *         <li>try to fetch a requested resource that may have been
+ *            stored in the cache</li>
+ *    </ul>
+ *
+ * The ResponseCache implementation decides which resources
+ * should be cached, and for how long they should be cached. If a
+ * request resource cannot be retrieved from the cache, then the
+ * protocol handlers will fetch the resource from its original
+ * location.
+ *
+ * The settings for URLConnection#useCaches controls whether the
+ * protocol is allowed to use a cached response.
+ *
+ * For more information on HTTP caching, see <a
+ * href="http://www.ietf.org/rfc/rfc2616.txt"><i>RFC&nbsp;2616: Hypertext
+ * Transfer Protocol -- HTTP/1.1</i></a>
+ *
+ * @author Yingxian Wang
+ * @since 1.5
+ */
+public abstract class ResponseCache {
+
+    /**
+     * The system wide cache that provides access to a url
+     * caching mechanism.
+     *
+     * @see #setDefault(ResponseCache)
+     * @see #getDefault()
+     */
+    private static ResponseCache theResponseCache;
+
+    /**
+     * Gets the system-wide response cache.
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     * {@link NetPermission}{@code ("getResponseCache")}
+     *
+     * @see #setDefault(ResponseCache)
+     * @return the system-wide {@code ResponseCache}
+     * @since 1.5
+     */
+    public synchronized  static ResponseCache getDefault() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(SecurityConstants.GET_RESPONSECACHE_PERMISSION);
+        }
+        return theResponseCache;
+    }
+
+    /**
+     * Sets (or unsets) the system-wide cache.
+     *
+     * Note: non-standard procotol handlers may ignore this setting.
+     *
+     * @param responseCache The response cache, or
+     *          {@code null} to unset the cache.
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     * {@link NetPermission}{@code ("setResponseCache")}
+     *
+     * @see #getDefault()
+     * @since 1.5
+     */
+    public synchronized static void setDefault(ResponseCache responseCache) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(SecurityConstants.SET_RESPONSECACHE_PERMISSION);
+        }
+        theResponseCache = responseCache;
+    }
+
+    /**
+     * Retrieve the cached response based on the requesting uri,
+     * request method and request headers. Typically this method is
+     * called by the protocol handler before it sends out the request
+     * to get the network resource. If a cached response is returned,
+     * that resource is used instead.
+     *
+     * @param uri a {@code URI} used to reference the requested
+     *            network resource
+     * @param rqstMethod a {@code String} representing the request
+     *            method
+     * @param rqstHeaders - a Map from request header
+     *            field names to lists of field values representing
+     *            the current request headers
+     * @return a {@code CacheResponse} instance if available
+     *          from cache, or null otherwise
+     * @throws  IOException if an I/O error occurs
+     * @throws  IllegalArgumentException if any one of the arguments is null
+     *
+     * @see     java.net.URLConnection#setUseCaches(boolean)
+     * @see     java.net.URLConnection#getUseCaches()
+     * @see     java.net.URLConnection#setDefaultUseCaches(boolean)
+     * @see     java.net.URLConnection#getDefaultUseCaches()
+     */
+    public abstract CacheResponse
+        get(URI uri, String rqstMethod, Map<String, List<String>> rqstHeaders)
+        throws IOException;
+
+    /**
+     * The protocol handler calls this method after a resource has
+     * been retrieved, and the ResponseCache must decide whether or
+     * not to store the resource in its cache. If the resource is to
+     * be cached, then put() must return a CacheRequest object which
+     * contains an OutputStream that the protocol handler will
+     * use to write the resource into the cache. If the resource is
+     * not to be cached, then put must return null.
+     *
+     * @param uri a {@code URI} used to reference the requested
+     *            network resource
+     * @param conn - a URLConnection instance that is used to fetch
+     *            the response to be cached
+     * @return a {@code CacheRequest} for recording the
+     *            response to be cached. Null return indicates that
+     *            the caller does not intend to cache the response.
+     * @throws IOException if an I/O error occurs
+     * @throws IllegalArgumentException if any one of the arguments is
+     *            null
+     */
+    public abstract CacheRequest put(URI uri, URLConnection conn)  throws IOException;
+}
diff --git a/java/net/SecureCacheResponse.java b/java/net/SecureCacheResponse.java
new file mode 100644
index 0000000..64fd414
--- /dev/null
+++ b/java/net/SecureCacheResponse.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.security.cert.Certificate;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import java.security.Principal;
+import java.util.List;
+
+/**
+ * Represents a cache response originally retrieved through secure
+ * means, such as TLS.
+ *
+ * @since 1.5
+ */
+public abstract class SecureCacheResponse extends CacheResponse {
+    /**
+     * Returns the cipher suite in use on the original connection that
+     * retrieved the network resource.
+     *
+     * @return a string representing the cipher suite
+     */
+    public abstract String getCipherSuite();
+
+    /**
+     * Returns the certificate chain that were sent to the server during
+     * handshaking of the original connection that retrieved the
+     * network resource.  Note: This method is useful only
+     * when using certificate-based cipher suites.
+     *
+     * @return an immutable List of Certificate representing the
+     *           certificate chain that was sent to the server. If no
+     *           certificate chain was sent, null will be returned.
+     * @see #getLocalPrincipal()
+     */
+    public abstract List<Certificate> getLocalCertificateChain();
+
+    /**
+     * Returns the server's certificate chain, which was established as
+     * part of defining the session in the original connection that
+     * retrieved the network resource, from cache.  Note: This method
+     * can be used only when using certificate-based cipher suites;
+     * using it with non-certificate-based cipher suites, such as
+     * Kerberos, will throw an SSLPeerUnverifiedException.
+     *
+     * @return an immutable List of Certificate representing the server's
+     *         certificate chain.
+     * @throws SSLPeerUnverifiedException if the peer is not verified.
+     * @see #getPeerPrincipal()
+     */
+    public abstract List<Certificate> getServerCertificateChain()
+        throws SSLPeerUnverifiedException;
+
+    /**
+     * Returns the server's principal which was established as part of
+     * defining the session during the original connection that
+     * retrieved the network resource.
+     *
+     * @return the server's principal. Returns an X500Principal of the
+     * end-entity certiticate for X509-based cipher suites, and
+     * KerberosPrincipal for Kerberos cipher suites.
+     *
+     * @throws SSLPeerUnverifiedException if the peer was not verified.
+     *
+     * @see #getServerCertificateChain()
+     * @see #getLocalPrincipal()
+     */
+     public abstract Principal getPeerPrincipal()
+             throws SSLPeerUnverifiedException;
+
+    /**
+      * Returns the principal that was sent to the server during
+      * handshaking in the original connection that retrieved the
+      * network resource.
+      *
+      * @return the principal sent to the server. Returns an X500Principal
+      * of the end-entity certificate for X509-based cipher suites, and
+      * KerberosPrincipal for Kerberos cipher suites. If no principal was
+      * sent, then null is returned.
+      *
+      * @see #getLocalCertificateChain()
+      * @see #getPeerPrincipal()
+      */
+     public abstract Principal getLocalPrincipal();
+}
diff --git a/java/net/ServerSocket.annotated.java b/java/net/ServerSocket.annotated.java
new file mode 100644
index 0000000..1fcd05f
--- /dev/null
+++ b/java/net/ServerSocket.annotated.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.net;
+
+import java.nio.channels.ServerSocketChannel;
+import java.io.IOException;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class ServerSocket implements java.io.Closeable {
+
+public ServerSocket() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public ServerSocket(int port) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public ServerSocket(int port, int backlog) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public ServerSocket(int port, int backlog, java.net.InetAddress bindAddr) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void bind(java.net.SocketAddress endpoint) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void bind(java.net.SocketAddress endpoint, int backlog) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public java.net.InetAddress getInetAddress() { throw new RuntimeException("Stub!"); }
+
+public int getLocalPort() { throw new RuntimeException("Stub!"); }
+
+public java.net.SocketAddress getLocalSocketAddress() { throw new RuntimeException("Stub!"); }
+
+public java.net.Socket accept() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
[email protected]
+public SocketImpl getImpl() throws SocketException { throw new RuntimeException("Stub!"); }
+
+protected final void implAccept(java.net.Socket s) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void close() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public java.nio.channels.ServerSocketChannel getChannel() { throw new RuntimeException("Stub!"); }
+
+public boolean isBound() { throw new RuntimeException("Stub!"); }
+
+public boolean isClosed() { throw new RuntimeException("Stub!"); }
+
+public synchronized void setSoTimeout(int timeout) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized int getSoTimeout() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void setReuseAddress(boolean on) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public boolean getReuseAddress() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public static synchronized void setSocketFactory(java.net.SocketImplFactory fac) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public synchronized void setReceiveBufferSize(int size) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized int getReceiveBufferSize() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/net/ServerSocket.java b/java/net/ServerSocket.java
new file mode 100644
index 0000000..444a84d
--- /dev/null
+++ b/java/net/ServerSocket.java
@@ -0,0 +1,932 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.nio.channels.ServerSocketChannel;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+
+/**
+ * This class implements server sockets. A server socket waits for
+ * requests to come in over the network. It performs some operation
+ * based on that request, and then possibly returns a result to the requester.
+ * <p>
+ * The actual work of the server socket is performed by an instance
+ * of the {@code SocketImpl} class. An application can
+ * change the socket factory that creates the socket
+ * implementation to configure itself to create sockets
+ * appropriate to the local firewall.
+ *
+ * @author  unascribed
+ * @see     java.net.SocketImpl
+ * @see     java.net.ServerSocket#setSocketFactory(java.net.SocketImplFactory)
+ * @see     java.nio.channels.ServerSocketChannel
+ * @since   JDK1.0
+ */
+public
+class ServerSocket implements java.io.Closeable {
+    /**
+     * Various states of this socket.
+     */
+    private boolean created = false;
+    private boolean bound = false;
+    private boolean closed = false;
+    private Object closeLock = new Object();
+
+    /**
+     * The implementation of this Socket.
+     */
+    private SocketImpl impl;
+
+    /**
+     * Are we using an older SocketImpl?
+     */
+    private boolean oldImpl = false;
+
+    /**
+     * Package-private constructor to create a ServerSocket associated with
+     * the given SocketImpl.
+     */
+    ServerSocket(SocketImpl impl) {
+        this.impl = impl;
+        impl.setServerSocket(this);
+    }
+
+    /**
+     * Creates an unbound server socket.
+     *
+     * @exception IOException IO error when opening the socket.
+     * @revised 1.4
+     */
+    public ServerSocket() throws IOException {
+        setImpl();
+    }
+
+    /**
+     * Creates a server socket, bound to the specified port. A port number
+     * of {@code 0} means that the port number is automatically
+     * allocated, typically from an ephemeral port range. This port
+     * number can then be retrieved by calling {@link #getLocalPort getLocalPort}.
+     * <p>
+     * The maximum queue length for incoming connection indications (a
+     * request to connect) is set to {@code 50}. If a connection
+     * indication arrives when the queue is full, the connection is refused.
+     * <p>
+     * If the application has specified a server socket factory, that
+     * factory's {@code createSocketImpl} method is called to create
+     * the actual socket implementation. Otherwise a "plain" socket is created.
+     * <p>
+     * If there is a security manager,
+     * its {@code checkListen} method is called
+     * with the {@code port} argument
+     * as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     *
+     * @param      port  the port number, or {@code 0} to use a port
+     *                   number that is automatically allocated.
+     *
+     * @exception  IOException  if an I/O error occurs when opening the socket.
+     * @exception  SecurityException
+     * if a security manager exists and its {@code checkListen}
+     * method doesn't allow the operation.
+     * @exception  IllegalArgumentException if the port parameter is outside
+     *             the specified range of valid port values, which is between
+     *             0 and 65535, inclusive.
+     *
+     * @see        java.net.SocketImpl
+     * @see        java.net.SocketImplFactory#createSocketImpl()
+     * @see        java.net.ServerSocket#setSocketFactory(java.net.SocketImplFactory)
+     * @see        SecurityManager#checkListen
+     */
+    public ServerSocket(int port) throws IOException {
+        this(port, 50, null);
+    }
+
+    /**
+     * Creates a server socket and binds it to the specified local port
+     * number, with the specified backlog.
+     * A port number of {@code 0} means that the port number is
+     * automatically allocated, typically from an ephemeral port range.
+     * This port number can then be retrieved by calling
+     * {@link #getLocalPort getLocalPort}.
+     * <p>
+     * The maximum queue length for incoming connection indications (a
+     * request to connect) is set to the {@code backlog} parameter. If
+     * a connection indication arrives when the queue is full, the
+     * connection is refused.
+     * <p>
+     * If the application has specified a server socket factory, that
+     * factory's {@code createSocketImpl} method is called to create
+     * the actual socket implementation. Otherwise a "plain" socket is created.
+     * <p>
+     * If there is a security manager,
+     * its {@code checkListen} method is called
+     * with the {@code port} argument
+     * as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * The {@code backlog} argument is the requested maximum number of
+     * pending connections on the socket. Its exact semantics are implementation
+     * specific. In particular, an implementation may impose a maximum length
+     * or may choose to ignore the parameter altogther. The value provided
+     * should be greater than {@code 0}. If it is less than or equal to
+     * {@code 0}, then an implementation specific default will be used.
+     * <P>
+     *
+     * @param      port     the port number, or {@code 0} to use a port
+     *                      number that is automatically allocated.
+     * @param      backlog  requested maximum length of the queue of incoming
+     *                      connections.
+     *
+     * @exception  IOException  if an I/O error occurs when opening the socket.
+     * @exception  SecurityException
+     * if a security manager exists and its {@code checkListen}
+     * method doesn't allow the operation.
+     * @exception  IllegalArgumentException if the port parameter is outside
+     *             the specified range of valid port values, which is between
+     *             0 and 65535, inclusive.
+     *
+     * @see        java.net.SocketImpl
+     * @see        java.net.SocketImplFactory#createSocketImpl()
+     * @see        java.net.ServerSocket#setSocketFactory(java.net.SocketImplFactory)
+     * @see        SecurityManager#checkListen
+     */
+    public ServerSocket(int port, int backlog) throws IOException {
+        this(port, backlog, null);
+    }
+
+    /**
+     * Create a server with the specified port, listen backlog, and
+     * local IP address to bind to.  The <i>bindAddr</i> argument
+     * can be used on a multi-homed host for a ServerSocket that
+     * will only accept connect requests to one of its addresses.
+     * If <i>bindAddr</i> is null, it will default accepting
+     * connections on any/all local addresses.
+     * The port must be between 0 and 65535, inclusive.
+     * A port number of {@code 0} means that the port number is
+     * automatically allocated, typically from an ephemeral port range.
+     * This port number can then be retrieved by calling
+     * {@link #getLocalPort getLocalPort}.
+     *
+     * <P>If there is a security manager, this method
+     * calls its {@code checkListen} method
+     * with the {@code port} argument
+     * as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * The {@code backlog} argument is the requested maximum number of
+     * pending connections on the socket. Its exact semantics are implementation
+     * specific. In particular, an implementation may impose a maximum length
+     * or may choose to ignore the parameter altogther. The value provided
+     * should be greater than {@code 0}. If it is less than or equal to
+     * {@code 0}, then an implementation specific default will be used.
+     * <P>
+     * @param port  the port number, or {@code 0} to use a port
+     *              number that is automatically allocated.
+     * @param backlog requested maximum length of the queue of incoming
+     *                connections.
+     * @param bindAddr the local InetAddress the server will bind to
+     *
+     * @throws  SecurityException if a security manager exists and
+     * its {@code checkListen} method doesn't allow the operation.
+     *
+     * @throws  IOException if an I/O error occurs when opening the socket.
+     * @exception  IllegalArgumentException if the port parameter is outside
+     *             the specified range of valid port values, which is between
+     *             0 and 65535, inclusive.
+     *
+     * @see SocketOptions
+     * @see SocketImpl
+     * @see SecurityManager#checkListen
+     * @since   JDK1.1
+     */
+    public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
+        setImpl();
+        if (port < 0 || port > 0xFFFF)
+            throw new IllegalArgumentException(
+                       "Port value out of range: " + port);
+        if (backlog < 1)
+          backlog = 50;
+        try {
+            bind(new InetSocketAddress(bindAddr, port), backlog);
+        } catch(SecurityException e) {
+            close();
+            throw e;
+        } catch(IOException e) {
+            close();
+            throw e;
+        }
+    }
+
+    // Android-changed: Made getImpl() public and @hide, for internal use.
+    /**
+     * Get the {@code SocketImpl} attached to this socket, creating
+     * it if necessary.
+     *
+     * @return  the {@code SocketImpl} attached to that ServerSocket.
+     * @throws SocketException if creation fails.
+     * @since 1.4
+     * @hide
+     */
+    public SocketImpl getImpl() throws SocketException {
+        if (!created)
+            createImpl();
+        return impl;
+    }
+
+    private void checkOldImpl() {
+        if (impl == null)
+            return;
+        // SocketImpl.connect() is a protected method, therefore we need to use
+        // getDeclaredMethod, therefore we need permission to access the member
+        try {
+            AccessController.doPrivileged(
+                new PrivilegedExceptionAction<Void>() {
+                    public Void run() throws NoSuchMethodException {
+                        impl.getClass().getDeclaredMethod("connect",
+                                                          SocketAddress.class,
+                                                          int.class);
+                        return null;
+                    }
+                });
+        } catch (java.security.PrivilegedActionException e) {
+            oldImpl = true;
+        }
+    }
+
+    private void setImpl() {
+        if (factory != null) {
+            impl = factory.createSocketImpl();
+            checkOldImpl();
+        } else {
+            // No need to do a checkOldImpl() here, we know it's an up to date
+            // SocketImpl!
+            impl = new SocksSocketImpl();
+        }
+        if (impl != null)
+            impl.setServerSocket(this);
+    }
+
+    /**
+     * Creates the socket implementation.
+     *
+     * @throws IOException if creation fails
+     * @since 1.4
+     */
+    void createImpl() throws SocketException {
+        if (impl == null)
+            setImpl();
+        try {
+            impl.create(true);
+            created = true;
+        } catch (IOException e) {
+            throw new SocketException(e.getMessage());
+        }
+    }
+
+    /**
+     *
+     * Binds the {@code ServerSocket} to a specific address
+     * (IP address and port number).
+     * <p>
+     * If the address is {@code null}, then the system will pick up
+     * an ephemeral port and a valid local address to bind the socket.
+     * <p>
+     * @param   endpoint        The IP address and port number to bind to.
+     * @throws  IOException if the bind operation fails, or if the socket
+     *                     is already bound.
+     * @throws  SecurityException       if a {@code SecurityManager} is present and
+     * its {@code checkListen} method doesn't allow the operation.
+     * @throws  IllegalArgumentException if endpoint is a
+     *          SocketAddress subclass not supported by this socket
+     * @since 1.4
+     */
+    public void bind(SocketAddress endpoint) throws IOException {
+        bind(endpoint, 50);
+    }
+
+    /**
+     *
+     * Binds the {@code ServerSocket} to a specific address
+     * (IP address and port number).
+     * <p>
+     * If the address is {@code null}, then the system will pick up
+     * an ephemeral port and a valid local address to bind the socket.
+     * <P>
+     * The {@code backlog} argument is the requested maximum number of
+     * pending connections on the socket. Its exact semantics are implementation
+     * specific. In particular, an implementation may impose a maximum length
+     * or may choose to ignore the parameter altogther. The value provided
+     * should be greater than {@code 0}. If it is less than or equal to
+     * {@code 0}, then an implementation specific default will be used.
+     * @param   endpoint        The IP address and port number to bind to.
+     * @param   backlog         requested maximum length of the queue of
+     *                          incoming connections.
+     * @throws  IOException if the bind operation fails, or if the socket
+     *                     is already bound.
+     * @throws  SecurityException       if a {@code SecurityManager} is present and
+     * its {@code checkListen} method doesn't allow the operation.
+     * @throws  IllegalArgumentException if endpoint is a
+     *          SocketAddress subclass not supported by this socket
+     * @since 1.4
+     */
+    public void bind(SocketAddress endpoint, int backlog) throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (!oldImpl && isBound())
+            throw new SocketException("Already bound");
+        if (endpoint == null)
+            endpoint = new InetSocketAddress(0);
+        if (!(endpoint instanceof InetSocketAddress))
+            throw new IllegalArgumentException("Unsupported address type");
+        InetSocketAddress epoint = (InetSocketAddress) endpoint;
+        if (epoint.isUnresolved())
+            throw new SocketException("Unresolved address");
+        if (backlog < 1)
+          backlog = 50;
+        try {
+            SecurityManager security = System.getSecurityManager();
+            if (security != null)
+                security.checkListen(epoint.getPort());
+            getImpl().bind(epoint.getAddress(), epoint.getPort());
+            getImpl().listen(backlog);
+            bound = true;
+        } catch(SecurityException e) {
+            bound = false;
+            throw e;
+        } catch(IOException e) {
+            bound = false;
+            throw e;
+        }
+    }
+
+    /**
+     * Returns the local address of this server socket.
+     * <p>
+     * If the socket was bound prior to being {@link #close closed},
+     * then this method will continue to return the local address
+     * after the socket is closed.
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * the {@link InetAddress#getLoopbackAddress loopback} address is returned.
+     *
+     * @return  the address to which this socket is bound,
+     *          or the loopback address if denied by the security manager,
+     *          or {@code null} if the socket is unbound.
+     *
+     * @see SecurityManager#checkConnect
+     */
+    public InetAddress getInetAddress() {
+        if (!isBound())
+            return null;
+        try {
+            InetAddress in = getImpl().getInetAddress();
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null)
+                sm.checkConnect(in.getHostAddress(), -1);
+            return in;
+        } catch (SecurityException e) {
+            return InetAddress.getLoopbackAddress();
+        } catch (SocketException e) {
+            // nothing
+            // If we're bound, the impl has been created
+            // so we shouldn't get here
+        }
+        return null;
+    }
+
+    /**
+     * Returns the port number on which this socket is listening.
+     * <p>
+     * If the socket was bound prior to being {@link #close closed},
+     * then this method will continue to return the port number
+     * after the socket is closed.
+     *
+     * @return  the port number to which this socket is listening or
+     *          -1 if the socket is not bound yet.
+     */
+    public int getLocalPort() {
+        if (!isBound())
+            return -1;
+        try {
+            return getImpl().getLocalPort();
+        } catch (SocketException e) {
+            // nothing
+            // If we're bound, the impl has been created
+            // so we shouldn't get here
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the address of the endpoint this socket is bound to.
+     * <p>
+     * If the socket was bound prior to being {@link #close closed},
+     * then this method will continue to return the address of the endpoint
+     * after the socket is closed.
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * a {@code SocketAddress} representing the
+     * {@link InetAddress#getLoopbackAddress loopback} address and the local
+     * port to which the socket is bound is returned.
+     *
+     * @return a {@code SocketAddress} representing the local endpoint of
+     *         this socket, or a {@code SocketAddress} representing the
+     *         loopback address if denied by the security manager,
+     *         or {@code null} if the socket is not bound yet.
+     *
+     * @see #getInetAddress()
+     * @see #getLocalPort()
+     * @see #bind(SocketAddress)
+     * @see SecurityManager#checkConnect
+     * @since 1.4
+     */
+
+    public SocketAddress getLocalSocketAddress() {
+        if (!isBound())
+            return null;
+        return new InetSocketAddress(getInetAddress(), getLocalPort());
+    }
+
+    /**
+     * Listens for a connection to be made to this socket and accepts
+     * it. The method blocks until a connection is made.
+     *
+     * <p>A new Socket {@code s} is created and, if there
+     * is a security manager,
+     * the security manager's {@code checkAccept} method is called
+     * with {@code s.getInetAddress().getHostAddress()} and
+     * {@code s.getPort()}
+     * as its arguments to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @exception  IOException  if an I/O error occurs when waiting for a
+     *               connection.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkAccept} method doesn't allow the operation.
+     * @exception  SocketTimeoutException if a timeout was previously set with setSoTimeout and
+     *             the timeout has been reached.
+     * @exception  java.nio.channels.IllegalBlockingModeException
+     *             if this socket has an associated channel, the channel is in
+     *             non-blocking mode, and there is no connection ready to be
+     *             accepted
+     *
+     * @return the new Socket
+     * @see SecurityManager#checkAccept
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public Socket accept() throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (!isBound())
+            throw new SocketException("Socket is not bound yet");
+        Socket s = new Socket((SocketImpl) null);
+        implAccept(s);
+        return s;
+    }
+
+    /**
+     * Subclasses of ServerSocket use this method to override accept()
+     * to return their own subclass of socket.  So a FooServerSocket
+     * will typically hand this method an <i>empty</i> FooSocket.  On
+     * return from implAccept the FooSocket will be connected to a client.
+     *
+     * @param s the Socket
+     * @throws java.nio.channels.IllegalBlockingModeException
+     *         if this socket has an associated channel,
+     *         and the channel is in non-blocking mode
+     * @throws IOException if an I/O error occurs when waiting
+     * for a connection.
+     * @since   JDK1.1
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    protected final void implAccept(Socket s) throws IOException {
+        SocketImpl si = null;
+        try {
+            if (s.impl == null)
+              s.setImpl();
+            else {
+                s.impl.reset();
+            }
+            si = s.impl;
+            s.impl = null;
+            si.address = new InetAddress();
+            si.fd = new FileDescriptor();
+            getImpl().accept(si);
+
+            SecurityManager security = System.getSecurityManager();
+            if (security != null) {
+                security.checkAccept(si.getInetAddress().getHostAddress(),
+                                     si.getPort());
+            }
+        } catch (IOException e) {
+            if (si != null)
+                si.reset();
+            s.impl = si;
+            throw e;
+        } catch (SecurityException e) {
+            if (si != null)
+                si.reset();
+            s.impl = si;
+            throw e;
+        }
+        s.impl = si;
+        s.postAccept();
+    }
+
+    /**
+     * Closes this socket.
+     *
+     * Any thread currently blocked in {@link #accept()} will throw
+     * a {@link SocketException}.
+     *
+     * <p> If this socket has an associated channel then the channel is closed
+     * as well.
+     *
+     * @exception  IOException  if an I/O error occurs when closing the socket.
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public void close() throws IOException {
+        synchronized(closeLock) {
+            if (isClosed())
+                return;
+            if (created)
+                impl.close();
+            closed = true;
+        }
+    }
+
+    /**
+     * Returns the unique {@link java.nio.channels.ServerSocketChannel} object
+     * associated with this socket, if any.
+     *
+     * <p> A server socket will have a channel if, and only if, the channel
+     * itself was created via the {@link
+     * java.nio.channels.ServerSocketChannel#open ServerSocketChannel.open}
+     * method.
+     *
+     * @return  the server-socket channel associated with this socket,
+     *          or {@code null} if this socket was not created
+     *          for a channel
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public ServerSocketChannel getChannel() {
+        return null;
+    }
+
+    /**
+     * Returns the binding state of the ServerSocket.
+     *
+     * @return true if the ServerSocket successfully bound to an address
+     * @since 1.4
+     */
+    public boolean isBound() {
+        // Before 1.3 ServerSockets were always bound during creation
+        return bound || oldImpl;
+    }
+
+    /**
+     * Returns the closed state of the ServerSocket.
+     *
+     * @return true if the socket has been closed
+     * @since 1.4
+     */
+    public boolean isClosed() {
+        synchronized(closeLock) {
+            return closed;
+        }
+    }
+
+    /**
+     * Enable/disable {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT} with the
+     * specified timeout, in milliseconds.  With this option set to a non-zero
+     * timeout, a call to accept() for this ServerSocket
+     * will block for only this amount of time.  If the timeout expires,
+     * a <B>java.net.SocketTimeoutException</B> is raised, though the
+     * ServerSocket is still valid.  The option <B>must</B> be enabled
+     * prior to entering the blocking operation to have effect.  The
+     * timeout must be {@code > 0}.
+     * A timeout of zero is interpreted as an infinite timeout.
+     * @param timeout the specified timeout, in milliseconds
+     * @exception SocketException if there is an error in
+     * the underlying protocol, such as a TCP error.
+     * @since   JDK1.1
+     * @see #getSoTimeout()
+     */
+    public synchronized void setSoTimeout(int timeout) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
+    }
+
+    /**
+     * Retrieve setting for {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT}.
+     * 0 returns implies that the option is disabled (i.e., timeout of infinity).
+     * @return the {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT} value
+     * @exception IOException if an I/O error occurs
+     * @since   JDK1.1
+     * @see #setSoTimeout(int)
+     */
+    public synchronized int getSoTimeout() throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
+        /* extra type safety */
+        if (o instanceof Integer) {
+            return ((Integer) o).intValue();
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Enable/disable the {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR}
+     * socket option.
+     * <p>
+     * When a TCP connection is closed the connection may remain
+     * in a timeout state for a period of time after the connection
+     * is closed (typically known as the {@code TIME_WAIT} state
+     * or {@code 2MSL} wait state).
+     * For applications using a well known socket address or port
+     * it may not be possible to bind a socket to the required
+     * {@code SocketAddress} if there is a connection in the
+     * timeout state involving the socket address or port.
+     * <p>
+     * Enabling {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} prior to
+     * binding the socket using {@link #bind(SocketAddress)} allows the socket
+     * to be bound even though a previous connection is in a timeout state.
+     * <p>
+     * When a {@code ServerSocket} is created the initial setting
+     * of {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is not defined.
+     * Applications can use {@link #getReuseAddress()} to determine the initial
+     * setting of {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR}.
+     * <p>
+     * The behaviour when {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is
+     * enabled or disabled after a socket is bound (See {@link #isBound()})
+     * is not defined.
+     *
+     * @param on  whether to enable or disable the socket option
+     * @exception SocketException if an error occurs enabling or
+     *            disabling the {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR}
+     *            socket option, or the socket is closed.
+     * @since 1.4
+     * @see #getReuseAddress()
+     * @see #bind(SocketAddress)
+     * @see #isBound()
+     * @see #isClosed()
+     */
+    public void setReuseAddress(boolean on) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on));
+    }
+
+    /**
+     * Tests if {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is enabled.
+     *
+     * @return a {@code boolean} indicating whether or not
+     *         {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is enabled.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @since   1.4
+     * @see #setReuseAddress(boolean)
+     */
+    public boolean getReuseAddress() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        return ((Boolean) (getImpl().getOption(SocketOptions.SO_REUSEADDR))).booleanValue();
+    }
+
+    /**
+     * Returns the implementation address and implementation port of
+     * this socket as a {@code String}.
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * an {@code InetAddress} representing the
+     * {@link InetAddress#getLoopbackAddress loopback} address is returned as
+     * the implementation address.
+     *
+     * @return  a string representation of this socket.
+     */
+    public String toString() {
+        if (!isBound())
+            return "ServerSocket[unbound]";
+        InetAddress in;
+        if (System.getSecurityManager() != null)
+            in = InetAddress.getLoopbackAddress();
+        else
+            in = impl.getInetAddress();
+        return "ServerSocket[addr=" + in +
+                ",localport=" + impl.getLocalPort()  + "]";
+    }
+
+    void setBound() {
+        bound = true;
+    }
+
+    void setCreated() {
+        created = true;
+    }
+
+    /**
+     * The factory for all server sockets.
+     */
+    private static SocketImplFactory factory = null;
+
+    /**
+     * Sets the server socket implementation factory for the
+     * application. The factory can be specified only once.
+     * <p>
+     * When an application creates a new server socket, the socket
+     * implementation factory's {@code createSocketImpl} method is
+     * called to create the actual socket implementation.
+     * <p>
+     * Passing {@code null} to the method is a no-op unless the factory
+     * was already set.
+     * <p>
+     * If there is a security manager, this method first calls
+     * the security manager's {@code checkSetFactory} method
+     * to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param      fac   the desired factory.
+     * @exception  IOException  if an I/O error occurs when setting the
+     *               socket factory.
+     * @exception  SocketException  if the factory has already been defined.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkSetFactory} method doesn't allow the operation.
+     * @see        java.net.SocketImplFactory#createSocketImpl()
+     * @see        SecurityManager#checkSetFactory
+     */
+    public static synchronized void setSocketFactory(SocketImplFactory fac) throws IOException {
+        if (factory != null) {
+            throw new SocketException("factory already defined");
+        }
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkSetFactory();
+        }
+        factory = fac;
+    }
+
+    /**
+     * Sets a default proposed value for the
+     * {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option for sockets
+     * accepted from this {@code ServerSocket}. The value actually set
+     * in the accepted socket must be determined by calling
+     * {@link Socket#getReceiveBufferSize()} after the socket
+     * is returned by {@link #accept()}.
+     * <p>
+     * The value of {@link SocketOptions#SO_RCVBUF SO_RCVBUF} is used both to
+     * set the size of the internal socket receive buffer, and to set the size
+     * of the TCP receive window that is advertized to the remote peer.
+     * <p>
+     * It is possible to change the value subsequently, by calling
+     * {@link Socket#setReceiveBufferSize(int)}. However, if the application
+     * wishes to allow a receive window larger than 64K bytes, as defined by RFC1323
+     * then the proposed value must be set in the ServerSocket <B>before</B>
+     * it is bound to a local address. This implies, that the ServerSocket must be
+     * created with the no-argument constructor, then setReceiveBufferSize() must
+     * be called and lastly the ServerSocket is bound to an address by calling bind().
+     * <p>
+     * Failure to do this will not cause an error, and the buffer size may be set to the
+     * requested value but the TCP receive window in sockets accepted from
+     * this ServerSocket will be no larger than 64K bytes.
+     *
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     *
+     * @param size the size to which to set the receive buffer
+     * size. This value must be greater than 0.
+     *
+     * @exception IllegalArgumentException if the
+     * value is 0 or is negative.
+     *
+     * @since 1.4
+     * @see #getReceiveBufferSize
+     */
+     public synchronized void setReceiveBufferSize (int size) throws SocketException {
+        if (!(size > 0)) {
+            throw new IllegalArgumentException("negative receive size");
+        }
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size));
+    }
+
+    /**
+     * Gets the value of the {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option
+     * for this {@code ServerSocket}, that is the proposed buffer size that
+     * will be used for Sockets accepted from this {@code ServerSocket}.
+     *
+     * <p>Note, the value actually set in the accepted socket is determined by
+     * calling {@link Socket#getReceiveBufferSize()}.
+     * @return the value of the {@link SocketOptions#SO_RCVBUF SO_RCVBUF}
+     *         option for this {@code Socket}.
+     * @exception SocketException if there is an error
+     *            in the underlying protocol, such as a TCP error.
+     * @see #setReceiveBufferSize(int)
+     * @since 1.4
+     */
+    public synchronized int getReceiveBufferSize()
+    throws SocketException{
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        int result = 0;
+        Object o = getImpl().getOption(SocketOptions.SO_RCVBUF);
+        if (o instanceof Integer) {
+            result = ((Integer)o).intValue();
+        }
+        return result;
+    }
+
+    /**
+     * Sets performance preferences for this ServerSocket.
+     *
+     * <p> Sockets use the TCP/IP protocol by default.  Some implementations
+     * may offer alternative protocols which have different performance
+     * characteristics than TCP/IP.  This method allows the application to
+     * express its own preferences as to how these tradeoffs should be made
+     * when the implementation chooses from the available protocols.
+     *
+     * <p> Performance preferences are described by three integers
+     * whose values indicate the relative importance of short connection time,
+     * low latency, and high bandwidth.  The absolute values of the integers
+     * are irrelevant; in order to choose a protocol the values are simply
+     * compared, with larger values indicating stronger preferences.  If the
+     * application prefers short connection time over both low latency and high
+     * bandwidth, for example, then it could invoke this method with the values
+     * {@code (1, 0, 0)}.  If the application prefers high bandwidth above low
+     * latency, and low latency above short connection time, then it could
+     * invoke this method with the values {@code (0, 1, 2)}.
+     *
+     * <p> Invoking this method after this socket has been bound
+     * will have no effect. This implies that in order to use this capability
+     * requires the socket to be created with the no-argument constructor.
+     *
+     * @param  connectionTime
+     *         An {@code int} expressing the relative importance of a short
+     *         connection time
+     *
+     * @param  latency
+     *         An {@code int} expressing the relative importance of low
+     *         latency
+     *
+     * @param  bandwidth
+     *         An {@code int} expressing the relative importance of high
+     *         bandwidth
+     *
+     * @since 1.5
+     */
+    public void setPerformancePreferences(int connectionTime,
+                                          int latency,
+                                          int bandwidth)
+    {
+        /* Not implemented yet */
+    }
+
+    // Android-added: getFileDescriptor$(), for testing / internal use.
+    /**
+     * @hide internal use only
+     */
+    public FileDescriptor getFileDescriptor$() {
+        return impl.getFileDescriptor();
+    }
+}
diff --git a/java/net/Socket.annotated.java b/java/net/Socket.annotated.java
new file mode 100644
index 0000000..e021788
--- /dev/null
+++ b/java/net/Socket.annotated.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.net;
+
+import java.nio.channels.SocketChannel;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Socket implements java.io.Closeable {
+
+public Socket() { throw new RuntimeException("Stub!"); }
+
+public Socket(java.net.Proxy proxy) { throw new RuntimeException("Stub!"); }
+
+protected Socket(java.net.SocketImpl impl) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public Socket(java.lang.String host, int port) throws java.io.IOException, java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+
+public Socket(java.net.InetAddress address, int port) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public Socket(java.lang.String host, int port, java.net.InetAddress localAddr, int localPort) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public Socket(java.net.InetAddress address, int port, java.net.InetAddress localAddr, int localPort) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public Socket(java.lang.String host, int port, boolean stream) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public Socket(java.net.InetAddress host, int port, boolean stream) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void connect(java.net.SocketAddress endpoint) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void connect(java.net.SocketAddress endpoint, int timeout) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void bind(java.net.SocketAddress bindpoint) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public java.net.InetAddress getInetAddress() { throw new RuntimeException("Stub!"); }
+
+public java.net.InetAddress getLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public int getPort() { throw new RuntimeException("Stub!"); }
+
+public int getLocalPort() { throw new RuntimeException("Stub!"); }
+
+public java.net.SocketAddress getRemoteSocketAddress() { throw new RuntimeException("Stub!"); }
+
+public java.net.SocketAddress getLocalSocketAddress() { throw new RuntimeException("Stub!"); }
+
+public java.nio.channels.SocketChannel getChannel() { throw new RuntimeException("Stub!"); }
+
+public java.io.InputStream getInputStream() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public java.io.OutputStream getOutputStream() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void setTcpNoDelay(boolean on) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public boolean getTcpNoDelay() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public void setSoLinger(boolean on, int linger) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public int getSoLinger() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public void sendUrgentData(int data) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void setOOBInline(boolean on) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public boolean getOOBInline() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void setSoTimeout(int timeout) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized int getSoTimeout() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void setSendBufferSize(int size) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized int getSendBufferSize() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void setReceiveBufferSize(int size) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized int getReceiveBufferSize() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public void setKeepAlive(boolean on) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public boolean getKeepAlive() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public void setTrafficClass(int tc) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public int getTrafficClass() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public void setReuseAddress(boolean on) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public boolean getReuseAddress() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void close() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void shutdownInput() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void shutdownOutput() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public boolean isConnected() { throw new RuntimeException("Stub!"); }
+
+public boolean isBound() { throw new RuntimeException("Stub!"); }
+
+public boolean isClosed() { throw new RuntimeException("Stub!"); }
+
+public boolean isInputShutdown() { throw new RuntimeException("Stub!"); }
+
+public boolean isOutputShutdown() { throw new RuntimeException("Stub!"); }
+
+public static synchronized void setSocketImplFactory(java.net.SocketImplFactory fac) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { throw new RuntimeException("Stub!"); }
+
[email protected]
[email protected]
+public java.io.FileDescriptor getFileDescriptor$() { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/net/Socket.java b/java/net/Socket.java
new file mode 100644
index 0000000..bae1d1c
--- /dev/null
+++ b/java/net/Socket.java
@@ -0,0 +1,1783 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.FileDescriptor;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.nio.channels.SocketChannel;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.security.PrivilegedAction;
+
+/**
+ * This class implements client sockets (also called just
+ * "sockets"). A socket is an endpoint for communication
+ * between two machines.
+ * <p>
+ * The actual work of the socket is performed by an instance of the
+ * {@code SocketImpl} class. An application, by changing
+ * the socket factory that creates the socket implementation,
+ * can configure itself to create sockets appropriate to the local
+ * firewall.
+ *
+ * @author  unascribed
+ * @see     java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory)
+ * @see     java.net.SocketImpl
+ * @see     java.nio.channels.SocketChannel
+ * @since   JDK1.0
+ */
+public
+class Socket implements java.io.Closeable {
+    /**
+     * Various states of this socket.
+     */
+    private boolean created = false;
+    private boolean bound = false;
+    private boolean connected = false;
+    private boolean closed = false;
+    private Object closeLock = new Object();
+    private boolean shutIn = false;
+    private boolean shutOut = false;
+
+    /**
+     * The implementation of this Socket.
+     */
+    SocketImpl impl;
+
+    /**
+     * Are we using an older SocketImpl?
+     */
+    private boolean oldImpl = false;
+
+    /**
+     * Creates an unconnected socket, with the
+     * system-default type of SocketImpl.
+     *
+     * @since   JDK1.1
+     * @revised 1.4
+     */
+    public Socket() {
+        setImpl();
+    }
+
+    /**
+     * Creates an unconnected socket, specifying the type of proxy, if any,
+     * that should be used regardless of any other settings.
+     * <P>
+     * If there is a security manager, its {@code checkConnect} method
+     * is called with the proxy host address and port number
+     * as its arguments. This could result in a SecurityException.
+     * <P>
+     * Examples:
+     * <UL> <LI>{@code Socket s = new Socket(Proxy.NO_PROXY);} will create
+     * a plain socket ignoring any other proxy configuration.</LI>
+     * <LI>{@code Socket s = new Socket(new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("socks.mydom.com", 1080)));}
+     * will create a socket connecting through the specified SOCKS proxy
+     * server.</LI>
+     * </UL>
+     *
+     * @param proxy a {@link java.net.Proxy Proxy} object specifying what kind
+     *              of proxying should be used.
+     * @throws IllegalArgumentException if the proxy is of an invalid type
+     *          or {@code null}.
+     * @throws SecurityException if a security manager is present and
+     *                           permission to connect to the proxy is
+     *                           denied.
+     * @see java.net.ProxySelector
+     * @see java.net.Proxy
+     *
+     * @since   1.5
+     */
+    public Socket(Proxy proxy) {
+        // Create a copy of Proxy as a security measure
+        if (proxy == null) {
+            throw new IllegalArgumentException("Invalid Proxy");
+        }
+        Proxy p = proxy == Proxy.NO_PROXY ? Proxy.NO_PROXY
+                                          : sun.net.ApplicationProxy.create(proxy);
+        Proxy.Type type = p.type();
+        // Android-changed: Removed HTTP proxy support.
+        // if (type == Proxy.Type.SOCKS || type == Proxy.Type.HTTP) {
+        if (type == Proxy.Type.SOCKS) {
+            SecurityManager security = System.getSecurityManager();
+            InetSocketAddress epoint = (InetSocketAddress) p.address();
+            if (epoint.getAddress() != null) {
+                checkAddress (epoint.getAddress(), "Socket");
+            }
+            if (security != null) {
+                if (epoint.isUnresolved())
+                    epoint = new InetSocketAddress(epoint.getHostName(), epoint.getPort());
+                if (epoint.isUnresolved())
+                    security.checkConnect(epoint.getHostName(), epoint.getPort());
+                else
+                    security.checkConnect(epoint.getAddress().getHostAddress(),
+                                  epoint.getPort());
+            }
+            // Android-changed: Removed HTTP proxy support.
+            // impl = type == Proxy.Type.SOCKS ? new SocksSocketImpl(p)
+            //                                : new HttpConnectSocketImpl(p);
+            impl = new SocksSocketImpl(p);
+            impl.setSocket(this);
+        } else {
+            if (p == Proxy.NO_PROXY) {
+                if (factory == null) {
+                    impl = new PlainSocketImpl();
+                    impl.setSocket(this);
+                } else
+                    setImpl();
+            } else
+                throw new IllegalArgumentException("Invalid Proxy");
+        }
+    }
+
+    /**
+     * Creates an unconnected Socket with a user-specified
+     * SocketImpl.
+     * <P>
+     * @param impl an instance of a <B>SocketImpl</B>
+     * the subclass wishes to use on the Socket.
+     *
+     * @exception SocketException if there is an error in the underlying protocol,
+     * such as a TCP error.
+     * @since   JDK1.1
+     */
+    protected Socket(SocketImpl impl) throws SocketException {
+        this.impl = impl;
+        if (impl != null) {
+            checkOldImpl();
+            this.impl.setSocket(this);
+        }
+    }
+
+    /**
+     * Creates a stream socket and connects it to the specified port
+     * number on the named host.
+     * <p>
+     * If the specified host is {@code null} it is the equivalent of
+     * specifying the address as
+     * {@link java.net.InetAddress#getByName InetAddress.getByName}{@code (null)}.
+     * In other words, it is equivalent to specifying an address of the
+     * loopback interface. </p>
+     * <p>
+     * If the application has specified a server socket factory, that
+     * factory's {@code createSocketImpl} method is called to create
+     * the actual socket implementation. Otherwise a "plain" socket is created.
+     * <p>
+     * If there is a security manager, its
+     * {@code checkConnect} method is called
+     * with the host address and {@code port}
+     * as its arguments. This could result in a SecurityException.
+     *
+     * @param      host   the host name, or {@code null} for the loopback address.
+     * @param      port   the port number.
+     *
+     * @exception  UnknownHostException if the IP address of
+     * the host could not be determined.
+     *
+     * @exception  IOException  if an I/O error occurs when creating the socket.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkConnect} method doesn't allow the operation.
+     * @exception  IllegalArgumentException if the port parameter is outside
+     *             the specified range of valid port values, which is between
+     *             0 and 65535, inclusive.
+     * @see        java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory)
+     * @see        java.net.SocketImpl
+     * @see        java.net.SocketImplFactory#createSocketImpl()
+     * @see        SecurityManager#checkConnect
+     */
+    public Socket(String host, int port)
+        throws UnknownHostException, IOException
+    {
+        // Android-changed: App compat. Socket ctor should try all addresses. http://b/30007735
+        this(InetAddress.getAllByName(host), port, (SocketAddress) null, true);
+    }
+
+    /**
+     * Creates a stream socket and connects it to the specified port
+     * number at the specified IP address.
+     * <p>
+     * If the application has specified a socket factory, that factory's
+     * {@code createSocketImpl} method is called to create the
+     * actual socket implementation. Otherwise a "plain" socket is created.
+     * <p>
+     * If there is a security manager, its
+     * {@code checkConnect} method is called
+     * with the host address and {@code port}
+     * as its arguments. This could result in a SecurityException.
+     *
+     * @param      address   the IP address.
+     * @param      port      the port number.
+     * @exception  IOException  if an I/O error occurs when creating the socket.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkConnect} method doesn't allow the operation.
+     * @exception  IllegalArgumentException if the port parameter is outside
+     *             the specified range of valid port values, which is between
+     *             0 and 65535, inclusive.
+     * @exception  NullPointerException if {@code address} is null.
+     * @see        java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory)
+     * @see        java.net.SocketImpl
+     * @see        java.net.SocketImplFactory#createSocketImpl()
+     * @see        SecurityManager#checkConnect
+     */
+    public Socket(InetAddress address, int port) throws IOException {
+        // Android-changed: App compat. Socket ctor should try all addresses. http://b/30007735
+        this(nonNullAddress(address), port, (SocketAddress) null, true);
+    }
+
+    /**
+     * Creates a socket and connects it to the specified remote host on
+     * the specified remote port. The Socket will also bind() to the local
+     * address and port supplied.
+     * <p>
+     * If the specified host is {@code null} it is the equivalent of
+     * specifying the address as
+     * {@link java.net.InetAddress#getByName InetAddress.getByName}{@code (null)}.
+     * In other words, it is equivalent to specifying an address of the
+     * loopback interface. </p>
+     * <p>
+     * A local port number of {@code zero} will let the system pick up a
+     * free port in the {@code bind} operation.</p>
+     * <p>
+     * If there is a security manager, its
+     * {@code checkConnect} method is called
+     * with the host address and {@code port}
+     * as its arguments. This could result in a SecurityException.
+     *
+     * @param host the name of the remote host, or {@code null} for the loopback address.
+     * @param port the remote port
+     * @param localAddr the local address the socket is bound to, or
+     *        {@code null} for the {@code anyLocal} address.
+     * @param localPort the local port the socket is bound to, or
+     *        {@code zero} for a system selected free port.
+     * @exception  IOException  if an I/O error occurs when creating the socket.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkConnect} method doesn't allow the connection
+     *             to the destination, or if its {@code checkListen} method
+     *             doesn't allow the bind to the local port.
+     * @exception  IllegalArgumentException if the port parameter or localPort
+     *             parameter is outside the specified range of valid port values,
+     *             which is between 0 and 65535, inclusive.
+     * @see        SecurityManager#checkConnect
+     * @since   JDK1.1
+     */
+    public Socket(String host, int port, InetAddress localAddr,
+                  int localPort) throws IOException {
+        // Android-changed: App compat. Socket ctor should try all addresses. http://b/30007735
+        this(InetAddress.getAllByName(host), port,
+             new InetSocketAddress(localAddr, localPort), true);
+    }
+
+    /**
+     * Creates a socket and connects it to the specified remote address on
+     * the specified remote port. The Socket will also bind() to the local
+     * address and port supplied.
+     * <p>
+     * If the specified local address is {@code null} it is the equivalent of
+     * specifying the address as the AnyLocal address
+     * (see {@link java.net.InetAddress#isAnyLocalAddress InetAddress.isAnyLocalAddress}{@code ()}).
+     * <p>
+     * A local port number of {@code zero} will let the system pick up a
+     * free port in the {@code bind} operation.</p>
+     * <p>
+     * If there is a security manager, its
+     * {@code checkConnect} method is called
+     * with the host address and {@code port}
+     * as its arguments. This could result in a SecurityException.
+     *
+     * @param address the remote address
+     * @param port the remote port
+     * @param localAddr the local address the socket is bound to, or
+     *        {@code null} for the {@code anyLocal} address.
+     * @param localPort the local port the socket is bound to or
+     *        {@code zero} for a system selected free port.
+     * @exception  IOException  if an I/O error occurs when creating the socket.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkConnect} method doesn't allow the connection
+     *             to the destination, or if its {@code checkListen} method
+     *             doesn't allow the bind to the local port.
+     * @exception  IllegalArgumentException if the port parameter or localPort
+     *             parameter is outside the specified range of valid port values,
+     *             which is between 0 and 65535, inclusive.
+     * @exception  NullPointerException if {@code address} is null.
+     * @see        SecurityManager#checkConnect
+     * @since   JDK1.1
+     */
+    public Socket(InetAddress address, int port, InetAddress localAddr,
+                  int localPort) throws IOException {
+        // Android-changed: App compat. Socket ctor should try all addresses. http://b/30007735
+        this(nonNullAddress(address), port,
+             new InetSocketAddress(localAddr, localPort), true);
+    }
+
+    /**
+     * Creates a stream socket and connects it to the specified port
+     * number on the named host.
+     * <p>
+     * If the specified host is {@code null} it is the equivalent of
+     * specifying the address as
+     * {@link java.net.InetAddress#getByName InetAddress.getByName}{@code (null)}.
+     * In other words, it is equivalent to specifying an address of the
+     * loopback interface. </p>
+     * <p>
+     * If the stream argument is {@code true}, this creates a
+     * stream socket. If the stream argument is {@code false}, it
+     * creates a datagram socket.
+     * <p>
+     * If the application has specified a server socket factory, that
+     * factory's {@code createSocketImpl} method is called to create
+     * the actual socket implementation. Otherwise a "plain" socket is created.
+     * <p>
+     * If there is a security manager, its
+     * {@code checkConnect} method is called
+     * with the host address and {@code port}
+     * as its arguments. This could result in a SecurityException.
+     * <p>
+     * If a UDP socket is used, TCP/IP related socket options will not apply.
+     *
+     * @param      host     the host name, or {@code null} for the loopback address.
+     * @param      port     the port number.
+     * @param      stream   a {@code boolean} indicating whether this is
+     *                      a stream socket or a datagram socket.
+     * @exception  IOException  if an I/O error occurs when creating the socket.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkConnect} method doesn't allow the operation.
+     * @exception  IllegalArgumentException if the port parameter is outside
+     *             the specified range of valid port values, which is between
+     *             0 and 65535, inclusive.
+     * @see        java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory)
+     * @see        java.net.SocketImpl
+     * @see        java.net.SocketImplFactory#createSocketImpl()
+     * @see        SecurityManager#checkConnect
+     * @deprecated Use DatagramSocket instead for UDP transport.
+     */
+    @Deprecated
+    public Socket(String host, int port, boolean stream) throws IOException {
+        // Android-changed: App compat. Socket ctor should try all addresses. http://b/30007735
+        this(InetAddress.getAllByName(host), port, (SocketAddress) null, stream);
+    }
+
+    /**
+     * Creates a socket and connects it to the specified port number at
+     * the specified IP address.
+     * <p>
+     * If the stream argument is {@code true}, this creates a
+     * stream socket. If the stream argument is {@code false}, it
+     * creates a datagram socket.
+     * <p>
+     * If the application has specified a server socket factory, that
+     * factory's {@code createSocketImpl} method is called to create
+     * the actual socket implementation. Otherwise a "plain" socket is created.
+     *
+     * <p>If there is a security manager, its
+     * {@code checkConnect} method is called
+     * with {@code host.getHostAddress()} and {@code port}
+     * as its arguments. This could result in a SecurityException.
+     * <p>
+     * If UDP socket is used, TCP/IP related socket options will not apply.
+     *
+     * @param      host     the IP address.
+     * @param      port      the port number.
+     * @param      stream    if {@code true}, create a stream socket;
+     *                       otherwise, create a datagram socket.
+     * @exception  IOException  if an I/O error occurs when creating the socket.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkConnect} method doesn't allow the operation.
+     * @exception  IllegalArgumentException if the port parameter is outside
+     *             the specified range of valid port values, which is between
+     *             0 and 65535, inclusive.
+     * @exception  NullPointerException if {@code host} is null.
+     * @see        java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory)
+     * @see        java.net.SocketImpl
+     * @see        java.net.SocketImplFactory#createSocketImpl()
+     * @see        SecurityManager#checkConnect
+     * @deprecated Use DatagramSocket instead for UDP transport.
+     */
+    @Deprecated
+    public Socket(InetAddress host, int port, boolean stream) throws IOException {
+        // Android-changed: App compat. Socket ctor should try all addresses. http://b/30007735
+        this(nonNullAddress(host), port, new InetSocketAddress(0), stream);
+    }
+
+    // BEGIN Android-changed: App compat. Socket ctor should try all addresses. http://b/30007735
+    private static InetAddress[] nonNullAddress(InetAddress address) {
+        // backward compatibility
+        if (address == null)
+            throw new NullPointerException();
+
+        return new InetAddress[] { address };
+    }
+
+    private Socket(InetAddress[] addresses, int port, SocketAddress localAddr,
+            boolean stream) throws IOException {
+        if (addresses == null || addresses.length == 0) {
+            throw new SocketException("Impossible: empty address list");
+        }
+
+        for (int i = 0; i < addresses.length; i++) {
+            setImpl();
+            try {
+                InetSocketAddress address = new InetSocketAddress(addresses[i], port);
+                createImpl(stream);
+                if (localAddr != null) {
+                    bind(localAddr);
+                }
+                connect(address);
+                break;
+            } catch (IOException | IllegalArgumentException | SecurityException e) {
+                try {
+                    // Android-changed: Let ctor call impl.close() instead of overridable close().
+                    // Subclasses may not expect a call to close() coming from this constructor.
+                    impl.close();
+                    closed = true;
+                } catch (IOException ce) {
+                    e.addSuppressed(ce);
+                }
+
+                // Only stop on the last address.
+                if (i == addresses.length - 1) {
+                    throw e;
+                }
+            }
+
+            // Discard the connection state and try again.
+            impl = null;
+            created = false;
+            bound = false;
+            closed = false;
+        }
+    }
+    // END Android-changed: App compat. Socket ctor should try all addresses. http://b/30007735
+
+    /**
+     * Creates the socket implementation.
+     *
+     * @param stream a {@code boolean} value : {@code true} for a TCP socket,
+     *               {@code false} for UDP.
+     * @throws IOException if creation fails
+     * @since 1.4
+     */
+     void createImpl(boolean stream) throws SocketException {
+        if (impl == null)
+            setImpl();
+        try {
+            impl.create(stream);
+            created = true;
+        } catch (IOException e) {
+            throw new SocketException(e.getMessage());
+        }
+    }
+
+    private void checkOldImpl() {
+        if (impl == null)
+            return;
+        // SocketImpl.connect() is a protected method, therefore we need to use
+        // getDeclaredMethod, therefore we need permission to access the member
+
+        oldImpl = AccessController.doPrivileged
+                                (new PrivilegedAction<Boolean>() {
+            public Boolean run() {
+                Class<?> clazz = impl.getClass();
+                while (true) {
+                    try {
+                        clazz.getDeclaredMethod("connect", SocketAddress.class, int.class);
+                        return Boolean.FALSE;
+                    } catch (NoSuchMethodException e) {
+                        clazz = clazz.getSuperclass();
+                        // java.net.SocketImpl class will always have this abstract method.
+                        // If we have not found it by now in the hierarchy then it does not
+                        // exist, we are an old style impl.
+                        if (clazz.equals(java.net.SocketImpl.class)) {
+                            return Boolean.TRUE;
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Sets impl to the system-default type of SocketImpl.
+     * @since 1.4
+     */
+    void setImpl() {
+        if (factory != null) {
+            impl = factory.createSocketImpl();
+            checkOldImpl();
+        } else {
+            // No need to do a checkOldImpl() here, we know it's an up to date
+            // SocketImpl!
+            impl = new SocksSocketImpl();
+        }
+        if (impl != null)
+            impl.setSocket(this);
+    }
+
+
+    /**
+     * Get the {@code SocketImpl} attached to this socket, creating
+     * it if necessary.
+     *
+     * @return  the {@code SocketImpl} attached to that ServerSocket.
+     * @throws SocketException if creation fails
+     * @since 1.4
+     */
+    SocketImpl getImpl() throws SocketException {
+        if (!created)
+            createImpl(true);
+        return impl;
+    }
+
+    /**
+     * Connects this socket to the server.
+     *
+     * @param   endpoint the {@code SocketAddress}
+     * @throws  IOException if an error occurs during the connection
+     * @throws  java.nio.channels.IllegalBlockingModeException
+     *          if this socket has an associated channel,
+     *          and the channel is in non-blocking mode
+     * @throws  IllegalArgumentException if endpoint is null or is a
+     *          SocketAddress subclass not supported by this socket
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public void connect(SocketAddress endpoint) throws IOException {
+        connect(endpoint, 0);
+    }
+
+    /**
+     * Connects this socket to the server with a specified timeout value.
+     * A timeout of zero is interpreted as an infinite timeout. The connection
+     * will then block until established or an error occurs.
+     *
+     * @param   endpoint the {@code SocketAddress}
+     * @param   timeout  the timeout value to be used in milliseconds.
+     * @throws  IOException if an error occurs during the connection
+     * @throws  SocketTimeoutException if timeout expires before connecting
+     * @throws  java.nio.channels.IllegalBlockingModeException
+     *          if this socket has an associated channel,
+     *          and the channel is in non-blocking mode
+     * @throws  IllegalArgumentException if endpoint is null or is a
+     *          SocketAddress subclass not supported by this socket
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public void connect(SocketAddress endpoint, int timeout) throws IOException {
+        if (endpoint == null)
+            throw new IllegalArgumentException("connect: The address can't be null");
+
+        if (timeout < 0)
+          throw new IllegalArgumentException("connect: timeout can't be negative");
+
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+
+        if (!oldImpl && isConnected())
+            throw new SocketException("already connected");
+
+        if (!(endpoint instanceof InetSocketAddress))
+            throw new IllegalArgumentException("Unsupported address type");
+
+        InetSocketAddress epoint = (InetSocketAddress) endpoint;
+        InetAddress addr = epoint.getAddress ();
+        int port = epoint.getPort();
+        checkAddress(addr, "connect");
+
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            if (epoint.isUnresolved())
+                security.checkConnect(epoint.getHostName(), port);
+            else
+                security.checkConnect(addr.getHostAddress(), port);
+        }
+        if (!created)
+            createImpl(true);
+        if (!oldImpl)
+            impl.connect(epoint, timeout);
+        else if (timeout == 0) {
+            if (epoint.isUnresolved())
+                impl.connect(addr.getHostName(), port);
+            else
+                impl.connect(addr, port);
+        } else
+            throw new UnsupportedOperationException("SocketImpl.connect(addr, timeout)");
+        connected = true;
+        /*
+         * If the socket was not bound before the connect, it is now because
+         * the kernel will have picked an ephemeral port & a local address
+         */
+        bound = true;
+    }
+
+    /**
+     * Binds the socket to a local address.
+     * <P>
+     * If the address is {@code null}, then the system will pick up
+     * an ephemeral port and a valid local address to bind the socket.
+     *
+     * @param   bindpoint the {@code SocketAddress} to bind to
+     * @throws  IOException if the bind operation fails, or if the socket
+     *                     is already bound.
+     * @throws  IllegalArgumentException if bindpoint is a
+     *          SocketAddress subclass not supported by this socket
+     * @throws  SecurityException  if a security manager exists and its
+     *          {@code checkListen} method doesn't allow the bind
+     *          to the local port.
+     *
+     * @since   1.4
+     * @see #isBound
+     */
+    public void bind(SocketAddress bindpoint) throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (!oldImpl && isBound())
+            throw new SocketException("Already bound");
+
+        if (bindpoint != null && (!(bindpoint instanceof InetSocketAddress)))
+            throw new IllegalArgumentException("Unsupported address type");
+        InetSocketAddress epoint = (InetSocketAddress) bindpoint;
+        if (epoint != null && epoint.isUnresolved())
+            throw new SocketException("Unresolved address");
+        if (epoint == null) {
+            epoint = new InetSocketAddress(0);
+        }
+        InetAddress addr = epoint.getAddress();
+        int port = epoint.getPort();
+        checkAddress (addr, "bind");
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkListen(port);
+        }
+        getImpl().bind (addr, port);
+        bound = true;
+    }
+
+    private void checkAddress (InetAddress addr, String op) {
+        if (addr == null) {
+            return;
+        }
+        if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) {
+            throw new IllegalArgumentException(op + ": invalid address type");
+        }
+    }
+
+    /**
+     * set the flags after an accept() call.
+     */
+    final void postAccept() {
+        connected = true;
+        created = true;
+        bound = true;
+    }
+
+    void setCreated() {
+        created = true;
+    }
+
+    void setBound() {
+        bound = true;
+    }
+
+    void setConnected() {
+        connected = true;
+    }
+
+    /**
+     * Returns the address to which the socket is connected.
+     * <p>
+     * If the socket was connected prior to being {@link #close closed},
+     * then this method will continue to return the connected address
+     * after the socket is closed.
+     *
+     * @return  the remote IP address to which this socket is connected,
+     *          or {@code null} if the socket is not connected.
+     */
+    public InetAddress getInetAddress() {
+        if (!isConnected())
+            return null;
+        try {
+            return getImpl().getInetAddress();
+        } catch (SocketException e) {
+        }
+        return null;
+    }
+
+    /**
+     * Gets the local address to which the socket is bound.
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * the {@link InetAddress#getLoopbackAddress loopback} address is returned.
+     *
+     * @return the local address to which the socket is bound,
+     *         the loopback address if denied by the security manager, or
+     *         the wildcard address if the socket is closed or not bound yet.
+     * @since   JDK1.1
+     *
+     * @see SecurityManager#checkConnect
+     */
+    public InetAddress getLocalAddress() {
+        // This is for backward compatibility
+        if (!isBound())
+            return InetAddress.anyLocalAddress();
+        InetAddress in = null;
+        try {
+            in = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null)
+                sm.checkConnect(in.getHostAddress(), -1);
+            if (in.isAnyLocalAddress()) {
+                in = InetAddress.anyLocalAddress();
+            }
+        } catch (SecurityException e) {
+            in = InetAddress.getLoopbackAddress();
+        } catch (Exception e) {
+            in = InetAddress.anyLocalAddress(); // "0.0.0.0"
+        }
+        return in;
+    }
+
+    /**
+     * Returns the remote port number to which this socket is connected.
+     * <p>
+     * If the socket was connected prior to being {@link #close closed},
+     * then this method will continue to return the connected port number
+     * after the socket is closed.
+     *
+     * @return  the remote port number to which this socket is connected, or
+     *          0 if the socket is not connected yet.
+     */
+    public int getPort() {
+        if (!isConnected())
+            return 0;
+        try {
+            return getImpl().getPort();
+        } catch (SocketException e) {
+            // Shouldn't happen as we're connected
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the local port number to which this socket is bound.
+     * <p>
+     * If the socket was bound prior to being {@link #close closed},
+     * then this method will continue to return the local port number
+     * after the socket is closed.
+     *
+     * @return  the local port number to which this socket is bound or -1
+     *          if the socket is not bound yet.
+     */
+    public int getLocalPort() {
+        if (!isBound())
+            return -1;
+        try {
+            return getImpl().getLocalPort();
+        } catch(SocketException e) {
+            // shouldn't happen as we're bound
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the address of the endpoint this socket is connected to, or
+     * {@code null} if it is unconnected.
+     * <p>
+     * If the socket was connected prior to being {@link #close closed},
+     * then this method will continue to return the connected address
+     * after the socket is closed.
+     *
+
+     * @return a {@code SocketAddress} representing the remote endpoint of this
+     *         socket, or {@code null} if it is not connected yet.
+     * @see #getInetAddress()
+     * @see #getPort()
+     * @see #connect(SocketAddress, int)
+     * @see #connect(SocketAddress)
+     * @since 1.4
+     */
+    public SocketAddress getRemoteSocketAddress() {
+        if (!isConnected())
+            return null;
+        return new InetSocketAddress(getInetAddress(), getPort());
+    }
+
+    /**
+     * Returns the address of the endpoint this socket is bound to.
+     * <p>
+     * If a socket bound to an endpoint represented by an
+     * {@code InetSocketAddress } is {@link #close closed},
+     * then this method will continue to return an {@code InetSocketAddress}
+     * after the socket is closed. In that case the returned
+     * {@code InetSocketAddress}'s address is the
+     * {@link InetAddress#isAnyLocalAddress wildcard} address
+     * and its port is the local port that it was bound to.
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * a {@code SocketAddress} representing the
+     * {@link InetAddress#getLoopbackAddress loopback} address and the local
+     * port to which this socket is bound is returned.
+     *
+     * @return a {@code SocketAddress} representing the local endpoint of
+     *         this socket, or a {@code SocketAddress} representing the
+     *         loopback address if denied by the security manager, or
+     *         {@code null} if the socket is not bound yet.
+     *
+     * @see #getLocalAddress()
+     * @see #getLocalPort()
+     * @see #bind(SocketAddress)
+     * @see SecurityManager#checkConnect
+     * @since 1.4
+     */
+
+    public SocketAddress getLocalSocketAddress() {
+        if (!isBound())
+            return null;
+        return new InetSocketAddress(getLocalAddress(), getLocalPort());
+    }
+
+    /**
+     * Returns the unique {@link java.nio.channels.SocketChannel SocketChannel}
+     * object associated with this socket, if any.
+     *
+     * <p> A socket will have a channel if, and only if, the channel itself was
+     * created via the {@link java.nio.channels.SocketChannel#open
+     * SocketChannel.open} or {@link
+     * java.nio.channels.ServerSocketChannel#accept ServerSocketChannel.accept}
+     * methods.
+     *
+     * @return  the socket channel associated with this socket,
+     *          or {@code null} if this socket was not created
+     *          for a channel
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public SocketChannel getChannel() {
+        return null;
+    }
+
+    /**
+     * Returns an input stream for this socket.
+     *
+     * <p> If this socket has an associated channel then the resulting input
+     * stream delegates all of its operations to the channel.  If the channel
+     * is in non-blocking mode then the input stream's {@code read} operations
+     * will throw an {@link java.nio.channels.IllegalBlockingModeException}.
+     *
+     * <p>Under abnormal conditions the underlying connection may be
+     * broken by the remote host or the network software (for example
+     * a connection reset in the case of TCP connections). When a
+     * broken connection is detected by the network software the
+     * following applies to the returned input stream :-
+     *
+     * <ul>
+     *
+     *   <li><p>The network software may discard bytes that are buffered
+     *   by the socket. Bytes that aren't discarded by the network
+     *   software can be read using {@link java.io.InputStream#read read}.
+     *
+     *   <li><p>If there are no bytes buffered on the socket, or all
+     *   buffered bytes have been consumed by
+     *   {@link java.io.InputStream#read read}, then all subsequent
+     *   calls to {@link java.io.InputStream#read read} will throw an
+     *   {@link java.io.IOException IOException}.
+     *
+     *   <li><p>If there are no bytes buffered on the socket, and the
+     *   socket has not been closed using {@link #close close}, then
+     *   {@link java.io.InputStream#available available} will
+     *   return {@code 0}.
+     *
+     * </ul>
+     *
+     * <p> Closing the returned {@link java.io.InputStream InputStream}
+     * will close the associated socket.
+     *
+     * @return     an input stream for reading bytes from this socket.
+     * @exception  IOException  if an I/O error occurs when creating the
+     *             input stream, the socket is closed, the socket is
+     *             not connected, or the socket input has been shutdown
+     *             using {@link #shutdownInput()}
+     *
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public InputStream getInputStream() throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (!isConnected())
+            throw new SocketException("Socket is not connected");
+        if (isInputShutdown())
+            throw new SocketException("Socket input is shutdown");
+        final Socket s = this;
+        InputStream is = null;
+        try {
+            is = AccessController.doPrivileged(
+                new PrivilegedExceptionAction<InputStream>() {
+                    public InputStream run() throws IOException {
+                        return impl.getInputStream();
+                    }
+                });
+        } catch (java.security.PrivilegedActionException e) {
+            throw (IOException) e.getException();
+        }
+        return is;
+    }
+
+    /**
+     * Returns an output stream for this socket.
+     *
+     * <p> If this socket has an associated channel then the resulting output
+     * stream delegates all of its operations to the channel.  If the channel
+     * is in non-blocking mode then the output stream's {@code write}
+     * operations will throw an {@link
+     * java.nio.channels.IllegalBlockingModeException}.
+     *
+     * <p> Closing the returned {@link java.io.OutputStream OutputStream}
+     * will close the associated socket.
+     *
+     * @return     an output stream for writing bytes to this socket.
+     * @exception  IOException  if an I/O error occurs when creating the
+     *               output stream or if the socket is not connected.
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public OutputStream getOutputStream() throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (!isConnected())
+            throw new SocketException("Socket is not connected");
+        if (isOutputShutdown())
+            throw new SocketException("Socket output is shutdown");
+        final Socket s = this;
+        OutputStream os = null;
+        try {
+            os = AccessController.doPrivileged(
+                new PrivilegedExceptionAction<OutputStream>() {
+                    public OutputStream run() throws IOException {
+                        return impl.getOutputStream();
+                    }
+                });
+        } catch (java.security.PrivilegedActionException e) {
+            throw (IOException) e.getException();
+        }
+        return os;
+    }
+
+    /**
+     * Enable/disable {@link SocketOptions#TCP_NODELAY TCP_NODELAY}
+     * (disable/enable Nagle's algorithm).
+     *
+     * @param on {@code true} to enable TCP_NODELAY,
+     * {@code false} to disable.
+     *
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     *
+     * @since   JDK1.1
+     *
+     * @see #getTcpNoDelay()
+     */
+    public void setTcpNoDelay(boolean on) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on));
+    }
+
+    /**
+     * Tests if {@link SocketOptions#TCP_NODELAY TCP_NODELAY} is enabled.
+     *
+     * @return a {@code boolean} indicating whether or not
+     *         {@link SocketOptions#TCP_NODELAY TCP_NODELAY} is enabled.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @since   JDK1.1
+     * @see #setTcpNoDelay(boolean)
+     */
+    public boolean getTcpNoDelay() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        return ((Boolean) getImpl().getOption(SocketOptions.TCP_NODELAY)).booleanValue();
+    }
+
+    /**
+     * Enable/disable {@link SocketOptions#SO_LINGER SO_LINGER} with the
+     * specified linger time in seconds. The maximum timeout value is platform
+     * specific.
+     *
+     * The setting only affects socket close.
+     *
+     * @param on     whether or not to linger on.
+     * @param linger how long to linger for, if on is true.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @exception IllegalArgumentException if the linger value is negative.
+     * @since JDK1.1
+     * @see #getSoLinger()
+     */
+    public void setSoLinger(boolean on, int linger) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (!on) {
+            getImpl().setOption(SocketOptions.SO_LINGER, new Boolean(on));
+        } else {
+            if (linger < 0) {
+                throw new IllegalArgumentException("invalid value for SO_LINGER");
+            }
+            if (linger > 65535)
+                linger = 65535;
+            getImpl().setOption(SocketOptions.SO_LINGER, new Integer(linger));
+        }
+    }
+
+    /**
+     * Returns setting for {@link SocketOptions#SO_LINGER SO_LINGER}.
+     * -1 returns implies that the
+     * option is disabled.
+     *
+     * The setting only affects socket close.
+     *
+     * @return the setting for {@link SocketOptions#SO_LINGER SO_LINGER}.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @since   JDK1.1
+     * @see #setSoLinger(boolean, int)
+     */
+    public int getSoLinger() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        Object o = getImpl().getOption(SocketOptions.SO_LINGER);
+        if (o instanceof Integer) {
+            return ((Integer) o).intValue();
+        } else {
+            return -1;
+        }
+    }
+
+    /**
+     * Send one byte of urgent data on the socket. The byte to be sent is the lowest eight
+     * bits of the data parameter. The urgent byte is
+     * sent after any preceding writes to the socket OutputStream
+     * and before any future writes to the OutputStream.
+     * @param data The byte of data to send
+     * @exception IOException if there is an error
+     *  sending the data.
+     * @since 1.4
+     */
+    public void sendUrgentData (int data) throws IOException  {
+        // Android-changed: If the socket is closed, sendUrgentData should not create a new impl.
+        // Fail early to avoid leaking resources.
+        // http://b/31818400
+        if (isClosed()) {
+            throw new SocketException("Socket is closed");
+        }
+
+        if (!getImpl().supportsUrgentData ()) {
+            throw new SocketException ("Urgent data not supported");
+        }
+        getImpl().sendUrgentData (data);
+    }
+
+    /**
+     * Enable/disable {@link SocketOptions#SO_OOBINLINE SO_OOBINLINE}
+     * (receipt of TCP urgent data)
+     *
+     * By default, this option is disabled and TCP urgent data received on a
+     * socket is silently discarded. If the user wishes to receive urgent data, then
+     * this option must be enabled. When enabled, urgent data is received
+     * inline with normal data.
+     * <p>
+     * Note, only limited support is provided for handling incoming urgent
+     * data. In particular, no notification of incoming urgent data is provided
+     * and there is no capability to distinguish between normal data and urgent
+     * data unless provided by a higher level protocol.
+     *
+     * @param on {@code true} to enable
+     *           {@link SocketOptions#SO_OOBINLINE SO_OOBINLINE},
+     *           {@code false} to disable.
+     *
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     *
+     * @since   1.4
+     *
+     * @see #getOOBInline()
+     */
+    public void setOOBInline(boolean on) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_OOBINLINE, Boolean.valueOf(on));
+    }
+
+    /**
+     * Tests if {@link SocketOptions#SO_OOBINLINE SO_OOBINLINE} is enabled.
+     *
+     * @return a {@code boolean} indicating whether or not
+     *         {@link SocketOptions#SO_OOBINLINE SO_OOBINLINE}is enabled.
+     *
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @since   1.4
+     * @see #setOOBInline(boolean)
+     */
+    public boolean getOOBInline() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        return ((Boolean) getImpl().getOption(SocketOptions.SO_OOBINLINE)).booleanValue();
+    }
+
+    /**
+     *  Enable/disable {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT}
+     *  with the specified timeout, in milliseconds. With this option set
+     *  to a non-zero timeout, a read() call on the InputStream associated with
+     *  this Socket will block for only this amount of time.  If the timeout
+     *  expires, a <B>java.net.SocketTimeoutException</B> is raised, though the
+     *  Socket is still valid. The option <B>must</B> be enabled
+     *  prior to entering the blocking operation to have effect. The
+     *  timeout must be {@code > 0}.
+     *  A timeout of zero is interpreted as an infinite timeout.
+     *
+     * @param timeout the specified timeout, in milliseconds.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @since   JDK 1.1
+     * @see #getSoTimeout()
+     */
+    public synchronized void setSoTimeout(int timeout) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (timeout < 0)
+          throw new IllegalArgumentException("timeout can't be negative");
+
+        getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
+    }
+
+    /**
+     * Returns setting for {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT}.
+     * 0 returns implies that the option is disabled (i.e., timeout of infinity).
+     *
+     * @return the setting for {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT}
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     *
+     * @since   JDK1.1
+     * @see #setSoTimeout(int)
+     */
+    public synchronized int getSoTimeout() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
+        /* extra type safety */
+        if (o instanceof Integer) {
+            return ((Integer) o).intValue();
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Sets the {@link SocketOptions#SO_SNDBUF SO_SNDBUF} option to the
+     * specified value for this {@code Socket}.
+     * The {@link SocketOptions#SO_SNDBUF SO_SNDBUF} option is used by the
+     * platform's networking code as a hint for the size to set the underlying
+     * network I/O buffers.
+     *
+     * <p>Because {@link SocketOptions#SO_SNDBUF SO_SNDBUF} is a hint,
+     * applications that want to verify what size the buffers were set to
+     * should call {@link #getSendBufferSize()}.
+     *
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     *
+     * @param size the size to which to set the send buffer
+     * size. This value must be greater than 0.
+     *
+     * @exception IllegalArgumentException if the
+     * value is 0 or is negative.
+     *
+     * @see #getSendBufferSize()
+     * @since 1.2
+     */
+    public synchronized void setSendBufferSize(int size)
+    throws SocketException{
+        if (!(size > 0)) {
+            throw new IllegalArgumentException("negative send size");
+        }
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_SNDBUF, new Integer(size));
+    }
+
+    /**
+     * Get value of the {@link SocketOptions#SO_SNDBUF SO_SNDBUF} option
+     * for this {@code Socket}, that is the buffer size used by the platform
+     * for output on this {@code Socket}.
+     * @return the value of the {@link SocketOptions#SO_SNDBUF SO_SNDBUF}
+     *         option for this {@code Socket}.
+     *
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     *
+     * @see #setSendBufferSize(int)
+     * @since 1.2
+     */
+    public synchronized int getSendBufferSize() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        int result = 0;
+        Object o = getImpl().getOption(SocketOptions.SO_SNDBUF);
+        if (o instanceof Integer) {
+            result = ((Integer)o).intValue();
+        }
+        return result;
+    }
+
+    /**
+     * Sets the {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option to the
+     * specified value for this {@code Socket}. The
+     * {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option is
+     * used by the platform's networking code as a hint for the size to set
+     * the underlying network I/O buffers.
+     *
+     * <p>Increasing the receive buffer size can increase the performance of
+     * network I/O for high-volume connection, while decreasing it can
+     * help reduce the backlog of incoming data.
+     *
+     * <p>Because {@link SocketOptions#SO_RCVBUF SO_RCVBUF} is a hint,
+     * applications that want to verify what size the buffers were set to
+     * should call {@link #getReceiveBufferSize()}.
+     *
+     * <p>The value of {@link SocketOptions#SO_RCVBUF SO_RCVBUF} is also used
+     * to set the TCP receive window that is advertized to the remote peer.
+     * Generally, the window size can be modified at any time when a socket is
+     * connected. However, if a receive window larger than 64K is required then
+     * this must be requested <B>before</B> the socket is connected to the
+     * remote peer. There are two cases to be aware of:
+     * <ol>
+     * <li>For sockets accepted from a ServerSocket, this must be done by calling
+     * {@link ServerSocket#setReceiveBufferSize(int)} before the ServerSocket
+     * is bound to a local address.<p></li>
+     * <li>For client sockets, setReceiveBufferSize() must be called before
+     * connecting the socket to its remote peer.</li></ol>
+     * @param size the size to which to set the receive buffer
+     * size. This value must be greater than 0.
+     *
+     * @exception IllegalArgumentException if the value is 0 or is
+     * negative.
+     *
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     *
+     * @see #getReceiveBufferSize()
+     * @see ServerSocket#setReceiveBufferSize(int)
+     * @since 1.2
+     */
+    public synchronized void setReceiveBufferSize(int size)
+    throws SocketException{
+        if (size <= 0) {
+            throw new IllegalArgumentException("invalid receive size");
+        }
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size));
+    }
+
+    /**
+     * Gets the value of the {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option
+     * for this {@code Socket}, that is the buffer size used by the platform
+     * for input on this {@code Socket}.
+     *
+     * @return the value of the {@link SocketOptions#SO_RCVBUF SO_RCVBUF}
+     *         option for this {@code Socket}.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @see #setReceiveBufferSize(int)
+     * @since 1.2
+     */
+    public synchronized int getReceiveBufferSize()
+    throws SocketException{
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        int result = 0;
+        Object o = getImpl().getOption(SocketOptions.SO_RCVBUF);
+        if (o instanceof Integer) {
+            result = ((Integer)o).intValue();
+        }
+        return result;
+    }
+
+    /**
+     * Enable/disable {@link SocketOptions#SO_KEEPALIVE SO_KEEPALIVE}.
+     *
+     * @param on  whether or not to have socket keep alive turned on.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @since 1.3
+     * @see #getKeepAlive()
+     */
+    public void setKeepAlive(boolean on) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_KEEPALIVE, Boolean.valueOf(on));
+    }
+
+    /**
+     * Tests if {@link SocketOptions#SO_KEEPALIVE SO_KEEPALIVE} is enabled.
+     *
+     * @return a {@code boolean} indicating whether or not
+     *         {@link SocketOptions#SO_KEEPALIVE SO_KEEPALIVE} is enabled.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @since   1.3
+     * @see #setKeepAlive(boolean)
+     */
+    public boolean getKeepAlive() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        return ((Boolean) getImpl().getOption(SocketOptions.SO_KEEPALIVE)).booleanValue();
+    }
+
+    /**
+     * Sets traffic class or type-of-service octet in the IP
+     * header for packets sent from this Socket.
+     * As the underlying network implementation may ignore this
+     * value applications should consider it a hint.
+     *
+     * <P> The tc <B>must</B> be in the range {@code 0 <= tc <=
+     * 255} or an IllegalArgumentException will be thrown.
+     * <p>Notes:
+     * <p>For Internet Protocol v4 the value consists of an
+     * {@code integer}, the least significant 8 bits of which
+     * represent the value of the TOS octet in IP packets sent by
+     * the socket.
+     * RFC 1349 defines the TOS values as follows:
+     *
+     * <UL>
+     * <LI><CODE>IPTOS_LOWCOST (0x02)</CODE></LI>
+     * <LI><CODE>IPTOS_RELIABILITY (0x04)</CODE></LI>
+     * <LI><CODE>IPTOS_THROUGHPUT (0x08)</CODE></LI>
+     * <LI><CODE>IPTOS_LOWDELAY (0x10)</CODE></LI>
+     * </UL>
+     * The last low order bit is always ignored as this
+     * corresponds to the MBZ (must be zero) bit.
+     * <p>
+     * Setting bits in the precedence field may result in a
+     * SocketException indicating that the operation is not
+     * permitted.
+     * <p>
+     * As RFC 1122 section 4.2.4.2 indicates, a compliant TCP
+     * implementation should, but is not required to, let application
+     * change the TOS field during the lifetime of a connection.
+     * So whether the type-of-service field can be changed after the
+     * TCP connection has been established depends on the implementation
+     * in the underlying platform. Applications should not assume that
+     * they can change the TOS field after the connection.
+     * <p>
+     * For Internet Protocol v6 {@code tc} is the value that
+     * would be placed into the sin6_flowinfo field of the IP header.
+     *
+     * @param tc        an {@code int} value for the bitset.
+     * @throws SocketException if there is an error setting the
+     * traffic class or type-of-service
+     * @since 1.4
+     * @see #getTrafficClass
+     * @see SocketOptions#IP_TOS
+     */
+    public void setTrafficClass(int tc) throws SocketException {
+        if (tc < 0 || tc > 255)
+            throw new IllegalArgumentException("tc is not in range 0 -- 255");
+
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        try {
+            getImpl().setOption(SocketOptions.IP_TOS, tc);
+        } catch (SocketException se) {
+            // not supported if socket already connected
+            // Solaris returns error in such cases
+            if(!isConnected())
+                throw se;
+        }
+    }
+
+    /**
+     * Gets traffic class or type-of-service in the IP header
+     * for packets sent from this Socket
+     * <p>
+     * As the underlying network implementation may ignore the
+     * traffic class or type-of-service set using {@link #setTrafficClass(int)}
+     * this method may return a different value than was previously
+     * set using the {@link #setTrafficClass(int)} method on this Socket.
+     *
+     * @return the traffic class or type-of-service already set
+     * @throws SocketException if there is an error obtaining the
+     * traffic class or type-of-service value.
+     * @since 1.4
+     * @see #setTrafficClass(int)
+     * @see SocketOptions#IP_TOS
+     */
+    public int getTrafficClass() throws SocketException {
+        // Android-changed: throw SocketException if the socket is already closed. http://b/31818400
+        if (isClosed()) {
+            throw new SocketException("Socket is closed");
+        }
+
+        return ((Integer) (getImpl().getOption(SocketOptions.IP_TOS))).intValue();
+    }
+
+    /**
+     * Enable/disable the {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR}
+     * socket option.
+     * <p>
+     * When a TCP connection is closed the connection may remain
+     * in a timeout state for a period of time after the connection
+     * is closed (typically known as the {@code TIME_WAIT} state
+     * or {@code 2MSL} wait state).
+     * For applications using a well known socket address or port
+     * it may not be possible to bind a socket to the required
+     * {@code SocketAddress} if there is a connection in the
+     * timeout state involving the socket address or port.
+     * <p>
+     * Enabling {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR}
+     * prior to binding the socket using {@link #bind(SocketAddress)} allows
+     * the socket to be bound even though a previous connection is in a timeout
+     * state.
+     * <p>
+     * When a {@code Socket} is created the initial setting
+     * of {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is disabled.
+     * <p>
+     * The behaviour when {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is
+     * enabled or disabled after a socket is bound (See {@link #isBound()})
+     * is not defined.
+     *
+     * @param on  whether to enable or disable the socket option
+     * @exception SocketException if an error occurs enabling or
+     *            disabling the {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR}
+     *            socket option, or the socket is closed.
+     * @since 1.4
+     * @see #getReuseAddress()
+     * @see #bind(SocketAddress)
+     * @see #isClosed()
+     * @see #isBound()
+     */
+    public void setReuseAddress(boolean on) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on));
+    }
+
+    /**
+     * Tests if {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is enabled.
+     *
+     * @return a {@code boolean} indicating whether or not
+     *         {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is enabled.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @since   1.4
+     * @see #setReuseAddress(boolean)
+     */
+    public boolean getReuseAddress() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        return ((Boolean) (getImpl().getOption(SocketOptions.SO_REUSEADDR))).booleanValue();
+    }
+
+    /**
+     * Closes this socket.
+     * <p>
+     * Any thread currently blocked in an I/O operation upon this socket
+     * will throw a {@link SocketException}.
+     * <p>
+     * Once a socket has been closed, it is not available for further networking
+     * use (i.e. can't be reconnected or rebound). A new socket needs to be
+     * created.
+     *
+     * <p> Closing this socket will also close the socket's
+     * {@link java.io.InputStream InputStream} and
+     * {@link java.io.OutputStream OutputStream}.
+     *
+     * <p> If this socket has an associated channel then the channel is closed
+     * as well.
+     *
+     * @exception  IOException  if an I/O error occurs when closing this socket.
+     * @revised 1.4
+     * @spec JSR-51
+     * @see #isClosed
+     */
+    public synchronized void close() throws IOException {
+        synchronized(closeLock) {
+            if (isClosed())
+                return;
+            if (created)
+                impl.close();
+            closed = true;
+        }
+    }
+
+    /**
+     * Places the input stream for this socket at "end of stream".
+     * Any data sent to the input stream side of the socket is acknowledged
+     * and then silently discarded.
+     * <p>
+     * If you read from a socket input stream after invoking this method on the
+     * socket, the stream's {@code available} method will return 0, and its
+     * {@code read} methods will return {@code -1} (end of stream).
+     *
+     * @exception IOException if an I/O error occurs when shutting down this
+     * socket.
+     *
+     * @since 1.3
+     * @see java.net.Socket#shutdownOutput()
+     * @see java.net.Socket#close()
+     * @see java.net.Socket#setSoLinger(boolean, int)
+     * @see #isInputShutdown
+     */
+    public void shutdownInput() throws IOException
+    {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (!isConnected())
+            throw new SocketException("Socket is not connected");
+        if (isInputShutdown())
+            throw new SocketException("Socket input is already shutdown");
+        getImpl().shutdownInput();
+        shutIn = true;
+    }
+
+    /**
+     * Disables the output stream for this socket.
+     * For a TCP socket, any previously written data will be sent
+     * followed by TCP's normal connection termination sequence.
+     *
+     * If you write to a socket output stream after invoking
+     * shutdownOutput() on the socket, the stream will throw
+     * an IOException.
+     *
+     * @exception IOException if an I/O error occurs when shutting down this
+     * socket.
+     *
+     * @since 1.3
+     * @see java.net.Socket#shutdownInput()
+     * @see java.net.Socket#close()
+     * @see java.net.Socket#setSoLinger(boolean, int)
+     * @see #isOutputShutdown
+     */
+    public void shutdownOutput() throws IOException
+    {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (!isConnected())
+            throw new SocketException("Socket is not connected");
+        if (isOutputShutdown())
+            throw new SocketException("Socket output is already shutdown");
+        getImpl().shutdownOutput();
+        shutOut = true;
+    }
+
+    /**
+     * Converts this socket to a {@code String}.
+     *
+     * @return  a string representation of this socket.
+     */
+    public String toString() {
+        try {
+            // Android-changed: change localport to localPort, and addr to address.
+            if (isConnected())
+                return "Socket[address=" + getImpl().getInetAddress() +
+                    ",port=" + getImpl().getPort() +
+                    ",localPort=" + getImpl().getLocalPort() + "]";
+        } catch (SocketException e) {
+        }
+        return "Socket[unconnected]";
+    }
+
+    /**
+     * Returns the connection state of the socket.
+     * <p>
+     * Note: Closing a socket doesn't clear its connection state, which means
+     * this method will return {@code true} for a closed socket
+     * (see {@link #isClosed()}) if it was successfuly connected prior
+     * to being closed.
+     *
+     * @return true if the socket was successfuly connected to a server
+     * @since 1.4
+     */
+    public boolean isConnected() {
+        // Before 1.3 Sockets were always connected during creation
+        return connected || oldImpl;
+    }
+
+    /**
+     * Returns the binding state of the socket.
+     * <p>
+     * Note: Closing a socket doesn't clear its binding state, which means
+     * this method will return {@code true} for a closed socket
+     * (see {@link #isClosed()}) if it was successfuly bound prior
+     * to being closed.
+     *
+     * @return true if the socket was successfuly bound to an address
+     * @since 1.4
+     * @see #bind
+     */
+    public boolean isBound() {
+        // Before 1.3 Sockets were always bound during creation
+        return bound || oldImpl;
+    }
+
+    /**
+     * Returns the closed state of the socket.
+     *
+     * @return true if the socket has been closed
+     * @since 1.4
+     * @see #close
+     */
+    public boolean isClosed() {
+        synchronized(closeLock) {
+            return closed;
+        }
+    }
+
+    /**
+     * Returns whether the read-half of the socket connection is closed.
+     *
+     * @return true if the input of the socket has been shutdown
+     * @since 1.4
+     * @see #shutdownInput
+     */
+    public boolean isInputShutdown() {
+        return shutIn;
+    }
+
+    /**
+     * Returns whether the write-half of the socket connection is closed.
+     *
+     * @return true if the output of the socket has been shutdown
+     * @since 1.4
+     * @see #shutdownOutput
+     */
+    public boolean isOutputShutdown() {
+        return shutOut;
+    }
+
+    /**
+     * The factory for all client sockets.
+     */
+    private static SocketImplFactory factory = null;
+
+    /**
+     * Sets the client socket implementation factory for the
+     * application. The factory can be specified only once.
+     * <p>
+     * When an application creates a new client socket, the socket
+     * implementation factory's {@code createSocketImpl} method is
+     * called to create the actual socket implementation.
+     * <p>
+     * Passing {@code null} to the method is a no-op unless the factory
+     * was already set.
+     * <p>If there is a security manager, this method first calls
+     * the security manager's {@code checkSetFactory} method
+     * to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param      fac   the desired factory.
+     * @exception  IOException  if an I/O error occurs when setting the
+     *               socket factory.
+     * @exception  SocketException  if the factory is already defined.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkSetFactory} method doesn't allow the operation.
+     * @see        java.net.SocketImplFactory#createSocketImpl()
+     * @see        SecurityManager#checkSetFactory
+     */
+    public static synchronized void setSocketImplFactory(SocketImplFactory fac)
+        throws IOException
+    {
+        if (factory != null) {
+            throw new SocketException("factory already defined");
+        }
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkSetFactory();
+        }
+        factory = fac;
+    }
+
+    /**
+     * Sets performance preferences for this socket.
+     *
+     * <p> Sockets use the TCP/IP protocol by default.  Some implementations
+     * may offer alternative protocols which have different performance
+     * characteristics than TCP/IP.  This method allows the application to
+     * express its own preferences as to how these tradeoffs should be made
+     * when the implementation chooses from the available protocols.
+     *
+     * <p> Performance preferences are described by three integers
+     * whose values indicate the relative importance of short connection time,
+     * low latency, and high bandwidth.  The absolute values of the integers
+     * are irrelevant; in order to choose a protocol the values are simply
+     * compared, with larger values indicating stronger preferences. Negative
+     * values represent a lower priority than positive values. If the
+     * application prefers short connection time over both low latency and high
+     * bandwidth, for example, then it could invoke this method with the values
+     * {@code (1, 0, 0)}.  If the application prefers high bandwidth above low
+     * latency, and low latency above short connection time, then it could
+     * invoke this method with the values {@code (0, 1, 2)}.
+     *
+     * <p> Invoking this method after this socket has been connected
+     * will have no effect.
+     *
+     * @param  connectionTime
+     *         An {@code int} expressing the relative importance of a short
+     *         connection time
+     *
+     * @param  latency
+     *         An {@code int} expressing the relative importance of low
+     *         latency
+     *
+     * @param  bandwidth
+     *         An {@code int} expressing the relative importance of high
+     *         bandwidth
+     *
+     * @since 1.5
+     */
+    public void setPerformancePreferences(int connectionTime,
+                                          int latency,
+                                          int bandwidth)
+    {
+        /* Not implemented yet */
+    }
+
+    // Android-added: getFileDescriptor$() method for testing and internal use.
+    /**
+     * @hide internal use only
+     */
+    public FileDescriptor getFileDescriptor$() {
+        return impl.getFileDescriptor();
+    }
+}
diff --git a/java/net/SocketAddress.java b/java/net/SocketAddress.java
new file mode 100644
index 0000000..cfb014b
--- /dev/null
+++ b/java/net/SocketAddress.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+
+
+/**
+ *
+ * This class represents a Socket Address with no protocol attachment.
+ * As an abstract class, it is meant to be subclassed with a specific,
+ * protocol dependent, implementation.
+ * <p>
+ * It provides an immutable object used by sockets for binding, connecting, or
+ * as returned values.
+ *
+ * @see java.net.Socket
+ * @see java.net.ServerSocket
+ * @since 1.4
+ */
+public abstract class SocketAddress implements java.io.Serializable {
+
+    static final long serialVersionUID = 5215720748342549866L;
+
+}
diff --git a/java/net/SocketException.java b/java/net/SocketException.java
new file mode 100644
index 0000000..64ae771
--- /dev/null
+++ b/java/net/SocketException.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * Thrown to indicate that there is an error creating or accessing a Socket.
+ *
+ * @author  Jonathan Payne
+ * @since   JDK1.0
+ */
+public
+class SocketException extends IOException {
+    private static final long serialVersionUID = -5935874303556886934L;
+
+    /**
+     * Constructs a new {@code SocketException} with the
+     * specified detail message.
+     *
+     * @param msg the detail message.
+     */
+    public SocketException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new {@code SocketException} with no detail message.
+     */
+    public SocketException() {
+    }
+
+    // BEGIN Android-added: SocketException ctor with cause for internal use.
+    /** @hide */
+    public SocketException(Throwable cause) {
+        super(cause);
+    }
+
+    /** @hide */
+    public SocketException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+    // END Android-added: SocketException ctor with cause for internal use.
+}
diff --git a/java/net/SocketImpl.annotated.java b/java/net/SocketImpl.annotated.java
new file mode 100644
index 0000000..2146d2f
--- /dev/null
+++ b/java/net/SocketImpl.annotated.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.net;
+
+import java.io.IOException;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class SocketImpl implements java.net.SocketOptions {
+
+public SocketImpl() { throw new RuntimeException("Stub!"); }
+
+protected abstract void create(boolean stream) throws java.io.IOException;
+
+protected abstract void connect(java.lang.String host, int port) throws java.io.IOException;
+
+protected abstract void connect(java.net.InetAddress address, int port) throws java.io.IOException;
+
+protected abstract void connect(java.net.SocketAddress address, int timeout) throws java.io.IOException;
+
+protected abstract void bind(java.net.InetAddress host, int port) throws java.io.IOException;
+
+protected abstract void listen(int backlog) throws java.io.IOException;
+
+protected abstract void accept(java.net.SocketImpl s) throws java.io.IOException;
+
+protected abstract java.io.InputStream getInputStream() throws java.io.IOException;
+
+protected abstract java.io.OutputStream getOutputStream() throws java.io.IOException;
+
+protected abstract int available() throws java.io.IOException;
+
+protected abstract void close() throws java.io.IOException;
+
+protected void shutdownInput() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+protected void shutdownOutput() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+protected java.io.FileDescriptor getFileDescriptor() { throw new RuntimeException("Stub!"); }
+
[email protected]
+public java.io.FileDescriptor getFD$() { throw new RuntimeException("Stub!"); }
+
+protected java.net.InetAddress getInetAddress() { throw new RuntimeException("Stub!"); }
+
+protected int getPort() { throw new RuntimeException("Stub!"); }
+
+protected boolean supportsUrgentData() { throw new RuntimeException("Stub!"); }
+
+protected abstract void sendUrgentData(int data) throws java.io.IOException;
+
+protected int getLocalPort() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+protected void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { throw new RuntimeException("Stub!"); }
+
+protected java.net.InetAddress address;
+
+protected java.io.FileDescriptor fd;
+
+protected int localport;
+
+protected int port;
+}
+
diff --git a/java/net/SocketImpl.java b/java/net/SocketImpl.java
new file mode 100644
index 0000000..ade2630
--- /dev/null
+++ b/java/net/SocketImpl.java
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileDescriptor;
+
+/**
+ * The abstract class {@code SocketImpl} is a common superclass
+ * of all classes that actually implement sockets. It is used to
+ * create both client and server sockets.
+ * <p>
+ * A "plain" socket implements these methods exactly as
+ * described, without attempting to go through a firewall or proxy.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public abstract class SocketImpl implements SocketOptions {
+    /**
+     * The actual Socket object.
+     */
+    Socket socket = null;
+    ServerSocket serverSocket = null;
+
+    /**
+     * The file descriptor object for this socket.
+     */
+    protected FileDescriptor fd;
+
+    /**
+     * The IP address of the remote end of this socket.
+     */
+    protected InetAddress address;
+
+    /**
+     * The port number on the remote host to which this socket is connected.
+     */
+    protected int port;
+
+    /**
+     * The local port number to which this socket is connected.
+     */
+    protected int localport;
+
+    /**
+     * Creates either a stream or a datagram socket.
+     *
+     * @param      stream   if {@code true}, create a stream socket;
+     *                      otherwise, create a datagram socket.
+     * @exception  IOException  if an I/O error occurs while creating the
+     *               socket.
+     */
+    protected abstract void create(boolean stream) throws IOException;
+
+    /**
+     * Connects this socket to the specified port on the named host.
+     *
+     * @param      host   the name of the remote host.
+     * @param      port   the port number.
+     * @exception  IOException  if an I/O error occurs when connecting to the
+     *               remote host.
+     */
+    protected abstract void connect(String host, int port) throws IOException;
+
+    /**
+     * Connects this socket to the specified port number on the specified host.
+     *
+     * @param      address   the IP address of the remote host.
+     * @param      port      the port number.
+     * @exception  IOException  if an I/O error occurs when attempting a
+     *               connection.
+     */
+    protected abstract void connect(InetAddress address, int port) throws IOException;
+
+    /**
+     * Connects this socket to the specified port number on the specified host.
+     * A timeout of zero is interpreted as an infinite timeout. The connection
+     * will then block until established or an error occurs.
+     *
+     * @param      address   the Socket address of the remote host.
+     * @param     timeout  the timeout value, in milliseconds, or zero for no timeout.
+     * @exception  IOException  if an I/O error occurs when attempting a
+     *               connection.
+     * @since 1.4
+     */
+    protected abstract void connect(SocketAddress address, int timeout) throws IOException;
+
+    /**
+     * Binds this socket to the specified local IP address and port number.
+     *
+     * @param      host   an IP address that belongs to a local interface.
+     * @param      port   the port number.
+     * @exception  IOException  if an I/O error occurs when binding this socket.
+     */
+    protected abstract void bind(InetAddress host, int port) throws IOException;
+
+    /**
+     * Sets the maximum queue length for incoming connection indications
+     * (a request to connect) to the {@code count} argument. If a
+     * connection indication arrives when the queue is full, the
+     * connection is refused.
+     *
+     * @param      backlog   the maximum length of the queue.
+     * @exception  IOException  if an I/O error occurs when creating the queue.
+     */
+    protected abstract void listen(int backlog) throws IOException;
+
+    /**
+     * Accepts a connection.
+     *
+     * @param      s   the accepted connection.
+     * @exception  IOException  if an I/O error occurs when accepting the
+     *               connection.
+     */
+    protected abstract void accept(SocketImpl s) throws IOException;
+
+    /**
+     * Returns an input stream for this socket.
+     *
+     * @return     a stream for reading from this socket.
+     * @exception  IOException  if an I/O error occurs when creating the
+     *               input stream.
+    */
+    protected abstract InputStream getInputStream() throws IOException;
+
+    /**
+     * Returns an output stream for this socket.
+     *
+     * @return     an output stream for writing to this socket.
+     * @exception  IOException  if an I/O error occurs when creating the
+     *               output stream.
+     */
+    protected abstract OutputStream getOutputStream() throws IOException;
+
+    /**
+     * Returns the number of bytes that can be read from this socket
+     * without blocking.
+     *
+     * @return     the number of bytes that can be read from this socket
+     *             without blocking.
+     * @exception  IOException  if an I/O error occurs when determining the
+     *               number of bytes available.
+     */
+    protected abstract int available() throws IOException;
+
+    /**
+     * Closes this socket.
+     *
+     * @exception  IOException  if an I/O error occurs when closing this socket.
+     */
+    protected abstract void close() throws IOException;
+
+    /**
+     * Places the input stream for this socket at "end of stream".
+     * Any data sent to this socket is acknowledged and then
+     * silently discarded.
+     *
+     * If you read from a socket input stream after invoking this method on the
+     * socket, the stream's {@code available} method will return 0, and its
+     * {@code read} methods will return {@code -1} (end of stream).
+     *
+     * @exception IOException if an I/O error occurs when shutting down this
+     * socket.
+     * @see java.net.Socket#shutdownOutput()
+     * @see java.net.Socket#close()
+     * @see java.net.Socket#setSoLinger(boolean, int)
+     * @since 1.3
+     */
+    protected void shutdownInput() throws IOException {
+      throw new IOException("Method not implemented!");
+    }
+
+    /**
+     * Disables the output stream for this socket.
+     * For a TCP socket, any previously written data will be sent
+     * followed by TCP's normal connection termination sequence.
+     *
+     * If you write to a socket output stream after invoking
+     * shutdownOutput() on the socket, the stream will throw
+     * an IOException.
+     *
+     * @exception IOException if an I/O error occurs when shutting down this
+     * socket.
+     * @see java.net.Socket#shutdownInput()
+     * @see java.net.Socket#close()
+     * @see java.net.Socket#setSoLinger(boolean, int)
+     * @since 1.3
+     */
+    protected void shutdownOutput() throws IOException {
+      throw new IOException("Method not implemented!");
+    }
+
+    /**
+     * Returns the value of this socket's {@code fd} field.
+     *
+     * @return  the value of this socket's {@code fd} field.
+     * @see     java.net.SocketImpl#fd
+     */
+    protected FileDescriptor getFileDescriptor() {
+        return fd;
+    }
+
+    // Android-added: getFD$() for testing.
+    /**
+     * @hide used by java.nio tests
+     */
+    public FileDescriptor getFD$() {
+        return fd;
+    }
+
+    /**
+     * Returns the value of this socket's {@code address} field.
+     *
+     * @return  the value of this socket's {@code address} field.
+     * @see     java.net.SocketImpl#address
+     */
+    protected InetAddress getInetAddress() {
+        return address;
+    }
+
+    /**
+     * Returns the value of this socket's {@code port} field.
+     *
+     * @return  the value of this socket's {@code port} field.
+     * @see     java.net.SocketImpl#port
+     */
+    protected int getPort() {
+        return port;
+    }
+
+    /**
+     * Returns whether or not this SocketImpl supports sending
+     * urgent data. By default, false is returned
+     * unless the method is overridden in a sub-class
+     *
+     * @return  true if urgent data supported
+     * @see     java.net.SocketImpl#address
+     * @since 1.4
+     */
+    protected boolean supportsUrgentData () {
+        return false; // must be overridden in sub-class
+    }
+
+    /**
+     * Send one byte of urgent data on the socket.
+     * The byte to be sent is the low eight bits of the parameter
+     * @param data The byte of data to send
+     * @exception IOException if there is an error
+     *  sending the data.
+     * @since 1.4
+     */
+    protected abstract void sendUrgentData (int data) throws IOException;
+
+    /**
+     * Returns the value of this socket's {@code localport} field.
+     *
+     * @return  the value of this socket's {@code localport} field.
+     * @see     java.net.SocketImpl#localport
+     */
+    protected int getLocalPort() {
+        return localport;
+    }
+
+    void setSocket(Socket soc) {
+        this.socket = soc;
+    }
+
+    Socket getSocket() {
+        return socket;
+    }
+
+    void setServerSocket(ServerSocket soc) {
+        this.serverSocket = soc;
+    }
+
+    ServerSocket getServerSocket() {
+        return serverSocket;
+    }
+
+    /**
+     * Returns the address and port of this socket as a {@code String}.
+     *
+     * @return  a string representation of this socket.
+     */
+    public String toString() {
+        return "Socket[addr=" + getInetAddress() +
+            ",port=" + getPort() + ",localport=" + getLocalPort()  + "]";
+    }
+
+    void reset() throws IOException {
+        address = null;
+        port = 0;
+        localport = 0;
+    }
+
+    /**
+     * Sets performance preferences for this socket.
+     *
+     * <p> Sockets use the TCP/IP protocol by default.  Some implementations
+     * may offer alternative protocols which have different performance
+     * characteristics than TCP/IP.  This method allows the application to
+     * express its own preferences as to how these tradeoffs should be made
+     * when the implementation chooses from the available protocols.
+     *
+     * <p> Performance preferences are described by three integers
+     * whose values indicate the relative importance of short connection time,
+     * low latency, and high bandwidth.  The absolute values of the integers
+     * are irrelevant; in order to choose a protocol the values are simply
+     * compared, with larger values indicating stronger preferences. Negative
+     * values represent a lower priority than positive values. If the
+     * application prefers short connection time over both low latency and high
+     * bandwidth, for example, then it could invoke this method with the values
+     * {@code (1, 0, 0)}.  If the application prefers high bandwidth above low
+     * latency, and low latency above short connection time, then it could
+     * invoke this method with the values {@code (0, 1, 2)}.
+     *
+     * By default, this method does nothing, unless it is overridden in a
+     * a sub-class.
+     *
+     * @param  connectionTime
+     *         An {@code int} expressing the relative importance of a short
+     *         connection time
+     *
+     * @param  latency
+     *         An {@code int} expressing the relative importance of low
+     *         latency
+     *
+     * @param  bandwidth
+     *         An {@code int} expressing the relative importance of high
+     *         bandwidth
+     *
+     * @since 1.5
+     */
+    protected void setPerformancePreferences(int connectionTime,
+                                          int latency,
+                                          int bandwidth)
+    {
+        /* Not implemented yet */
+    }
+
+    <T> void setOption(SocketOption<T> name, T value) throws IOException {
+        if (name == StandardSocketOptions.SO_KEEPALIVE) {
+            setOption(SocketOptions.SO_KEEPALIVE, value);
+        } else if (name == StandardSocketOptions.SO_SNDBUF) {
+            setOption(SocketOptions.SO_SNDBUF, value);
+        } else if (name == StandardSocketOptions.SO_RCVBUF) {
+            setOption(SocketOptions.SO_RCVBUF, value);
+        } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+            setOption(SocketOptions.SO_REUSEADDR, value);
+        } else if (name == StandardSocketOptions.SO_LINGER) {
+            setOption(SocketOptions.SO_LINGER, value);
+        } else if (name == StandardSocketOptions.IP_TOS) {
+            setOption(SocketOptions.IP_TOS, value);
+        } else if (name == StandardSocketOptions.TCP_NODELAY) {
+            setOption(SocketOptions.TCP_NODELAY, value);
+        } else {
+            throw new UnsupportedOperationException("unsupported option");
+        }
+    }
+
+    <T> T getOption(SocketOption<T> name) throws IOException {
+        if (name == StandardSocketOptions.SO_KEEPALIVE) {
+            return (T)getOption(SocketOptions.SO_KEEPALIVE);
+        } else if (name == StandardSocketOptions.SO_SNDBUF) {
+            return (T)getOption(SocketOptions.SO_SNDBUF);
+        } else if (name == StandardSocketOptions.SO_RCVBUF) {
+            return (T)getOption(SocketOptions.SO_RCVBUF);
+        } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+            return (T)getOption(SocketOptions.SO_REUSEADDR);
+        } else if (name == StandardSocketOptions.SO_LINGER) {
+            return (T)getOption(SocketOptions.SO_LINGER);
+        } else if (name == StandardSocketOptions.IP_TOS) {
+            return (T)getOption(SocketOptions.IP_TOS);
+        } else if (name == StandardSocketOptions.TCP_NODELAY) {
+            return (T)getOption(SocketOptions.TCP_NODELAY);
+        } else {
+            throw new UnsupportedOperationException("unsupported option");
+        }
+    }
+}
diff --git a/java/net/SocketImplFactory.java b/java/net/SocketImplFactory.java
new file mode 100644
index 0000000..7aa6363
--- /dev/null
+++ b/java/net/SocketImplFactory.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * This interface defines a factory for socket implementations. It
+ * is used by the classes {@code Socket} and
+ * {@code ServerSocket} to create actual socket
+ * implementations.
+ *
+ * @author  Arthur van Hoff
+ * @see     java.net.Socket
+ * @see     java.net.ServerSocket
+ * @since   JDK1.0
+ */
+public
+interface SocketImplFactory {
+    /**
+     * Creates a new {@code SocketImpl} instance.
+     *
+     * @return  a new instance of {@code SocketImpl}.
+     * @see     java.net.SocketImpl
+     */
+    SocketImpl createSocketImpl();
+}
diff --git a/java/net/SocketInputStream.java b/java/net/SocketInputStream.java
new file mode 100644
index 0000000..8d0e0c5
--- /dev/null
+++ b/java/net/SocketInputStream.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+
+import dalvik.system.BlockGuard;
+import sun.net.ConnectionResetException;
+
+/**
+ * This stream extends FileInputStream to implement a
+ * SocketInputStream. Note that this class should <b>NOT</b> be
+ * public.
+ *
+ * @author      Jonathan Payne
+ * @author      Arthur van Hoff
+ */
+class SocketInputStream extends FileInputStream
+{
+    // Android-removed: Android doesn't need to call native init.
+    // static {
+    //    init();
+    //}
+
+    private boolean eof;
+    private AbstractPlainSocketImpl impl = null;
+    private byte temp[];
+    private Socket socket = null;
+
+    /**
+     * Creates a new SocketInputStream. Can only be called
+     * by a Socket. This method needs to hang on to the owner Socket so
+     * that the fd will not be closed.
+     * @param impl the implemented socket input stream
+     */
+    SocketInputStream(AbstractPlainSocketImpl impl) throws IOException {
+        super(impl.getFileDescriptor());
+        this.impl = impl;
+        socket = impl.getSocket();
+    }
+
+    /**
+     * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
+     * object associated with this file input stream.</p>
+     *
+     * The {@code getChannel} method of {@code SocketInputStream}
+     * returns {@code null} since it is a socket based stream.</p>
+     *
+     * @return  the file channel associated with this file input stream
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public final FileChannel getChannel() {
+        return null;
+    }
+
+    /**
+     * Reads into an array of bytes at the specified offset using
+     * the received socket primitive.
+     * @param fd the FileDescriptor
+     * @param b the buffer into which the data is read
+     * @param off the start offset of the data
+     * @param len the maximum number of bytes read
+     * @param timeout the read timeout in ms
+     * @return the actual number of bytes read, -1 is
+     *          returned when the end of the stream is reached.
+     * @exception IOException If an I/O error has occurred.
+     */
+    private native int socketRead0(FileDescriptor fd,
+                                   byte b[], int off, int len,
+                                   int timeout)
+        throws IOException;
+
+    // wrap native call to allow instrumentation
+    /**
+     * Reads into an array of bytes at the specified offset using
+     * the received socket primitive.
+     * @param fd the FileDescriptor
+     * @param b the buffer into which the data is read
+     * @param off the start offset of the data
+     * @param len the maximum number of bytes read
+     * @param timeout the read timeout in ms
+     * @return the actual number of bytes read, -1 is
+     *          returned when the end of the stream is reached.
+     * @exception IOException If an I/O error has occurred.
+     */
+    private int socketRead(FileDescriptor fd,
+                           byte b[], int off, int len,
+                           int timeout)
+        throws IOException {
+        return socketRead0(fd, b, off, len, timeout);
+    }
+
+    /**
+     * Reads into a byte array data from the socket.
+     * @param b the buffer into which the data is read
+     * @return the actual number of bytes read, -1 is
+     *          returned when the end of the stream is reached.
+     * @exception IOException If an I/O error has occurred.
+     */
+    public int read(byte b[]) throws IOException {
+        return read(b, 0, b.length);
+    }
+
+    /**
+     * Reads into a byte array <i>b</i> at offset <i>off</i>,
+     * <i>length</i> bytes of data.
+     * @param b the buffer into which the data is read
+     * @param off the start offset of the data
+     * @param length the maximum number of bytes read
+     * @return the actual number of bytes read, -1 is
+     *          returned when the end of the stream is reached.
+     * @exception IOException If an I/O error has occurred.
+     */
+    public int read(byte b[], int off, int length) throws IOException {
+        return read(b, off, length, impl.getTimeout());
+    }
+
+    int read(byte b[], int off, int length, int timeout) throws IOException {
+        int n;
+
+        // EOF already encountered
+        if (eof) {
+            return -1;
+        }
+
+        // connection reset
+        if (impl.isConnectionReset()) {
+            throw new SocketException("Connection reset");
+        }
+
+        // bounds check
+        if (length <= 0 || off < 0 || length > b.length - off) {
+            if (length == 0) {
+                return 0;
+            }
+            throw new ArrayIndexOutOfBoundsException("length == " + length
+                    + " off == " + off + " buffer length == " + b.length);
+        }
+
+        boolean gotReset = false;
+
+        // acquire file descriptor and do the read
+        FileDescriptor fd = impl.acquireFD();
+        try {
+            // Android-added: Check BlockGuard policy in read().
+            BlockGuard.getThreadPolicy().onNetwork();
+            n = socketRead(fd, b, off, length, timeout);
+            if (n > 0) {
+                return n;
+            }
+        } catch (ConnectionResetException rstExc) {
+            gotReset = true;
+        } finally {
+            impl.releaseFD();
+        }
+
+        /*
+         * We receive a "connection reset" but there may be bytes still
+         * buffered on the socket
+         */
+        if (gotReset) {
+            impl.setConnectionResetPending();
+            impl.acquireFD();
+            try {
+                n = socketRead(fd, b, off, length, timeout);
+                if (n > 0) {
+                    return n;
+                }
+            } catch (ConnectionResetException rstExc) {
+            } finally {
+                impl.releaseFD();
+            }
+        }
+
+        /*
+         * If we get here we are at EOF, the socket has been closed,
+         * or the connection has been reset.
+         */
+        if (impl.isClosedOrPending()) {
+            throw new SocketException("Socket closed");
+        }
+        if (impl.isConnectionResetPending()) {
+            impl.setConnectionReset();
+        }
+        if (impl.isConnectionReset()) {
+            throw new SocketException("Connection reset");
+        }
+        eof = true;
+        return -1;
+    }
+
+    /**
+     * Reads a single byte from the socket.
+     */
+    public int read() throws IOException {
+        if (eof) {
+            return -1;
+        }
+        temp = new byte[1];
+        int n = read(temp, 0, 1);
+        if (n <= 0) {
+            return -1;
+        }
+        return temp[0] & 0xff;
+    }
+
+    /**
+     * Skips n bytes of input.
+     * @param numbytes the number of bytes to skip
+     * @return  the actual number of bytes skipped.
+     * @exception IOException If an I/O error has occurred.
+     */
+    public long skip(long numbytes) throws IOException {
+        if (numbytes <= 0) {
+            return 0;
+        }
+        long n = numbytes;
+        int buflen = (int) Math.min(1024, n);
+        byte data[] = new byte[buflen];
+        while (n > 0) {
+            int r = read(data, 0, (int) Math.min((long) buflen, n));
+            if (r < 0) {
+                break;
+            }
+            n -= r;
+        }
+        return numbytes - n;
+    }
+
+    /**
+     * Returns the number of bytes that can be read without blocking.
+     * @return the number of immediately available bytes
+     */
+    public int available() throws IOException {
+        // Android-changed: Bug fix, if eof == true, we must indicate that we
+        // have 0 bytes available.
+        if (eof) {
+            return 0;
+        } else {
+            return impl.available();
+        }
+    }
+
+    /**
+     * Closes the stream.
+     */
+    private boolean closing = false;
+    public void close() throws IOException {
+        // Prevent recursion. See BugId 4484411
+        if (closing)
+            return;
+        closing = true;
+        if (socket != null) {
+            if (!socket.isClosed())
+                socket.close();
+        } else
+            impl.close();
+        closing = false;
+    }
+
+    void setEOF(boolean eof) {
+        this.eof = eof;
+    }
+
+    /**
+     * Overrides finalize, the fd is closed by the Socket.
+     */
+    protected void finalize() {}
+
+    // Android-removed: Android doesn't need native init.
+    /*
+     * Perform class load-time initializations.
+     *
+    private native static void init();
+    */
+}
diff --git a/java/net/SocketOption.java b/java/net/SocketOption.java
new file mode 100644
index 0000000..2ccf57f
--- /dev/null
+++ b/java/net/SocketOption.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * A socket option associated with a socket.
+ *
+ * <p> In the {@link java.nio.channels channels} package, the {@link
+ * java.nio.channels.NetworkChannel} interface defines the {@link
+ * java.nio.channels.NetworkChannel#setOption(SocketOption,Object) setOption}
+ * and {@link java.nio.channels.NetworkChannel#getOption(SocketOption) getOption}
+ * methods to set and query the channel's socket options.
+ *
+ * @param   <T>     The type of the socket option value.
+ *
+ * @since 1.7
+ *
+ * @see StandardSocketOptions
+ */
+
+public interface SocketOption<T> {
+
+    /**
+     * Returns the name of the socket option.
+     *
+     * @return the name of the socket option
+     */
+    String name();
+
+    /**
+     * Returns the type of the socket option value.
+     *
+     * @return the type of the socket option value
+     */
+    Class<T> type();
+}
diff --git a/java/net/SocketOptions.java b/java/net/SocketOptions.java
new file mode 100644
index 0000000..7e1b0fc
--- /dev/null
+++ b/java/net/SocketOptions.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.lang.annotation.Native;
+
+/**
+ * Interface of methods to get/set socket options.  This interface is
+ * implemented by: <B>SocketImpl</B> and  <B>DatagramSocketImpl</B>.
+ * Subclasses of these should override the methods
+ * of this interface in order to support their own options.
+ * <P>
+ * The methods and constants which specify options in this interface are
+ * for implementation only.  If you're not subclassing SocketImpl or
+ * DatagramSocketImpl, <B>you won't use these directly.</B> There are
+ * type-safe methods to get/set each of these options in Socket, ServerSocket,
+ * DatagramSocket and MulticastSocket.
+ * <P>
+ * @author David Brown
+ */
+
+
+public interface SocketOptions {
+
+    /**
+     * Enable/disable the option specified by <I>optID</I>.  If the option
+     * is to be enabled, and it takes an option-specific "value",  this is
+     * passed in <I>value</I>.  The actual type of value is option-specific,
+     * and it is an error to pass something that isn't of the expected type:
+     * <BR><PRE>
+     * SocketImpl s;
+     * ...
+     * s.setOption(SO_LINGER, new Integer(10));
+     *    // OK - set SO_LINGER w/ timeout of 10 sec.
+     * s.setOption(SO_LINGER, new Double(10));
+     *    // ERROR - expects java.lang.Integer
+     *</PRE>
+     * If the requested option is binary, it can be set using this method by
+     * a java.lang.Boolean:
+     * <BR><PRE>
+     * s.setOption(TCP_NODELAY, new Boolean(true));
+     *    // OK - enables TCP_NODELAY, a binary option
+     * </PRE>
+     * <BR>
+     * Any option can be disabled using this method with a Boolean(false):
+     * <BR><PRE>
+     * s.setOption(TCP_NODELAY, new Boolean(false));
+     *    // OK - disables TCP_NODELAY
+     * s.setOption(SO_LINGER, new Boolean(false));
+     *    // OK - disables SO_LINGER
+     * </PRE>
+     * <BR>
+     * For an option that has a notion of on and off, and requires
+     * a non-boolean parameter, setting its value to anything other than
+     * <I>Boolean(false)</I> implicitly enables it.
+     * <BR>
+     * Throws SocketException if the option is unrecognized,
+     * the socket is closed, or some low-level error occurred
+     * <BR>
+     * @param optID identifies the option
+     * @param value the parameter of the socket option
+     * @throws SocketException if the option is unrecognized,
+     * the socket is closed, or some low-level error occurred
+     * @see #getOption(int)
+     */
+    public void
+        setOption(int optID, Object value) throws SocketException;
+
+    /**
+     * Fetch the value of an option.
+     * Binary options will return java.lang.Boolean(true)
+     * if enabled, java.lang.Boolean(false) if disabled, e.g.:
+     * <BR><PRE>
+     * SocketImpl s;
+     * ...
+     * Boolean noDelay = (Boolean)(s.getOption(TCP_NODELAY));
+     * if (noDelay.booleanValue()) {
+     *     // true if TCP_NODELAY is enabled...
+     * ...
+     * }
+     * </PRE>
+     * <P>
+     * For options that take a particular type as a parameter,
+     * getOption(int) will return the parameter's value, else
+     * it will return java.lang.Boolean(false):
+     * <PRE>
+     * Object o = s.getOption(SO_LINGER);
+     * if (o instanceof Integer) {
+     *     System.out.print("Linger time is " + ((Integer)o).intValue());
+     * } else {
+     *   // the true type of o is java.lang.Boolean(false);
+     * }
+     * </PRE>
+     *
+     * @param optID an {@code int} identifying the option to fetch
+     * @return the value of the option
+     * @throws SocketException if the socket is closed
+     * @throws SocketException if <I>optID</I> is unknown along the
+     *         protocol stack (including the SocketImpl)
+     * @see #setOption(int, java.lang.Object)
+     */
+    public Object getOption(int optID) throws SocketException;
+
+    /**
+     * The java-supported BSD-style options.
+     */
+
+    /**
+     * Disable Nagle's algorithm for this connection.  Written data
+     * to the network is not buffered pending acknowledgement of
+     * previously written data.
+     *<P>
+     * Valid for TCP only: SocketImpl.
+     *
+     * @see Socket#setTcpNoDelay
+     * @see Socket#getTcpNoDelay
+     */
+
+    @Native public final static int TCP_NODELAY = 0x0001;
+
+    /**
+     * Fetch the local address binding of a socket (this option cannot
+     * be "set" only "gotten", since sockets are bound at creation time,
+     * and so the locally bound address cannot be changed).  The default local
+     * address of a socket is INADDR_ANY, meaning any local address on a
+     * multi-homed host.  A multi-homed host can use this option to accept
+     * connections to only one of its addresses (in the case of a
+     * ServerSocket or DatagramSocket), or to specify its return address
+     * to the peer (for a Socket or DatagramSocket).  The parameter of
+     * this option is an InetAddress.
+     * <P>
+     * This option <B>must</B> be specified in the constructor.
+     * <P>
+     * Valid for: SocketImpl, DatagramSocketImpl
+     *
+     * @see Socket#getLocalAddress
+     * @see DatagramSocket#getLocalAddress
+     */
+
+    @Native public final static int SO_BINDADDR = 0x000F;
+
+    /** Sets SO_REUSEADDR for a socket.  This is used only for MulticastSockets
+     * in java, and it is set by default for MulticastSockets.
+     * <P>
+     * Valid for: DatagramSocketImpl
+     */
+
+    @Native public final static int SO_REUSEADDR = 0x04;
+
+    /**
+     * Sets SO_BROADCAST for a socket. This option enables and disables
+     * the ability of the process to send broadcast messages. It is supported
+     * for only datagram sockets and only on networks that support
+     * the concept of a broadcast message (e.g. Ethernet, token ring, etc.),
+     * and it is set by default for DatagramSockets.
+     * @since 1.4
+     */
+
+    @Native public final static int SO_BROADCAST = 0x0020;
+
+    /** Set which outgoing interface on which to send multicast packets.
+     * Useful on hosts with multiple network interfaces, where applications
+     * want to use other than the system default.  Takes/returns an InetAddress.
+     * <P>
+     * Valid for Multicast: DatagramSocketImpl
+     *
+     * @see MulticastSocket#setInterface(InetAddress)
+     * @see MulticastSocket#getInterface()
+     */
+
+    @Native public final static int IP_MULTICAST_IF = 0x10;
+
+    /** Same as above. This option is introduced so that the behaviour
+     *  with IP_MULTICAST_IF will be kept the same as before, while
+     *  this new option can support setting outgoing interfaces with either
+     *  IPv4 and IPv6 addresses.
+     *
+     *  NOTE: make sure there is no conflict with this
+     * @see MulticastSocket#setNetworkInterface(NetworkInterface)
+     * @see MulticastSocket#getNetworkInterface()
+     * @since 1.4
+     */
+    @Native public final static int IP_MULTICAST_IF2 = 0x1f;
+
+    /**
+     * This option enables or disables local loopback of multicast datagrams.
+     * This option is enabled by default for Multicast Sockets.
+     * @since 1.4
+     */
+
+    @Native public final static int IP_MULTICAST_LOOP = 0x12;
+
+    /**
+     * This option sets the type-of-service or traffic class field
+     * in the IP header for a TCP or UDP socket.
+     * @since 1.4
+     */
+
+    @Native public final static int IP_TOS = 0x3;
+
+    /**
+     * Specify a linger-on-close timeout.  This option disables/enables
+     * immediate return from a <B>close()</B> of a TCP Socket.  Enabling
+     * this option with a non-zero Integer <I>timeout</I> means that a
+     * <B>close()</B> will block pending the transmission and acknowledgement
+     * of all data written to the peer, at which point the socket is closed
+     * <I>gracefully</I>.  Upon reaching the linger timeout, the socket is
+     * closed <I>forcefully</I>, with a TCP RST. Enabling the option with a
+     * timeout of zero does a forceful close immediately. If the specified
+     * timeout value exceeds 65,535 it will be reduced to 65,535.
+     * <P>
+     * Valid only for TCP: SocketImpl
+     *
+     * @see Socket#setSoLinger
+     * @see Socket#getSoLinger
+     */
+    @Native public final static int SO_LINGER = 0x0080;
+
+    /** Set a timeout on blocking Socket operations:
+     * <PRE>
+     * ServerSocket.accept();
+     * SocketInputStream.read();
+     * DatagramSocket.receive();
+     * </PRE>
+     *
+     * <P> The option must be set prior to entering a blocking
+     * operation to take effect.  If the timeout expires and the
+     * operation would continue to block,
+     * <B>java.io.InterruptedIOException</B> is raised.  The Socket is
+     * not closed in this case.
+     *
+     * <P> Valid for all sockets: SocketImpl, DatagramSocketImpl
+     *
+     * @see Socket#setSoTimeout
+     * @see ServerSocket#setSoTimeout
+     * @see DatagramSocket#setSoTimeout
+     */
+    @Native public final static int SO_TIMEOUT = 0x1006;
+
+    /**
+     * Set a hint the size of the underlying buffers used by the
+     * platform for outgoing network I/O. When used in set, this is a
+     * suggestion to the kernel from the application about the size of
+     * buffers to use for the data to be sent over the socket. When
+     * used in get, this must return the size of the buffer actually
+     * used by the platform when sending out data on this socket.
+     *
+     * Valid for all sockets: SocketImpl, DatagramSocketImpl
+     *
+     * @see Socket#setSendBufferSize
+     * @see Socket#getSendBufferSize
+     * @see DatagramSocket#setSendBufferSize
+     * @see DatagramSocket#getSendBufferSize
+     */
+    @Native public final static int SO_SNDBUF = 0x1001;
+
+    /**
+     * Set a hint the size of the underlying buffers used by the
+     * platform for incoming network I/O. When used in set, this is a
+     * suggestion to the kernel from the application about the size of
+     * buffers to use for the data to be received over the
+     * socket. When used in get, this must return the size of the
+     * buffer actually used by the platform when receiving in data on
+     * this socket.
+     *
+     * Valid for all sockets: SocketImpl, DatagramSocketImpl
+     *
+     * @see Socket#setReceiveBufferSize
+     * @see Socket#getReceiveBufferSize
+     * @see DatagramSocket#setReceiveBufferSize
+     * @see DatagramSocket#getReceiveBufferSize
+     */
+    @Native public final static int SO_RCVBUF = 0x1002;
+
+    /**
+     * When the keepalive option is set for a TCP socket and no data
+     * has been exchanged across the socket in either direction for
+     * 2 hours (NOTE: the actual value is implementation dependent),
+     * TCP automatically sends a keepalive probe to the peer. This probe is a
+     * TCP segment to which the peer must respond.
+     * One of three responses is expected:
+     * 1. The peer responds with the expected ACK. The application is not
+     *    notified (since everything is OK). TCP will send another probe
+     *    following another 2 hours of inactivity.
+     * 2. The peer responds with an RST, which tells the local TCP that
+     *    the peer host has crashed and rebooted. The socket is closed.
+     * 3. There is no response from the peer. The socket is closed.
+     *
+     * The purpose of this option is to detect if the peer host crashes.
+     *
+     * Valid only for TCP socket: SocketImpl
+     *
+     * @see Socket#setKeepAlive
+     * @see Socket#getKeepAlive
+     */
+    @Native public final static int SO_KEEPALIVE = 0x0008;
+
+    /**
+     * When the OOBINLINE option is set, any TCP urgent data received on
+     * the socket will be received through the socket input stream.
+     * When the option is disabled (which is the default) urgent data
+     * is silently discarded.
+     *
+     * @see Socket#setOOBInline
+     * @see Socket#getOOBInline
+     */
+    @Native public final static int SO_OOBINLINE = 0x1003;
+}
diff --git a/java/net/SocketOutputStream.java b/java/net/SocketOutputStream.java
new file mode 100644
index 0000000..9e8e792
--- /dev/null
+++ b/java/net/SocketOutputStream.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+
+import dalvik.system.BlockGuard;
+
+/**
+ * This stream extends FileOutputStream to implement a
+ * SocketOutputStream. Note that this class should <b>NOT</b> be
+ * public.
+ *
+ * @author      Jonathan Payne
+ * @author      Arthur van Hoff
+ */
+class SocketOutputStream extends FileOutputStream
+{
+    // Android-removed: Android doesn't need to call native init.
+    // static {
+    //    init();
+    //}
+
+    private AbstractPlainSocketImpl impl = null;
+    private byte temp[] = new byte[1];
+    private Socket socket = null;
+
+    /**
+     * Creates a new SocketOutputStream. Can only be called
+     * by a Socket. This method needs to hang on to the owner Socket so
+     * that the fd will not be closed.
+     * @param impl the socket output stream inplemented
+     */
+    SocketOutputStream(AbstractPlainSocketImpl impl) throws IOException {
+        super(impl.getFileDescriptor());
+        this.impl = impl;
+        socket = impl.getSocket();
+    }
+
+    /**
+     * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
+     * object associated with this file output stream. </p>
+     *
+     * The {@code getChannel} method of {@code SocketOutputStream}
+     * returns {@code null} since it is a socket based stream.</p>
+     *
+     * @return  the file channel associated with this file output stream
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public final FileChannel getChannel() {
+        return null;
+    }
+
+    /**
+     * Writes to the socket.
+     * @param fd the FileDescriptor
+     * @param b the data to be written
+     * @param off the start offset in the data
+     * @param len the number of bytes that are written
+     * @exception IOException If an I/O error has occurred.
+     */
+    private native void socketWrite0(FileDescriptor fd, byte[] b, int off,
+                                     int len) throws IOException;
+
+    /**
+     * Writes to the socket with appropriate locking of the
+     * FileDescriptor.
+     * @param b the data to be written
+     * @param off the start offset in the data
+     * @param len the number of bytes that are written
+     * @exception IOException If an I/O error has occurred.
+     */
+    private void socketWrite(byte b[], int off, int len) throws IOException {
+
+
+        if (len <= 0 || off < 0 || len > b.length - off) {
+            if (len == 0) {
+                return;
+            }
+            throw new ArrayIndexOutOfBoundsException("len == " + len
+                    + " off == " + off + " buffer length == " + b.length);
+        }
+
+        FileDescriptor fd = impl.acquireFD();
+        try {
+            // Android-added: Check BlockGuard policy in socketWrite.
+            BlockGuard.getThreadPolicy().onNetwork();
+            socketWrite0(fd, b, off, len);
+        } catch (SocketException se) {
+            if (se instanceof sun.net.ConnectionResetException) {
+                impl.setConnectionResetPending();
+                se = new SocketException("Connection reset");
+            }
+            if (impl.isClosedOrPending()) {
+                throw new SocketException("Socket closed");
+            } else {
+                throw se;
+            }
+        } finally {
+            impl.releaseFD();
+        }
+    }
+
+    /**
+     * Writes a byte to the socket.
+     * @param b the data to be written
+     * @exception IOException If an I/O error has occurred.
+     */
+    public void write(int b) throws IOException {
+        temp[0] = (byte)b;
+        socketWrite(temp, 0, 1);
+    }
+
+    /**
+     * Writes the contents of the buffer <i>b</i> to the socket.
+     * @param b the data to be written
+     * @exception SocketException If an I/O error has occurred.
+     */
+    public void write(byte b[]) throws IOException {
+        socketWrite(b, 0, b.length);
+    }
+
+    /**
+     * Writes <i>length</i> bytes from buffer <i>b</i> starting at
+     * offset <i>len</i>.
+     * @param b the data to be written
+     * @param off the start offset in the data
+     * @param len the number of bytes that are written
+     * @exception SocketException If an I/O error has occurred.
+     */
+    public void write(byte b[], int off, int len) throws IOException {
+        socketWrite(b, off, len);
+    }
+
+    /**
+     * Closes the stream.
+     */
+    private boolean closing = false;
+    public void close() throws IOException {
+        // Prevent recursion. See BugId 4484411
+        if (closing)
+            return;
+        closing = true;
+        if (socket != null) {
+            if (!socket.isClosed())
+                socket.close();
+        } else
+            impl.close();
+        closing = false;
+    }
+
+    /**
+     * Overrides finalize, the fd is closed by the Socket.
+     */
+    protected void finalize() {}
+
+    // Android-removed: Android doesn't need native init.
+    /*
+     * Perform class load-time initializations.
+     *
+    private native static void init();
+    */
+}
diff --git a/java/net/SocketPermission.java b/java/net/SocketPermission.java
new file mode 100644
index 0000000..2195ecc
--- /dev/null
+++ b/java/net/SocketPermission.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.security.Permission;
+
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public final class SocketPermission extends Permission
+implements java.io.Serializable
+{
+
+    public SocketPermission(String host, String action) { super(""); }
+
+    public boolean implies(Permission p) { return true; }
+
+    public String getActions() { return null; }
+}
diff --git a/java/net/SocketSecrets.java b/java/net/SocketSecrets.java
new file mode 100644
index 0000000..9772906
--- /dev/null
+++ b/java/net/SocketSecrets.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+
+class SocketSecrets {
+
+    /* accessed by reflection from jdk.net.Sockets */
+
+    /* obj must be a Socket or ServerSocket */
+
+    private static <T> void setOption(Object obj, SocketOption<T> name, T value) throws IOException {
+        SocketImpl impl;
+
+        if (obj instanceof Socket) {
+            impl = ((Socket)obj).getImpl();
+        } else if (obj instanceof ServerSocket) {
+            impl = ((ServerSocket)obj).getImpl();
+        } else {
+            throw new IllegalArgumentException();
+        }
+        impl.setOption(name, value);
+    }
+
+    private static <T> T getOption(Object obj, SocketOption<T> name) throws IOException {
+        SocketImpl impl;
+
+        if (obj instanceof Socket) {
+            impl = ((Socket)obj).getImpl();
+        } else if (obj instanceof ServerSocket) {
+            impl = ((ServerSocket)obj).getImpl();
+        } else {
+            throw new IllegalArgumentException();
+        }
+        return impl.getOption(name);
+    }
+
+    private static <T> void setOption(DatagramSocket s, SocketOption<T> name, T value) throws IOException {
+        s.getImpl().setOption(name, value);
+    }
+
+    private static <T> T getOption(DatagramSocket s, SocketOption<T> name) throws IOException {
+        return s.getImpl().getOption(name);
+    }
+
+}
diff --git a/java/net/SocketTimeoutException.java b/java/net/SocketTimeoutException.java
new file mode 100644
index 0000000..5daf600
--- /dev/null
+++ b/java/net/SocketTimeoutException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * Signals that a timeout has occurred on a socket read or accept.
+ *
+ * @since   1.4
+ */
+
+public class SocketTimeoutException extends java.io.InterruptedIOException {
+    private static final long serialVersionUID = -8846654841826352300L;
+
+    /**
+     * Constructs a new SocketTimeoutException with a detail
+     * message.
+     * @param msg the detail message
+     */
+    public SocketTimeoutException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Construct a new SocketTimeoutException with no detailed message.
+     */
+    public SocketTimeoutException() {}
+}
diff --git a/java/net/SocksConsts.java b/java/net/SocksConsts.java
new file mode 100644
index 0000000..df47aa7
--- /dev/null
+++ b/java/net/SocksConsts.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+
+/**
+ * Constants used by the SOCKS protocol implementation.
+ */
+
+interface SocksConsts {
+    static final int PROTO_VERS4                = 4;
+    static final int PROTO_VERS         = 5;
+    static final int DEFAULT_PORT               = 1080;
+
+    static final int NO_AUTH            = 0;
+    static final int GSSAPI             = 1;
+    static final int USER_PASSW         = 2;
+    static final int NO_METHODS         = -1;
+
+    static final int CONNECT            = 1;
+    static final int BIND                       = 2;
+    static final int UDP_ASSOC          = 3;
+
+    static final int IPV4                       = 1;
+    static final int DOMAIN_NAME                = 3;
+    static final int IPV6                       = 4;
+
+    static final int REQUEST_OK         = 0;
+    static final int GENERAL_FAILURE    = 1;
+    static final int NOT_ALLOWED                = 2;
+    static final int NET_UNREACHABLE    = 3;
+    static final int HOST_UNREACHABLE   = 4;
+    static final int CONN_REFUSED               = 5;
+    static final int TTL_EXPIRED                = 6;
+    static final int CMD_NOT_SUPPORTED  = 7;
+    static final int ADDR_TYPE_NOT_SUP  = 8;
+}
diff --git a/java/net/SocksSocketImpl.java b/java/net/SocksSocketImpl.java
new file mode 100644
index 0000000..0d9d8f5
--- /dev/null
+++ b/java/net/SocksSocketImpl.java
@@ -0,0 +1,1100 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.BufferedOutputStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import sun.net.SocksProxy;
+import sun.net.www.ParseUtil;
+/* import org.ietf.jgss.*; */
+
+/**
+ * SOCKS (V4 & V5) TCP socket implementation (RFC 1928).
+ * This is a subclass of PlainSocketImpl.
+ * Note this class should <b>NOT</b> be public.
+ */
+
+class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
+    private String server = null;
+    private int serverPort = DEFAULT_PORT;
+    private InetSocketAddress external_address;
+    private boolean useV4 = false;
+    private Socket cmdsock = null;
+    private InputStream cmdIn = null;
+    private OutputStream cmdOut = null;
+    /* true if the Proxy has been set programatically */
+    private boolean applicationSetProxy;  /* false */
+
+
+    SocksSocketImpl() {
+        // Nothing needed
+    }
+
+    SocksSocketImpl(String server, int port) {
+        this.server = server;
+        this.serverPort = (port == -1 ? DEFAULT_PORT : port);
+    }
+
+    SocksSocketImpl(Proxy proxy) {
+        SocketAddress a = proxy.address();
+        if (a instanceof InetSocketAddress) {
+            InetSocketAddress ad = (InetSocketAddress) a;
+            // Use getHostString() to avoid reverse lookups
+            server = ad.getHostString();
+            serverPort = ad.getPort();
+        }
+    }
+
+    void setV4() {
+        useV4 = true;
+    }
+
+    private synchronized void privilegedConnect(final String host,
+                                              final int port,
+                                              final int timeout)
+         throws IOException
+    {
+        try {
+            AccessController.doPrivileged(
+                new java.security.PrivilegedExceptionAction<Void>() {
+                    public Void run() throws IOException {
+                              superConnectServer(host, port, timeout);
+                              cmdIn = getInputStream();
+                              cmdOut = getOutputStream();
+                              return null;
+                          }
+                      });
+        } catch (java.security.PrivilegedActionException pae) {
+            throw (IOException) pae.getException();
+        }
+    }
+
+    private void superConnectServer(String host, int port,
+                                    int timeout) throws IOException {
+        super.connect(new InetSocketAddress(host, port), timeout);
+    }
+
+    private static int remainingMillis(long deadlineMillis) throws IOException {
+        if (deadlineMillis == 0L)
+            return 0;
+
+        final long remaining = deadlineMillis - System.currentTimeMillis();
+        if (remaining > 0)
+            return (int) remaining;
+
+        throw new SocketTimeoutException();
+    }
+
+    private int readSocksReply(InputStream in, byte[] data) throws IOException {
+        return readSocksReply(in, data, 0L);
+    }
+
+    private int readSocksReply(InputStream in, byte[] data, long deadlineMillis) throws IOException {
+        int len = data.length;
+        int received = 0;
+        for (int attempts = 0; received < len && attempts < 3; attempts++) {
+            int count;
+            try {
+                count = ((SocketInputStream)in).read(data, received, len - received, remainingMillis(deadlineMillis));
+            } catch (SocketTimeoutException e) {
+                throw new SocketTimeoutException("Connect timed out");
+            }
+            if (count < 0)
+                throw new SocketException("Malformed reply from SOCKS server");
+            received += count;
+        }
+        return received;
+    }
+
+    /**
+     * Provides the authentication machanism required by the proxy.
+     */
+    private boolean authenticate(byte method, InputStream in,
+                                 BufferedOutputStream out) throws IOException {
+        return authenticate(method, in, out, 0L);
+    }
+
+    private boolean authenticate(byte method, InputStream in,
+                                 BufferedOutputStream out,
+                                 long deadlineMillis) throws IOException {
+        // No Authentication required. We're done then!
+        if (method == NO_AUTH)
+            return true;
+        /**
+         * User/Password authentication. Try, in that order :
+         * - The application provided Authenticator, if any
+         * - the user.name & no password (backward compatibility behavior).
+         */
+        if (method == USER_PASSW) {
+            String userName;
+            String password = null;
+            final InetAddress addr = InetAddress.getByName(server);
+            PasswordAuthentication pw =
+                java.security.AccessController.doPrivileged(
+                    new java.security.PrivilegedAction<PasswordAuthentication>() {
+                        public PasswordAuthentication run() {
+                                return Authenticator.requestPasswordAuthentication(
+                                       server, addr, serverPort, "SOCKS5", "SOCKS authentication", null);
+                            }
+                        });
+            if (pw != null) {
+                userName = pw.getUserName();
+                password = new String(pw.getPassword());
+            } else {
+                userName = java.security.AccessController.doPrivileged(
+                        new sun.security.action.GetPropertyAction("user.name"));
+            }
+            if (userName == null)
+                return false;
+            out.write(1);
+            out.write(userName.length());
+            try {
+                out.write(userName.getBytes("ISO-8859-1"));
+            } catch (java.io.UnsupportedEncodingException uee) {
+                assert false;
+            }
+            if (password != null) {
+                out.write(password.length());
+                try {
+                    out.write(password.getBytes("ISO-8859-1"));
+                } catch (java.io.UnsupportedEncodingException uee) {
+                    assert false;
+                }
+            } else
+                out.write(0);
+            out.flush();
+            byte[] data = new byte[2];
+            int i = readSocksReply(in, data, deadlineMillis);
+            if (i != 2 || data[1] != 0) {
+                /* RFC 1929 specifies that the connection MUST be closed if
+                   authentication fails */
+                out.close();
+                in.close();
+                return false;
+            }
+            /* Authentication succeeded */
+            return true;
+        }
+        /**
+         * GSSAPI authentication mechanism.
+         * Unfortunately the RFC seems out of sync with the Reference
+         * implementation. I'll leave this in for future completion.
+         */
+//      if (method == GSSAPI) {
+//          try {
+//              GSSManager manager = GSSManager.getInstance();
+//              GSSName name = manager.createName("SERVICE:socks@"+server,
+//                                                   null);
+//              GSSContext context = manager.createContext(name, null, null,
+//                                                         GSSContext.DEFAULT_LIFETIME);
+//              context.requestMutualAuth(true);
+//              context.requestReplayDet(true);
+//              context.requestSequenceDet(true);
+//              context.requestCredDeleg(true);
+//              byte []inToken = new byte[0];
+//              while (!context.isEstablished()) {
+//                  byte[] outToken
+//                      = context.initSecContext(inToken, 0, inToken.length);
+//                  // send the output token if generated
+//                  if (outToken != null) {
+//                      out.write(1);
+//                      out.write(1);
+//                      out.writeShort(outToken.length);
+//                      out.write(outToken);
+//                      out.flush();
+//                      data = new byte[2];
+//                      i = readSocksReply(in, data, deadlineMillis);
+//                      if (i != 2 || data[1] == 0xff) {
+//                          in.close();
+//                          out.close();
+//                          return false;
+//                      }
+//                      i = readSocksReply(in, data, deadlineMillis);
+//                      int len = 0;
+//                      len = ((int)data[0] & 0xff) << 8;
+//                      len += data[1];
+//                      data = new byte[len];
+//                      i = readSocksReply(in, data, deadlineMillis);
+//                      if (i == len)
+//                          return true;
+//                      in.close();
+//                      out.close();
+//                  }
+//              }
+//          } catch (GSSException e) {
+//              /* RFC 1961 states that if Context initialisation fails the connection
+//                 MUST be closed */
+//              e.printStackTrace();
+//              in.close();
+//              out.close();
+//          }
+//      }
+        return false;
+    }
+
+    private void connectV4(InputStream in, OutputStream out,
+                           InetSocketAddress endpoint,
+                           long deadlineMillis) throws IOException {
+        if (!(endpoint.getAddress() instanceof Inet4Address)) {
+            throw new SocketException("SOCKS V4 requires IPv4 only addresses");
+        }
+        out.write(PROTO_VERS4);
+        out.write(CONNECT);
+        out.write((endpoint.getPort() >> 8) & 0xff);
+        out.write((endpoint.getPort() >> 0) & 0xff);
+        out.write(endpoint.getAddress().getAddress());
+        String userName = getUserName();
+        try {
+            out.write(userName.getBytes("ISO-8859-1"));
+        } catch (java.io.UnsupportedEncodingException uee) {
+            assert false;
+        }
+        out.write(0);
+        out.flush();
+        byte[] data = new byte[8];
+        int n = readSocksReply(in, data, deadlineMillis);
+        if (n != 8)
+            throw new SocketException("Reply from SOCKS server has bad length: " + n);
+        if (data[0] != 0 && data[0] != 4)
+            throw new SocketException("Reply from SOCKS server has bad version");
+        SocketException ex = null;
+        switch (data[1]) {
+        case 90:
+            // Success!
+            external_address = endpoint;
+            break;
+        case 91:
+            ex = new SocketException("SOCKS request rejected");
+            break;
+        case 92:
+            ex = new SocketException("SOCKS server couldn't reach destination");
+            break;
+        case 93:
+            ex = new SocketException("SOCKS authentication failed");
+            break;
+        default:
+            ex = new SocketException("Reply from SOCKS server contains bad status");
+            break;
+        }
+        if (ex != null) {
+            in.close();
+            out.close();
+            throw ex;
+        }
+    }
+
+    /**
+     * Connects the Socks Socket to the specified endpoint. It will first
+     * connect to the SOCKS proxy and negotiate the access. If the proxy
+     * grants the connections, then the connect is successful and all
+     * further traffic will go to the "real" endpoint.
+     *
+     * @param   endpoint        the {@code SocketAddress} to connect to.
+     * @param   timeout         the timeout value in milliseconds
+     * @throws  IOException     if the connection can't be established.
+     * @throws  SecurityException if there is a security manager and it
+     *                          doesn't allow the connection
+     * @throws  IllegalArgumentException if endpoint is null or a
+     *          SocketAddress subclass not supported by this socket
+     */
+    @Override
+    protected void connect(SocketAddress endpoint, int timeout) throws IOException {
+        final long deadlineMillis;
+
+        if (timeout == 0) {
+            deadlineMillis = 0L;
+        } else {
+            long finish = System.currentTimeMillis() + timeout;
+            deadlineMillis = finish < 0 ? Long.MAX_VALUE : finish;
+        }
+
+        SecurityManager security = System.getSecurityManager();
+        if (endpoint == null || !(endpoint instanceof InetSocketAddress))
+            throw new IllegalArgumentException("Unsupported address type");
+        InetSocketAddress epoint = (InetSocketAddress) endpoint;
+        if (security != null) {
+            if (epoint.isUnresolved())
+                security.checkConnect(epoint.getHostName(),
+                                      epoint.getPort());
+            else
+                security.checkConnect(epoint.getAddress().getHostAddress(),
+                                      epoint.getPort());
+        }
+        if (server == null) {
+            // Android-removed: Logic to establish proxy connection based on default ProxySelector.
+            // Removed code that tried to establish proxy connection if ProxySelector#getDefault()
+            // is not null. This was never the case in previous Android releases, was causing
+            // issues and therefore was removed.
+            /*
+            // This is the general case
+            // server is not null only when the socket was created with a
+            // specified proxy in which case it does bypass the ProxySelector
+            ProxySelector sel = java.security.AccessController.doPrivileged(
+                new java.security.PrivilegedAction<ProxySelector>() {
+                    public ProxySelector run() {
+                            return ProxySelector.getDefault();
+                        }
+                    });
+            if (sel == null) {
+                /*
+                 * No default proxySelector --> direct connection
+                 *
+                super.connect(epoint, remainingMillis(deadlineMillis));
+                return;
+            }
+            URI uri;
+            // Use getHostString() to avoid reverse lookups
+            String host = epoint.getHostString();
+            // IPv6 litteral?
+            if (epoint.getAddress() instanceof Inet6Address &&
+                (!host.startsWith("[")) && (host.indexOf(":") >= 0)) {
+                host = "[" + host + "]";
+            }
+            try {
+                uri = new URI("socket://" + ParseUtil.encodePath(host) + ":"+ epoint.getPort());
+            } catch (URISyntaxException e) {
+                // This shouldn't happen
+                assert false : e;
+                uri = null;
+            }
+            Proxy p = null;
+            IOException savedExc = null;
+            java.util.Iterator<Proxy> iProxy = null;
+            iProxy = sel.select(uri).iterator();
+            if (iProxy == null || !(iProxy.hasNext())) {
+                super.connect(epoint, remainingMillis(deadlineMillis));
+                return;
+            }
+            while (iProxy.hasNext()) {
+                p = iProxy.next();
+                if (p == null || p.type() != Proxy.Type.SOCKS) {
+                    super.connect(epoint, remainingMillis(deadlineMillis));
+                    return;
+                }
+
+                if (!(p.address() instanceof InetSocketAddress))
+                    throw new SocketException("Unknown address type for proxy: " + p);
+                // Use getHostString() to avoid reverse lookups
+                server = ((InetSocketAddress) p.address()).getHostString();
+                serverPort = ((InetSocketAddress) p.address()).getPort();
+                if (p instanceof SocksProxy) {
+                    if (((SocksProxy)p).protocolVersion() == 4) {
+                        useV4 = true;
+                    }
+                }
+
+                // Connects to the SOCKS server
+                try {
+                    privilegedConnect(server, serverPort, remainingMillis(deadlineMillis));
+                    // Worked, let's get outta here
+                    break;
+                } catch (IOException e) {
+                    // Ooops, let's notify the ProxySelector
+                    sel.connectFailed(uri,p.address(),e);
+                    server = null;
+                    serverPort = -1;
+                    savedExc = e;
+                    // Will continue the while loop and try the next proxy
+                }
+            }
+
+            /*
+             * If server is still null at this point, none of the proxy
+             * worked
+             *
+            if (server == null) {
+                throw new SocketException("Can't connect to SOCKS proxy:"
+                                          + savedExc.getMessage());
+            }
+             */
+            super.connect(epoint, remainingMillis(deadlineMillis));
+            return;
+        } else {
+            // Connects to the SOCKS server
+            try {
+                privilegedConnect(server, serverPort, remainingMillis(deadlineMillis));
+            } catch (IOException e) {
+                throw new SocketException(e.getMessage());
+            }
+        }
+
+        // cmdIn & cmdOut were initialized during the privilegedConnect() call
+        BufferedOutputStream out = new BufferedOutputStream(cmdOut, 512);
+        InputStream in = cmdIn;
+
+        if (useV4) {
+            // SOCKS Protocol version 4 doesn't know how to deal with
+            // DOMAIN type of addresses (unresolved addresses here)
+            if (epoint.isUnresolved())
+                throw new UnknownHostException(epoint.toString());
+            connectV4(in, out, epoint, deadlineMillis);
+            return;
+        }
+
+        // This is SOCKS V5
+        out.write(PROTO_VERS);
+        out.write(2);
+        out.write(NO_AUTH);
+        out.write(USER_PASSW);
+        out.flush();
+        byte[] data = new byte[2];
+        int i = readSocksReply(in, data, deadlineMillis);
+        if (i != 2 || ((int)data[0]) != PROTO_VERS) {
+            // Maybe it's not a V5 sever after all
+            // Let's try V4 before we give up
+            // SOCKS Protocol version 4 doesn't know how to deal with
+            // DOMAIN type of addresses (unresolved addresses here)
+            if (epoint.isUnresolved())
+                throw new UnknownHostException(epoint.toString());
+            connectV4(in, out, epoint, deadlineMillis);
+            return;
+        }
+        if (((int)data[1]) == NO_METHODS)
+            throw new SocketException("SOCKS : No acceptable methods");
+        if (!authenticate(data[1], in, out, deadlineMillis)) {
+            throw new SocketException("SOCKS : authentication failed");
+        }
+        out.write(PROTO_VERS);
+        out.write(CONNECT);
+        out.write(0);
+        /* Test for IPV4/IPV6/Unresolved */
+        if (epoint.isUnresolved()) {
+            out.write(DOMAIN_NAME);
+            out.write(epoint.getHostName().length());
+            try {
+                out.write(epoint.getHostName().getBytes("ISO-8859-1"));
+            } catch (java.io.UnsupportedEncodingException uee) {
+                assert false;
+            }
+            out.write((epoint.getPort() >> 8) & 0xff);
+            out.write((epoint.getPort() >> 0) & 0xff);
+        } else if (epoint.getAddress() instanceof Inet6Address) {
+            out.write(IPV6);
+            out.write(epoint.getAddress().getAddress());
+            out.write((epoint.getPort() >> 8) & 0xff);
+            out.write((epoint.getPort() >> 0) & 0xff);
+        } else {
+            out.write(IPV4);
+            out.write(epoint.getAddress().getAddress());
+            out.write((epoint.getPort() >> 8) & 0xff);
+            out.write((epoint.getPort() >> 0) & 0xff);
+        }
+        out.flush();
+        data = new byte[4];
+        i = readSocksReply(in, data, deadlineMillis);
+        if (i != 4)
+            throw new SocketException("Reply from SOCKS server has bad length");
+        SocketException ex = null;
+        int len;
+        byte[] addr;
+        switch (data[1]) {
+        case REQUEST_OK:
+            // success!
+            switch(data[3]) {
+            case IPV4:
+                addr = new byte[4];
+                i = readSocksReply(in, addr, deadlineMillis);
+                if (i != 4)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                data = new byte[2];
+                i = readSocksReply(in, data, deadlineMillis);
+                if (i != 2)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                break;
+            case DOMAIN_NAME:
+                len = data[1];
+                byte[] host = new byte[len];
+                i = readSocksReply(in, host, deadlineMillis);
+                if (i != len)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                data = new byte[2];
+                i = readSocksReply(in, data, deadlineMillis);
+                if (i != 2)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                break;
+            case IPV6:
+                len = data[1];
+                addr = new byte[len];
+                i = readSocksReply(in, addr, deadlineMillis);
+                if (i != len)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                data = new byte[2];
+                i = readSocksReply(in, data, deadlineMillis);
+                if (i != 2)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                break;
+            default:
+                ex = new SocketException("Reply from SOCKS server contains wrong code");
+                break;
+            }
+            break;
+        case GENERAL_FAILURE:
+            ex = new SocketException("SOCKS server general failure");
+            break;
+        case NOT_ALLOWED:
+            ex = new SocketException("SOCKS: Connection not allowed by ruleset");
+            break;
+        case NET_UNREACHABLE:
+            ex = new SocketException("SOCKS: Network unreachable");
+            break;
+        case HOST_UNREACHABLE:
+            ex = new SocketException("SOCKS: Host unreachable");
+            break;
+        case CONN_REFUSED:
+            ex = new SocketException("SOCKS: Connection refused");
+            break;
+        case TTL_EXPIRED:
+            ex =  new SocketException("SOCKS: TTL expired");
+            break;
+        case CMD_NOT_SUPPORTED:
+            ex = new SocketException("SOCKS: Command not supported");
+            break;
+        case ADDR_TYPE_NOT_SUP:
+            ex = new SocketException("SOCKS: address type not supported");
+            break;
+        }
+        if (ex != null) {
+            in.close();
+            out.close();
+            throw ex;
+        }
+        external_address = epoint;
+    }
+
+    // Android-removed: Dead code. bindV4, socksBind, acceptFrom methods.
+    /*
+    private void bindV4(InputStream in, OutputStream out,
+                        InetAddress baddr,
+                        int lport) throws IOException {
+        if (!(baddr instanceof Inet4Address)) {
+            throw new SocketException("SOCKS V4 requires IPv4 only addresses");
+        }
+        super.bind(baddr, lport);
+        byte[] addr1 = baddr.getAddress();
+        /* Test for AnyLocal *
+        InetAddress naddr = baddr;
+        if (naddr.isAnyLocalAddress()) {
+            naddr = AccessController.doPrivileged(
+                        new PrivilegedAction<InetAddress>() {
+                            public InetAddress run() {
+                                return cmdsock.getLocalAddress();
+
+                            }
+                        });
+            addr1 = naddr.getAddress();
+        }
+        out.write(PROTO_VERS4);
+        out.write(BIND);
+        out.write((super.getLocalPort() >> 8) & 0xff);
+        out.write((super.getLocalPort() >> 0) & 0xff);
+        out.write(addr1);
+        String userName = getUserName();
+        try {
+            out.write(userName.getBytes("ISO-8859-1"));
+        } catch (java.io.UnsupportedEncodingException uee) {
+            assert false;
+        }
+        out.write(0);
+        out.flush();
+        byte[] data = new byte[8];
+        int n = readSocksReply(in, data);
+        if (n != 8)
+            throw new SocketException("Reply from SOCKS server has bad length: " + n);
+        if (data[0] != 0 && data[0] != 4)
+            throw new SocketException("Reply from SOCKS server has bad version");
+        SocketException ex = null;
+        switch (data[1]) {
+        case 90:
+            // Success!
+            external_address = new InetSocketAddress(baddr, lport);
+            break;
+        case 91:
+            ex = new SocketException("SOCKS request rejected");
+            break;
+        case 92:
+            ex = new SocketException("SOCKS server couldn't reach destination");
+            break;
+        case 93:
+            ex = new SocketException("SOCKS authentication failed");
+            break;
+        default:
+            ex = new SocketException("Reply from SOCKS server contains bad status");
+            break;
+        }
+        if (ex != null) {
+            in.close();
+            out.close();
+            throw ex;
+        }
+
+    }
+
+    /**
+     * Sends the Bind request to the SOCKS proxy. In the SOCKS protocol, bind
+     * means "accept incoming connection from", so the SocketAddress is the
+     * the one of the host we do accept connection from.
+     *
+     * @param      saddr   the Socket address of the remote host.
+     * @exception  IOException  if an I/O error occurs when binding this socket.
+     *
+    protected synchronized void socksBind(InetSocketAddress saddr) throws IOException {
+        if (socket != null) {
+            // this is a client socket, not a server socket, don't
+            // call the SOCKS proxy for a bind!
+            return;
+        }
+
+        // Connects to the SOCKS server
+
+        if (server == null) {
+            // This is the general case
+            // server is not null only when the socket was created with a
+            // specified proxy in which case it does bypass the ProxySelector
+            ProxySelector sel = java.security.AccessController.doPrivileged(
+                new java.security.PrivilegedAction<ProxySelector>() {
+                    public ProxySelector run() {
+                            return ProxySelector.getDefault();
+                        }
+                    });
+            if (sel == null) {
+                /*
+                 * No default proxySelector --> direct connection
+                 *
+                return;
+            }
+            URI uri;
+            // Use getHostString() to avoid reverse lookups
+            String host = saddr.getHostString();
+            // IPv6 litteral?
+            if (saddr.getAddress() instanceof Inet6Address &&
+                (!host.startsWith("[")) && (host.indexOf(":") >= 0)) {
+                host = "[" + host + "]";
+            }
+            try {
+                uri = new URI("serversocket://" + ParseUtil.encodePath(host) + ":"+ saddr.getPort());
+            } catch (URISyntaxException e) {
+                // This shouldn't happen
+                assert false : e;
+                uri = null;
+            }
+            Proxy p = null;
+            Exception savedExc = null;
+            java.util.Iterator<Proxy> iProxy = null;
+            iProxy = sel.select(uri).iterator();
+            if (iProxy == null || !(iProxy.hasNext())) {
+                return;
+            }
+            while (iProxy.hasNext()) {
+                p = iProxy.next();
+                if (p == null || p.type() != Proxy.Type.SOCKS) {
+                    return;
+                }
+
+                if (!(p.address() instanceof InetSocketAddress))
+                    throw new SocketException("Unknown address type for proxy: " + p);
+                // Use getHostString() to avoid reverse lookups
+                server = ((InetSocketAddress) p.address()).getHostString();
+                serverPort = ((InetSocketAddress) p.address()).getPort();
+                if (p instanceof SocksProxy) {
+                    if (((SocksProxy)p).protocolVersion() == 4) {
+                        useV4 = true;
+                    }
+                }
+
+                // Connects to the SOCKS server
+                try {
+                    AccessController.doPrivileged(
+                        new PrivilegedExceptionAction<Void>() {
+                            public Void run() throws Exception {
+                                cmdsock = new Socket(new PlainSocketImpl());
+                                cmdsock.connect(new InetSocketAddress(server, serverPort));
+                                cmdIn = cmdsock.getInputStream();
+                                cmdOut = cmdsock.getOutputStream();
+                                return null;
+                            }
+                        });
+                } catch (Exception e) {
+                    // Ooops, let's notify the ProxySelector
+                    sel.connectFailed(uri,p.address(),new SocketException(e.getMessage()));
+                    server = null;
+                    serverPort = -1;
+                    cmdsock = null;
+                    savedExc = e;
+                    // Will continue the while loop and try the next proxy
+                }
+            }
+
+            /*
+             * If server is still null at this point, none of the proxy
+             * worked
+             *
+            if (server == null || cmdsock == null) {
+                throw new SocketException("Can't connect to SOCKS proxy:"
+                                          + savedExc.getMessage());
+            }
+        } else {
+            try {
+                AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<Void>() {
+                        public Void run() throws Exception {
+                            cmdsock = new Socket(new PlainSocketImpl());
+                            cmdsock.connect(new InetSocketAddress(server, serverPort));
+                            cmdIn = cmdsock.getInputStream();
+                            cmdOut = cmdsock.getOutputStream();
+                            return null;
+                        }
+                    });
+            } catch (Exception e) {
+                throw new SocketException(e.getMessage());
+            }
+        }
+        BufferedOutputStream out = new BufferedOutputStream(cmdOut, 512);
+        InputStream in = cmdIn;
+        if (useV4) {
+            bindV4(in, out, saddr.getAddress(), saddr.getPort());
+            return;
+        }
+        out.write(PROTO_VERS);
+        out.write(2);
+        out.write(NO_AUTH);
+        out.write(USER_PASSW);
+        out.flush();
+        byte[] data = new byte[2];
+        int i = readSocksReply(in, data);
+        if (i != 2 || ((int)data[0]) != PROTO_VERS) {
+            // Maybe it's not a V5 sever after all
+            // Let's try V4 before we give up
+            bindV4(in, out, saddr.getAddress(), saddr.getPort());
+            return;
+        }
+        if (((int)data[1]) == NO_METHODS)
+            throw new SocketException("SOCKS : No acceptable methods");
+        if (!authenticate(data[1], in, out)) {
+            throw new SocketException("SOCKS : authentication failed");
+        }
+        // We're OK. Let's issue the BIND command.
+        out.write(PROTO_VERS);
+        out.write(BIND);
+        out.write(0);
+        int lport = saddr.getPort();
+        if (saddr.isUnresolved()) {
+            out.write(DOMAIN_NAME);
+            out.write(saddr.getHostName().length());
+            try {
+                out.write(saddr.getHostName().getBytes("ISO-8859-1"));
+            } catch (java.io.UnsupportedEncodingException uee) {
+                assert false;
+            }
+            out.write((lport >> 8) & 0xff);
+            out.write((lport >> 0) & 0xff);
+        } else if (saddr.getAddress() instanceof Inet4Address) {
+            byte[] addr1 = saddr.getAddress().getAddress();
+            out.write(IPV4);
+            out.write(addr1);
+            out.write((lport >> 8) & 0xff);
+            out.write((lport >> 0) & 0xff);
+            out.flush();
+        } else if (saddr.getAddress() instanceof Inet6Address) {
+            byte[] addr1 = saddr.getAddress().getAddress();
+            out.write(IPV6);
+            out.write(addr1);
+            out.write((lport >> 8) & 0xff);
+            out.write((lport >> 0) & 0xff);
+            out.flush();
+        } else {
+            cmdsock.close();
+            throw new SocketException("unsupported address type : " + saddr);
+        }
+        data = new byte[4];
+        i = readSocksReply(in, data);
+        SocketException ex = null;
+        int len, nport;
+        byte[] addr;
+        switch (data[1]) {
+        case REQUEST_OK:
+            // success!
+            switch(data[3]) {
+            case IPV4:
+                addr = new byte[4];
+                i = readSocksReply(in, addr);
+                if (i != 4)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                data = new byte[2];
+                i = readSocksReply(in, data);
+                if (i != 2)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                nport = ((int)data[0] & 0xff) << 8;
+                nport += ((int)data[1] & 0xff);
+                external_address =
+                    new InetSocketAddress(new Inet4Address("", addr) , nport);
+                break;
+            case DOMAIN_NAME:
+                len = data[1];
+                byte[] host = new byte[len];
+                i = readSocksReply(in, host);
+                if (i != len)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                data = new byte[2];
+                i = readSocksReply(in, data);
+                if (i != 2)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                nport = ((int)data[0] & 0xff) << 8;
+                nport += ((int)data[1] & 0xff);
+                external_address = new InetSocketAddress(new String(host), nport);
+                break;
+            case IPV6:
+                len = data[1];
+                addr = new byte[len];
+                i = readSocksReply(in, addr);
+                if (i != len)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                data = new byte[2];
+                i = readSocksReply(in, data);
+                if (i != 2)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                nport = ((int)data[0] & 0xff) << 8;
+                nport += ((int)data[1] & 0xff);
+                external_address =
+                    new InetSocketAddress(new Inet6Address("", addr), nport);
+                break;
+            }
+            break;
+        case GENERAL_FAILURE:
+            ex = new SocketException("SOCKS server general failure");
+            break;
+        case NOT_ALLOWED:
+            ex = new SocketException("SOCKS: Bind not allowed by ruleset");
+            break;
+        case NET_UNREACHABLE:
+            ex = new SocketException("SOCKS: Network unreachable");
+            break;
+        case HOST_UNREACHABLE:
+            ex = new SocketException("SOCKS: Host unreachable");
+            break;
+        case CONN_REFUSED:
+            ex = new SocketException("SOCKS: Connection refused");
+            break;
+        case TTL_EXPIRED:
+            ex =  new SocketException("SOCKS: TTL expired");
+            break;
+        case CMD_NOT_SUPPORTED:
+            ex = new SocketException("SOCKS: Command not supported");
+            break;
+        case ADDR_TYPE_NOT_SUP:
+            ex = new SocketException("SOCKS: address type not supported");
+            break;
+        }
+        if (ex != null) {
+            in.close();
+            out.close();
+            cmdsock.close();
+            cmdsock = null;
+            throw ex;
+        }
+        cmdIn = in;
+        cmdOut = out;
+    }
+
+    /**
+     * Accepts a connection from a specific host.
+     *
+     * @param      s   the accepted connection.
+     * @param      saddr the socket address of the host we do accept
+     *               connection from
+     * @exception  IOException  if an I/O error occurs when accepting the
+     *               connection.
+     *
+    protected void acceptFrom(SocketImpl s, InetSocketAddress saddr) throws IOException {
+        if (cmdsock == null) {
+            // Not a Socks ServerSocket.
+            return;
+        }
+        InputStream in = cmdIn;
+        // Sends the "SOCKS BIND" request.
+        socksBind(saddr);
+        in.read();
+        int i = in.read();
+        in.read();
+        SocketException ex = null;
+        int nport;
+        byte[] addr;
+        InetSocketAddress real_end = null;
+        switch (i) {
+        case REQUEST_OK:
+            // success!
+            i = in.read();
+            switch(i) {
+            case IPV4:
+                addr = new byte[4];
+                readSocksReply(in, addr);
+                nport = in.read() << 8;
+                nport += in.read();
+                real_end =
+                    new InetSocketAddress(new Inet4Address("", addr) , nport);
+                break;
+            case DOMAIN_NAME:
+                int len = in.read();
+                addr = new byte[len];
+                readSocksReply(in, addr);
+                nport = in.read() << 8;
+                nport += in.read();
+                real_end = new InetSocketAddress(new String(addr), nport);
+                break;
+            case IPV6:
+                addr = new byte[16];
+                readSocksReply(in, addr);
+                nport = in.read() << 8;
+                nport += in.read();
+                real_end =
+                    new InetSocketAddress(new Inet6Address("", addr), nport);
+                break;
+            }
+            break;
+        case GENERAL_FAILURE:
+            ex = new SocketException("SOCKS server general failure");
+            break;
+        case NOT_ALLOWED:
+            ex = new SocketException("SOCKS: Accept not allowed by ruleset");
+            break;
+        case NET_UNREACHABLE:
+            ex = new SocketException("SOCKS: Network unreachable");
+            break;
+        case HOST_UNREACHABLE:
+            ex = new SocketException("SOCKS: Host unreachable");
+            break;
+        case CONN_REFUSED:
+            ex = new SocketException("SOCKS: Connection refused");
+            break;
+        case TTL_EXPIRED:
+            ex =  new SocketException("SOCKS: TTL expired");
+            break;
+        case CMD_NOT_SUPPORTED:
+            ex = new SocketException("SOCKS: Command not supported");
+            break;
+        case ADDR_TYPE_NOT_SUP:
+            ex = new SocketException("SOCKS: address type not supported");
+            break;
+        }
+        if (ex != null) {
+            cmdIn.close();
+            cmdOut.close();
+            cmdsock.close();
+            cmdsock = null;
+            throw ex;
+        }
+
+        /**
+         * This is where we have to do some fancy stuff.
+         * The datastream from the socket "accepted" by the proxy will
+         * come through the cmdSocket. So we have to swap the socketImpls
+         *
+        if (s instanceof SocksSocketImpl) {
+            ((SocksSocketImpl)s).external_address = real_end;
+        }
+        if (s instanceof PlainSocketImpl) {
+            PlainSocketImpl psi = (PlainSocketImpl) s;
+            psi.setInputStream((SocketInputStream) in);
+            psi.setFileDescriptor(cmdsock.getImpl().getFileDescriptor());
+            psi.setAddress(cmdsock.getImpl().getInetAddress());
+            psi.setPort(cmdsock.getImpl().getPort());
+            psi.setLocalPort(cmdsock.getImpl().getLocalPort());
+        } else {
+            s.fd = cmdsock.getImpl().fd;
+            s.address = cmdsock.getImpl().address;
+            s.port = cmdsock.getImpl().port;
+            s.localport = cmdsock.getImpl().localport;
+        }
+
+        // Need to do that so that the socket won't be closed
+        // when the ServerSocket is closed by the user.
+        // It kinds of detaches the Socket because it is now
+        // used elsewhere.
+        cmdsock = null;
+    }
+    */
+
+    /**
+     * Returns the value of this socket's {@code address} field.
+     *
+     * @return  the value of this socket's {@code address} field.
+     * @see     java.net.SocketImpl#address
+     */
+    @Override
+    protected InetAddress getInetAddress() {
+        if (external_address != null)
+            return external_address.getAddress();
+        else
+            return super.getInetAddress();
+    }
+
+    /**
+     * Returns the value of this socket's {@code port} field.
+     *
+     * @return  the value of this socket's {@code port} field.
+     * @see     java.net.SocketImpl#port
+     */
+    @Override
+    protected int getPort() {
+        if (external_address != null)
+            return external_address.getPort();
+        else
+            return super.getPort();
+    }
+
+    @Override
+    protected int getLocalPort() {
+        if (socket != null)
+            return super.getLocalPort();
+        if (external_address != null)
+            return external_address.getPort();
+        else
+            return super.getLocalPort();
+    }
+
+    @Override
+    protected void close() throws IOException {
+        if (cmdsock != null)
+            cmdsock.close();
+        cmdsock = null;
+        super.close();
+    }
+
+    private String getUserName() {
+        String userName = "";
+        if (applicationSetProxy) {
+            try {
+                userName = System.getProperty("user.name");
+            } catch (SecurityException se) { /* swallow Exception */ }
+        } else {
+            userName = java.security.AccessController.doPrivileged(
+                new sun.security.action.GetPropertyAction("user.name"));
+        }
+        return userName;
+    }
+}
diff --git a/java/net/StandardProtocolFamily.java b/java/net/StandardProtocolFamily.java
new file mode 100644
index 0000000..25aaed4
--- /dev/null
+++ b/java/net/StandardProtocolFamily.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * Defines the standard families of communication protocols.
+ *
+ * @since 1.7
+ */
+
+public enum StandardProtocolFamily implements ProtocolFamily {
+
+    /**
+     * Internet Protocol Version 4 (IPv4)
+     */
+    INET,
+
+    /**
+     * Internet Protocol Version 6 (IPv6)
+     */
+    INET6
+}
diff --git a/java/net/StandardSocketOptions.java b/java/net/StandardSocketOptions.java
new file mode 100644
index 0000000..7fdd5f0
--- /dev/null
+++ b/java/net/StandardSocketOptions.java
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * Defines the <em>standard</em> socket options.
+ *
+ * <p> The {@link SocketOption#name name} of each socket option defined by this
+ * class is its field name.
+ *
+ * <p> In this release, the socket options defined here are used by {@link
+ * java.nio.channels.NetworkChannel network} channels in the {@link
+ * java.nio.channels channels} package.
+ *
+ * @since 1.7
+ */
+
+public final class StandardSocketOptions {
+    private StandardSocketOptions() { }
+
+    // -- SOL_SOCKET --
+
+    /**
+     * Allow transmission of broadcast datagrams.
+     *
+     * <p> The value of this socket option is a {@code Boolean} that represents
+     * whether the option is enabled or disabled. The option is specific to
+     * datagram-oriented sockets sending to {@link java.net.Inet4Address IPv4}
+     * broadcast addresses. When the socket option is enabled then the socket
+     * can be used to send <em>broadcast datagrams</em>.
+     *
+     * <p> The initial value of this socket option is {@code FALSE}. The socket
+     * option may be enabled or disabled at any time. Some operating systems may
+     * require that the Java virtual machine be started with implementation
+     * specific privileges to enable this option or send broadcast datagrams.
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc919.txt">RFC&nbsp;929:
+     * Broadcasting Internet Datagrams</a>
+     * @see DatagramSocket#setBroadcast
+     */
+    public static final SocketOption<Boolean> SO_BROADCAST =
+        new StdSocketOption<Boolean>("SO_BROADCAST", Boolean.class);
+
+    /**
+     * Keep connection alive.
+     *
+     * <p> The value of this socket option is a {@code Boolean} that represents
+     * whether the option is enabled or disabled. When the {@code SO_KEEPALIVE}
+     * option is enabled the operating system may use a <em>keep-alive</em>
+     * mechanism to periodically probe the other end of a connection when the
+     * connection is otherwise idle. The exact semantics of the keep alive
+     * mechanism is system dependent and therefore unspecified.
+     *
+     * <p> The initial value of this socket option is {@code FALSE}. The socket
+     * option may be enabled or disabled at any time.
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc1122.txt">RFC&nbsp;1122
+     * Requirements for Internet Hosts -- Communication Layers</a>
+     * @see Socket#setKeepAlive
+     */
+    public static final SocketOption<Boolean> SO_KEEPALIVE =
+        new StdSocketOption<Boolean>("SO_KEEPALIVE", Boolean.class);
+
+    /**
+     * The size of the socket send buffer.
+     *
+     * <p> The value of this socket option is an {@code Integer} that is the
+     * size of the socket send buffer in bytes. The socket send buffer is an
+     * output buffer used by the networking implementation. It may need to be
+     * increased for high-volume connections. The value of the socket option is
+     * a <em>hint</em> to the implementation to size the buffer and the actual
+     * size may differ. The socket option can be queried to retrieve the actual
+     * size.
+     *
+     * <p> For datagram-oriented sockets, the size of the send buffer may limit
+     * the size of the datagrams that may be sent by the socket. Whether
+     * datagrams larger than the buffer size are sent or discarded is system
+     * dependent.
+     *
+     * <p> The initial/default size of the socket send buffer and the range of
+     * allowable values is system dependent although a negative size is not
+     * allowed. An attempt to set the socket send buffer to larger than its
+     * maximum size causes it to be set to its maximum size.
+     *
+     * <p> An implementation allows this socket option to be set before the
+     * socket is bound or connected. Whether an implementation allows the
+     * socket send buffer to be changed after the socket is bound is system
+     * dependent.
+     *
+     * @see Socket#setSendBufferSize
+     */
+    public static final SocketOption<Integer> SO_SNDBUF =
+        new StdSocketOption<Integer>("SO_SNDBUF", Integer.class);
+
+
+    /**
+     * The size of the socket receive buffer.
+     *
+     * <p> The value of this socket option is an {@code Integer} that is the
+     * size of the socket receive buffer in bytes. The socket receive buffer is
+     * an input buffer used by the networking implementation. It may need to be
+     * increased for high-volume connections or decreased to limit the possible
+     * backlog of incoming data. The value of the socket option is a
+     * <em>hint</em> to the implementation to size the buffer and the actual
+     * size may differ.
+     *
+     * <p> For datagram-oriented sockets, the size of the receive buffer may
+     * limit the size of the datagrams that can be received. Whether datagrams
+     * larger than the buffer size can be received is system dependent.
+     * Increasing the socket receive buffer may be important for cases where
+     * datagrams arrive in bursts faster than they can be processed.
+     *
+     * <p> In the case of stream-oriented sockets and the TCP/IP protocol, the
+     * size of the socket receive buffer may be used when advertising the size
+     * of the TCP receive window to the remote peer.
+     *
+     * <p> The initial/default size of the socket receive buffer and the range
+     * of allowable values is system dependent although a negative size is not
+     * allowed. An attempt to set the socket receive buffer to larger than its
+     * maximum size causes it to be set to its maximum size.
+     *
+     * <p> An implementation allows this socket option to be set before the
+     * socket is bound or connected. Whether an implementation allows the
+     * socket receive buffer to be changed after the socket is bound is system
+     * dependent.
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc1323.txt">RFC&nbsp;1323: TCP
+     * Extensions for High Performance</a>
+     * @see Socket#setReceiveBufferSize
+     * @see ServerSocket#setReceiveBufferSize
+     */
+    public static final SocketOption<Integer> SO_RCVBUF =
+        new StdSocketOption<Integer>("SO_RCVBUF", Integer.class);
+
+    /**
+     * Re-use address.
+     *
+     * <p> The value of this socket option is a {@code Boolean} that represents
+     * whether the option is enabled or disabled. The exact semantics of this
+     * socket option are socket type and system dependent.
+     *
+     * <p> In the case of stream-oriented sockets, this socket option will
+     * usually determine whether the socket can be bound to a socket address
+     * when a previous connection involving that socket address is in the
+     * <em>TIME_WAIT</em> state. On implementations where the semantics differ,
+     * and the socket option is not required to be enabled in order to bind the
+     * socket when a previous connection is in this state, then the
+     * implementation may choose to ignore this option.
+     *
+     * <p> For datagram-oriented sockets the socket option is used to allow
+     * multiple programs bind to the same address. This option should be enabled
+     * when the socket is to be used for Internet Protocol (IP) multicasting.
+     *
+     * <p> An implementation allows this socket option to be set before the
+     * socket is bound or connected. Changing the value of this socket option
+     * after the socket is bound has no effect. The default value of this
+     * socket option is system dependent.
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc793.txt">RFC&nbsp;793: Transmission
+     * Control Protocol</a>
+     * @see ServerSocket#setReuseAddress
+     */
+    public static final SocketOption<Boolean> SO_REUSEADDR =
+        new StdSocketOption<Boolean>("SO_REUSEADDR", Boolean.class);
+
+    /**
+     * Linger on close if data is present.
+     *
+     * <p> The value of this socket option is an {@code Integer} that controls
+     * the action taken when unsent data is queued on the socket and a method
+     * to close the socket is invoked. If the value of the socket option is zero
+     * or greater, then it represents a timeout value, in seconds, known as the
+     * <em>linger interval</em>. The linger interval is the timeout for the
+     * {@code close} method to block while the operating system attempts to
+     * transmit the unsent data or it decides that it is unable to transmit the
+     * data. If the value of the socket option is less than zero then the option
+     * is disabled. In that case the {@code close} method does not wait until
+     * unsent data is transmitted; if possible the operating system will transmit
+     * any unsent data before the connection is closed.
+     *
+     * <p> This socket option is intended for use with sockets that are configured
+     * in {@link java.nio.channels.SelectableChannel#isBlocking() blocking} mode
+     * only. The behavior of the {@code close} method when this option is
+     * enabled on a non-blocking socket is not defined.
+     *
+     * <p> The initial value of this socket option is a negative value, meaning
+     * that the option is disabled. The option may be enabled, or the linger
+     * interval changed, at any time. The maximum value of the linger interval
+     * is system dependent. Setting the linger interval to a value that is
+     * greater than its maximum value causes the linger interval to be set to
+     * its maximum value.
+     *
+     * @see Socket#setSoLinger
+     */
+    public static final SocketOption<Integer> SO_LINGER =
+        new StdSocketOption<Integer>("SO_LINGER", Integer.class);
+
+
+    // -- IPPROTO_IP --
+
+    /**
+     * The Type of Service (ToS) octet in the Internet Protocol (IP) header.
+     *
+     * <p> The value of this socket option is an {@code Integer} representing
+     * the value of the ToS octet in IP packets sent by sockets to an {@link
+     * StandardProtocolFamily#INET IPv4} socket. The interpretation of the ToS
+     * octet is network specific and is not defined by this class. Further
+     * information on the ToS octet can be found in <a
+     * href="http://www.ietf.org/rfc/rfc1349.txt">RFC&nbsp;1349</a> and <a
+     * href="http://www.ietf.org/rfc/rfc2474.txt">RFC&nbsp;2474</a>. The value
+     * of the socket option is a <em>hint</em>. An implementation may ignore the
+     * value, or ignore specific values.
+     *
+     * <p> The initial/default value of the TOS field in the ToS octet is
+     * implementation specific but will typically be {@code 0}. For
+     * datagram-oriented sockets the option may be configured at any time after
+     * the socket has been bound. The new value of the octet is used when sending
+     * subsequent datagrams. It is system dependent whether this option can be
+     * queried or changed prior to binding the socket.
+     *
+     * <p> The behavior of this socket option on a stream-oriented socket, or an
+     * {@link StandardProtocolFamily#INET6 IPv6} socket, is not defined in this
+     * release.
+     *
+     * @see DatagramSocket#setTrafficClass
+     */
+    public static final SocketOption<Integer> IP_TOS =
+        new StdSocketOption<Integer>("IP_TOS", Integer.class);
+
+    /**
+     * The network interface for Internet Protocol (IP) multicast datagrams.
+     *
+     * <p> The value of this socket option is a {@link NetworkInterface} that
+     * represents the outgoing interface for multicast datagrams sent by the
+     * datagram-oriented socket. For {@link StandardProtocolFamily#INET6 IPv6}
+     * sockets then it is system dependent whether setting this option also
+     * sets the outgoing interface for multicast datagrams sent to IPv4
+     * addresses.
+     *
+     * <p> The initial/default value of this socket option may be {@code null}
+     * to indicate that outgoing interface will be selected by the operating
+     * system, typically based on the network routing tables. An implementation
+     * allows this socket option to be set after the socket is bound. Whether
+     * the socket option can be queried or changed prior to binding the socket
+     * is system dependent.
+     *
+     * @see java.nio.channels.MulticastChannel
+     * @see MulticastSocket#setInterface
+     */
+    public static final SocketOption<NetworkInterface> IP_MULTICAST_IF =
+        new StdSocketOption<NetworkInterface>("IP_MULTICAST_IF", NetworkInterface.class);
+
+    /**
+     * The <em>time-to-live</em> for Internet Protocol (IP) multicast datagrams.
+     *
+     * <p> The value of this socket option is an {@code Integer} in the range
+     * {@code 0 <= value <= 255}. It is used to control the scope of multicast
+     * datagrams sent by the datagram-oriented socket.
+     * In the case of an {@link StandardProtocolFamily#INET IPv4} socket
+     * the option is the time-to-live (TTL) on multicast datagrams sent by the
+     * socket. Datagrams with a TTL of zero are not transmitted on the network
+     * but may be delivered locally. In the case of an {@link
+     * StandardProtocolFamily#INET6 IPv6} socket the option is the
+     * <em>hop limit</em> which is number of <em>hops</em> that the datagram can
+     * pass through before expiring on the network. For IPv6 sockets it is
+     * system dependent whether the option also sets the <em>time-to-live</em>
+     * on multicast datagrams sent to IPv4 addresses.
+     *
+     * <p> The initial/default value of the time-to-live setting is typically
+     * {@code 1}. An implementation allows this socket option to be set after
+     * the socket is bound. Whether the socket option can be queried or changed
+     * prior to binding the socket is system dependent.
+     *
+     * @see java.nio.channels.MulticastChannel
+     * @see MulticastSocket#setTimeToLive
+     */
+    public static final SocketOption<Integer> IP_MULTICAST_TTL =
+        new StdSocketOption<Integer>("IP_MULTICAST_TTL", Integer.class);
+
+    /**
+     * Loopback for Internet Protocol (IP) multicast datagrams.
+     *
+     * <p> The value of this socket option is a {@code Boolean} that controls
+     * the <em>loopback</em> of multicast datagrams. The value of the socket
+     * option represents if the option is enabled or disabled.
+     *
+     * <p> The exact semantics of this socket options are system dependent.
+     * In particular, it is system dependent whether the loopback applies to
+     * multicast datagrams sent from the socket or received by the socket.
+     * For {@link StandardProtocolFamily#INET6 IPv6} sockets then it is
+     * system dependent whether the option also applies to multicast datagrams
+     * sent to IPv4 addresses.
+     *
+     * <p> The initial/default value of this socket option is {@code TRUE}. An
+     * implementation allows this socket option to be set after the socket is
+     * bound. Whether the socket option can be queried or changed prior to
+     * binding the socket is system dependent.
+     *
+     * @see java.nio.channels.MulticastChannel
+     *  @see MulticastSocket#setLoopbackMode
+     */
+    public static final SocketOption<Boolean> IP_MULTICAST_LOOP =
+        new StdSocketOption<Boolean>("IP_MULTICAST_LOOP", Boolean.class);
+
+
+    // -- IPPROTO_TCP --
+
+    /**
+     * Disable the Nagle algorithm.
+     *
+     * <p> The value of this socket option is a {@code Boolean} that represents
+     * whether the option is enabled or disabled. The socket option is specific to
+     * stream-oriented sockets using the TCP/IP protocol. TCP/IP uses an algorithm
+     * known as <em>The Nagle Algorithm</em> to coalesce short segments and
+     * improve network efficiency.
+     *
+     * <p> The default value of this socket option is {@code FALSE}. The
+     * socket option should only be enabled in cases where it is known that the
+     * coalescing impacts performance. The socket option may be enabled at any
+     * time. In other words, the Nagle Algorithm can be disabled. Once the option
+     * is enabled, it is system dependent whether it can be subsequently
+     * disabled. If it cannot, then invoking the {@code setOption} method to
+     * disable the option has no effect.
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc1122.txt">RFC&nbsp;1122:
+     * Requirements for Internet Hosts -- Communication Layers</a>
+     * @see Socket#setTcpNoDelay
+     */
+    public static final SocketOption<Boolean> TCP_NODELAY =
+        new StdSocketOption<Boolean>("TCP_NODELAY", Boolean.class);
+
+
+    private static class StdSocketOption<T> implements SocketOption<T> {
+        private final String name;
+        private final Class<T> type;
+        StdSocketOption(String name, Class<T> type) {
+            this.name = name;
+            this.type = type;
+        }
+        @Override public String name() { return name; }
+        @Override public Class<T> type() { return type; }
+        @Override public String toString() { return name; }
+    }
+}
diff --git a/java/net/URI.java b/java/net/URI.java
new file mode 100644
index 0000000..ebba41b
--- /dev/null
+++ b/java/net/URI.java
@@ -0,0 +1,3602 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.CharacterCodingException;
+import java.text.Normalizer;
+import sun.nio.cs.ThreadLocalCoders;
+
+import java.lang.Character;             // for javadoc
+import java.lang.NullPointerException;  // for javadoc
+
+
+// Android-changed: Reformat @see links.
+/**
+ * Represents a Uniform Resource Identifier (URI) reference.
+ *
+ * <p> Aside from some minor deviations noted below, an instance of this
+ * class represents a URI reference as defined by
+ * <a href="http://www.ietf.org/rfc/rfc2396.txt"><i>RFC&nbsp;2396: Uniform
+ * Resource Identifiers (URI): Generic Syntax</i></a>, amended by <a
+ * href="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC&nbsp;2732: Format for
+ * Literal IPv6 Addresses in URLs</i></a>. The Literal IPv6 address format
+ * also supports scope_ids. The syntax and usage of scope_ids is described
+ * <a href="Inet6Address.html#scoped">here</a>.
+ * This class provides constructors for creating URI instances from
+ * their components or by parsing their string forms, methods for accessing the
+ * various components of an instance, and methods for normalizing, resolving,
+ * and relativizing URI instances.  Instances of this class are immutable.
+ *
+ *
+ * <h3> URI syntax and components </h3>
+ *
+ * At the highest level a URI reference (hereinafter simply "URI") in string
+ * form has the syntax
+ *
+ * <blockquote>
+ * [<i>scheme</i><b>{@code :}</b>]<i>scheme-specific-part</i>[<b>{@code #}</b><i>fragment</i>]
+ * </blockquote>
+ *
+ * where square brackets [...] delineate optional components and the characters
+ * <b>{@code :}</b> and <b>{@code #}</b> stand for themselves.
+ *
+ * <p> An <i>absolute</i> URI specifies a scheme; a URI that is not absolute is
+ * said to be <i>relative</i>.  URIs are also classified according to whether
+ * they are <i>opaque</i> or <i>hierarchical</i>.
+ *
+ * <p> An <i>opaque</i> URI is an absolute URI whose scheme-specific part does
+ * not begin with a slash character ({@code '/'}).  Opaque URIs are not
+ * subject to further parsing.  Some examples of opaque URIs are:
+ *
+ * <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
+ * <tr><td>{@code mailto:[email protected]}<td></tr>
+ * <tr><td>{@code news:comp.lang.java}<td></tr>
+ * <tr><td>{@code urn:isbn:096139210x}</td></tr>
+ * </table></blockquote>
+ *
+ * <p> A <i>hierarchical</i> URI is either an absolute URI whose
+ * scheme-specific part begins with a slash character, or a relative URI, that
+ * is, a URI that does not specify a scheme.  Some examples of hierarchical
+ * URIs are:
+ *
+ * <blockquote>
+ * {@code http://java.sun.com/j2se/1.3/}<br>
+ * {@code docs/guide/collections/designfaq.html#28}<br>
+ * {@code ../../../demo/jfc/SwingSet2/src/SwingSet2.java}<br>
+ * {@code file:///~/calendar}
+ * </blockquote>
+ *
+ * <p> A hierarchical URI is subject to further parsing according to the syntax
+ *
+ * <blockquote>
+ * [<i>scheme</i><b>{@code :}</b>][<b>{@code //}</b><i>authority</i>][<i>path</i>][<b>{@code ?}</b><i>query</i>][<b>{@code #}</b><i>fragment</i>]
+ * </blockquote>
+ *
+ * where the characters <b>{@code :}</b>, <b>{@code /}</b>,
+ * <b>{@code ?}</b>, and <b>{@code #}</b> stand for themselves.  The
+ * scheme-specific part of a hierarchical URI consists of the characters
+ * between the scheme and fragment components.
+ *
+ * <p> The authority component of a hierarchical URI is, if specified, either
+ * <i>server-based</i> or <i>registry-based</i>.  A server-based authority
+ * parses according to the familiar syntax
+ *
+ * <blockquote>
+ * [<i>user-info</i><b>{@code @}</b>]<i>host</i>[<b>{@code :}</b><i>port</i>]
+ * </blockquote>
+ *
+ * where the characters <b>{@code @}</b> and <b>{@code :}</b> stand for
+ * themselves.  Nearly all URI schemes currently in use are server-based.  An
+ * authority component that does not parse in this way is considered to be
+ * registry-based.
+ *
+ * <p> The path component of a hierarchical URI is itself said to be absolute
+ * if it begins with a slash character ({@code '/'}); otherwise it is
+ * relative.  The path of a hierarchical URI that is either absolute or
+ * specifies an authority is always absolute.
+ *
+ * <p> All told, then, a URI instance has the following nine components:
+ *
+ * <blockquote><table summary="Describes the components of a URI:scheme,scheme-specific-part,authority,user-info,host,port,path,query,fragment">
+ * <tr><th><i>Component</i></th><th><i>Type</i></th></tr>
+ * <tr><td>scheme</td><td>{@code String}</td></tr>
+ * <tr><td>scheme-specific-part&nbsp;&nbsp;&nbsp;&nbsp;</td><td>{@code String}</td></tr>
+ * <tr><td>authority</td><td>{@code String}</td></tr>
+ * <tr><td>user-info</td><td>{@code String}</td></tr>
+ * <tr><td>host</td><td>{@code String}</td></tr>
+ * <tr><td>port</td><td>{@code int}</td></tr>
+ * <tr><td>path</td><td>{@code String}</td></tr>
+ * <tr><td>query</td><td>{@code String}</td></tr>
+ * <tr><td>fragment</td><td>{@code String}</td></tr>
+ * </table></blockquote>
+ *
+ * In a given instance any particular component is either <i>undefined</i> or
+ * <i>defined</i> with a distinct value.  Undefined string components are
+ * represented by {@code null}, while undefined integer components are
+ * represented by {@code -1}.  A string component may be defined to have the
+ * empty string as its value; this is not equivalent to that component being
+ * undefined.
+ *
+ * <p> Whether a particular component is or is not defined in an instance
+ * depends upon the type of the URI being represented.  An absolute URI has a
+ * scheme component.  An opaque URI has a scheme, a scheme-specific part, and
+ * possibly a fragment, but has no other components.  A hierarchical URI always
+ * has a path (though it may be empty) and a scheme-specific-part (which at
+ * least contains the path), and may have any of the other components.  If the
+ * authority component is present and is server-based then the host component
+ * will be defined and the user-information and port components may be defined.
+ *
+ *
+ * <h4> Operations on URI instances </h4>
+ *
+ * The key operations supported by this class are those of
+ * <i>normalization</i>, <i>resolution</i>, and <i>relativization</i>.
+ *
+ * <p> <i>Normalization</i> is the process of removing unnecessary {@code "."}
+ * and {@code ".."} segments from the path component of a hierarchical URI.
+ * Each {@code "."} segment is simply removed.  A {@code ".."} segment is
+ * removed only if it is preceded by a non-{@code ".."} segment.
+ * Normalization has no effect upon opaque URIs.
+ *
+ * <p> <i>Resolution</i> is the process of resolving one URI against another,
+ * <i>base</i> URI.  The resulting URI is constructed from components of both
+ * URIs in the manner specified by RFC&nbsp;2396, taking components from the
+ * base URI for those not specified in the original.  For hierarchical URIs,
+ * the path of the original is resolved against the path of the base and then
+ * normalized.  The result, for example, of resolving
+ *
+ * <blockquote>
+ * {@code docs/guide/collections/designfaq.html#28}
+ * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ * &nbsp;&nbsp;&nbsp;&nbsp;(1)
+ * </blockquote>
+ *
+ * against the base URI {@code http://java.sun.com/j2se/1.3/} is the result
+ * URI
+ *
+ * <blockquote>
+ * {@code http://java.sun.com/j2se/1.3/docs/guide/collections/designfaq.html#28}
+ * </blockquote>
+ *
+ * Resolving the relative URI
+ *
+ * <blockquote>
+ * {@code ../../../demo/jfc/SwingSet2/src/SwingSet2.java}&nbsp;&nbsp;&nbsp;&nbsp;(2)
+ * </blockquote>
+ *
+ * against this result yields, in turn,
+ *
+ * <blockquote>
+ * {@code http://java.sun.com/j2se/1.3/demo/jfc/SwingSet2/src/SwingSet2.java}
+ * </blockquote>
+ *
+ * Resolution of both absolute and relative URIs, and of both absolute and
+ * relative paths in the case of hierarchical URIs, is supported.  Resolving
+ * the URI {@code file:///~calendar} against any other URI simply yields the
+ * original URI, since it is absolute.  Resolving the relative URI (2) above
+ * against the relative base URI (1) yields the normalized, but still relative,
+ * URI
+ *
+ * <blockquote>
+ * {@code demo/jfc/SwingSet2/src/SwingSet2.java}
+ * </blockquote>
+ *
+ * <p> <i>Relativization</i>, finally, is the inverse of resolution: For any
+ * two normalized URIs <i>u</i> and&nbsp;<i>v</i>,
+ *
+ * <blockquote>
+ *   <i>u</i>{@code .relativize(}<i>u</i>{@code .resolve(}<i>v</i>{@code )).equals(}<i>v</i>{@code )}&nbsp;&nbsp;and<br>
+ *   <i>u</i>{@code .resolve(}<i>u</i>{@code .relativize(}<i>v</i>{@code )).equals(}<i>v</i>{@code )}&nbsp;&nbsp;.<br>
+ * </blockquote>
+ *
+ * This operation is often useful when constructing a document containing URIs
+ * that must be made relative to the base URI of the document wherever
+ * possible.  For example, relativizing the URI
+ *
+ * <blockquote>
+ * {@code http://java.sun.com/j2se/1.3/docs/guide/index.html}
+ * </blockquote>
+ *
+ * against the base URI
+ *
+ * <blockquote>
+ * {@code http://java.sun.com/j2se/1.3}
+ * </blockquote>
+ *
+ * yields the relative URI {@code docs/guide/index.html}.
+ *
+ *
+ * <h4> Character categories </h4>
+ *
+ * RFC&nbsp;2396 specifies precisely which characters are permitted in the
+ * various components of a URI reference.  The following categories, most of
+ * which are taken from that specification, are used below to describe these
+ * constraints:
+ *
+ * <blockquote><table cellspacing=2 summary="Describes categories alpha,digit,alphanum,unreserved,punct,reserved,escaped,and other">
+ *   <tr><th valign=top><i>alpha</i></th>
+ *       <td>The US-ASCII alphabetic characters,
+ *        {@code 'A'}&nbsp;through&nbsp;{@code 'Z'}
+ *        and {@code 'a'}&nbsp;through&nbsp;{@code 'z'}</td></tr>
+ *   <tr><th valign=top><i>digit</i></th>
+ *       <td>The US-ASCII decimal digit characters,
+ *       {@code '0'}&nbsp;through&nbsp;{@code '9'}</td></tr>
+ *   <tr><th valign=top><i>alphanum</i></th>
+ *       <td>All <i>alpha</i> and <i>digit</i> characters</td></tr>
+ *   <tr><th valign=top><i>unreserved</i>&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *       <td>All <i>alphanum</i> characters together with those in the string
+ *        {@code "_-!.~'()*"}</td></tr>
+ *   <tr><th valign=top><i>punct</i></th>
+ *       <td>The characters in the string {@code ",;:$&+="}</td></tr>
+ *   <tr><th valign=top><i>reserved</i></th>
+ *       <td>All <i>punct</i> characters together with those in the string
+ *        {@code "?/[]@"}</td></tr>
+ *   <tr><th valign=top><i>escaped</i></th>
+ *       <td>Escaped octets, that is, triplets consisting of the percent
+ *           character ({@code '%'}) followed by two hexadecimal digits
+ *           ({@code '0'}-{@code '9'}, {@code 'A'}-{@code 'F'}, and
+ *           {@code 'a'}-{@code 'f'})</td></tr>
+ *   <tr><th valign=top><i>other</i></th>
+ *       <td>The Unicode characters that are not in the US-ASCII character set,
+ *           are not control characters (according to the {@link
+ *           java.lang.Character#isISOControl(char) Character.isISOControl}
+ *           method), and are not space characters (according to the {@link
+ *           java.lang.Character#isSpaceChar(char) Character.isSpaceChar}
+ *           method)&nbsp;&nbsp;<i>(<b>Deviation from RFC 2396</b>, which is
+ *           limited to US-ASCII)</i></td></tr>
+ * </table></blockquote>
+ *
+ * <p><a name="legal-chars"></a> The set of all legal URI characters consists of
+ * the <i>unreserved</i>, <i>reserved</i>, <i>escaped</i>, and <i>other</i>
+ * characters.
+ *
+ *
+ * <h4> Escaped octets, quotation, encoding, and decoding </h4>
+ *
+ * RFC 2396 allows escaped octets to appear in the user-info, path, query, and
+ * fragment components.  Escaping serves two purposes in URIs:
+ *
+ * <ul>
+ *
+ *   <li><p> To <i>encode</i> non-US-ASCII characters when a URI is required to
+ *   conform strictly to RFC&nbsp;2396 by not containing any <i>other</i>
+ *   characters.  </p></li>
+ *
+ *   <li><p> To <i>quote</i> characters that are otherwise illegal in a
+ *   component.  The user-info, path, query, and fragment components differ
+ *   slightly in terms of which characters are considered legal and illegal.
+ *   </p></li>
+ *
+ * </ul>
+ *
+ * These purposes are served in this class by three related operations:
+ *
+ * <ul>
+ *
+ *   <li><p><a name="encode"></a> A character is <i>encoded</i> by replacing it
+ *   with the sequence of escaped octets that represent that character in the
+ *   UTF-8 character set.  The Euro currency symbol ({@code '\u005Cu20AC'}),
+ *   for example, is encoded as {@code "%E2%82%AC"}.  <i>(<b>Deviation from
+ *   RFC&nbsp;2396</b>, which does not specify any particular character
+ *   set.)</i> </p></li>
+ *
+ *   <li><p><a name="quote"></a> An illegal character is <i>quoted</i> simply by
+ *   encoding it.  The space character, for example, is quoted by replacing it
+ *   with {@code "%20"}.  UTF-8 contains US-ASCII, hence for US-ASCII
+ *   characters this transformation has exactly the effect required by
+ *   RFC&nbsp;2396. </p></li>
+ *
+ *   <li><p><a name="decode"></a>
+ *   A sequence of escaped octets is <i>decoded</i> by
+ *   replacing it with the sequence of characters that it represents in the
+ *   UTF-8 character set.  UTF-8 contains US-ASCII, hence decoding has the
+ *   effect of de-quoting any quoted US-ASCII characters as well as that of
+ *   decoding any encoded non-US-ASCII characters.  If a <a
+ *   href="../nio/charset/CharsetDecoder.html#ce">decoding error</a> occurs
+ *   when decoding the escaped octets then the erroneous octets are replaced by
+ *   {@code '\u005CuFFFD'}, the Unicode replacement character.  </p></li>
+ *
+ * </ul>
+ *
+ * These operations are exposed in the constructors and methods of this class
+ * as follows:
+ *
+ * <ul>
+ *
+ *   <li><p> The {@linkplain #URI(java.lang.String) single-argument
+ *   constructor} requires any illegal characters in its argument to be
+ *   quoted and preserves any escaped octets and <i>other</i> characters that
+ *   are present.  </p></li>
+ *
+ *   <li><p> The {@linkplain
+ *   #URI(java.lang.String,java.lang.String,java.lang.String,int,java.lang.String,java.lang.String,java.lang.String)
+ *   multi-argument constructors} quote illegal characters as
+ *   required by the components in which they appear.  The percent character
+ *   ({@code '%'}) is always quoted by these constructors.  Any <i>other</i>
+ *   characters are preserved.  </p></li>
+ *
+ *   <li><p> The {@link #getRawUserInfo() getRawUserInfo}, {@link #getRawPath()
+ *   getRawPath}, {@link #getRawQuery() getRawQuery}, {@link #getRawFragment()
+ *   getRawFragment}, {@link #getRawAuthority() getRawAuthority}, and {@link
+ *   #getRawSchemeSpecificPart() getRawSchemeSpecificPart} methods return the
+ *   values of their corresponding components in raw form, without interpreting
+ *   any escaped octets.  The strings returned by these methods may contain
+ *   both escaped octets and <i>other</i> characters, and will not contain any
+ *   illegal characters.  </p></li>
+ *
+ *   <li><p> The {@link #getUserInfo() getUserInfo}, {@link #getPath()
+ *   getPath}, {@link #getQuery() getQuery}, {@link #getFragment()
+ *   getFragment}, {@link #getAuthority() getAuthority}, and {@link
+ *   #getSchemeSpecificPart() getSchemeSpecificPart} methods decode any escaped
+ *   octets in their corresponding components.  The strings returned by these
+ *   methods may contain both <i>other</i> characters and illegal characters,
+ *   and will not contain any escaped octets.  </p></li>
+ *
+ *   <li><p> The {@link #toString() toString} method returns a URI string with
+ *   all necessary quotation but which may contain <i>other</i> characters.
+ *   </p></li>
+ *
+ *   <li><p> The {@link #toASCIIString() toASCIIString} method returns a fully
+ *   quoted and encoded URI string that does not contain any <i>other</i>
+ *   characters.  </p></li>
+ *
+ * </ul>
+ *
+ *
+ * <h4> Identities </h4>
+ *
+ * For any URI <i>u</i>, it is always the case that
+ *
+ * <blockquote>
+ * {@code new URI(}<i>u</i>{@code .toString()).equals(}<i>u</i>{@code )}&nbsp;.
+ * </blockquote>
+ *
+ * For any URI <i>u</i> that does not contain redundant syntax such as two
+ * slashes before an empty authority (as in {@code file:///tmp/}&nbsp;) or a
+ * colon following a host name but no port (as in
+ * {@code http://java.sun.com:}&nbsp;), and that does not encode characters
+ * except those that must be quoted, the following identities also hold:
+ * <pre>
+ *     new URI(<i>u</i>.getScheme(),
+ *             <i>u</i>.getSchemeSpecificPart(),
+ *             <i>u</i>.getFragment())
+ *     .equals(<i>u</i>)</pre>
+ * in all cases,
+ * <pre>
+ *     new URI(<i>u</i>.getScheme(),
+ *             <i>u</i>.getUserInfo(), <i>u</i>.getAuthority(),
+ *             <i>u</i>.getPath(), <i>u</i>.getQuery(),
+ *             <i>u</i>.getFragment())
+ *     .equals(<i>u</i>)</pre>
+ * if <i>u</i> is hierarchical, and
+ * <pre>
+ *     new URI(<i>u</i>.getScheme(),
+ *             <i>u</i>.getUserInfo(), <i>u</i>.getHost(), <i>u</i>.getPort(),
+ *             <i>u</i>.getPath(), <i>u</i>.getQuery(),
+ *             <i>u</i>.getFragment())
+ *     .equals(<i>u</i>)</pre>
+ * if <i>u</i> is hierarchical and has either no authority or a server-based
+ * authority.
+ *
+ *
+ * <h4> URIs, URLs, and URNs </h4>
+ *
+ * A URI is a uniform resource <i>identifier</i> while a URL is a uniform
+ * resource <i>locator</i>.  Hence every URL is a URI, abstractly speaking, but
+ * not every URI is a URL.  This is because there is another subcategory of
+ * URIs, uniform resource <i>names</i> (URNs), which name resources but do not
+ * specify how to locate them.  The {@code mailto}, {@code news}, and
+ * {@code isbn} URIs shown above are examples of URNs.
+ *
+ * <p> The conceptual distinction between URIs and URLs is reflected in the
+ * differences between this class and the {@link URL} class.
+ *
+ * <p> An instance of this class represents a URI reference in the syntactic
+ * sense defined by RFC&nbsp;2396.  A URI may be either absolute or relative.
+ * A URI string is parsed according to the generic syntax without regard to the
+ * scheme, if any, that it specifies.  No lookup of the host, if any, is
+ * performed, and no scheme-dependent stream handler is constructed.  Equality,
+ * hashing, and comparison are defined strictly in terms of the character
+ * content of the instance.  In other words, a URI instance is little more than
+ * a structured string that supports the syntactic, scheme-independent
+ * operations of comparison, normalization, resolution, and relativization.
+ *
+ * <p> An instance of the {@link URL} class, by contrast, represents the
+ * syntactic components of a URL together with some of the information required
+ * to access the resource that it describes.  A URL must be absolute, that is,
+ * it must always specify a scheme.  A URL string is parsed according to its
+ * scheme.  A stream handler is always established for a URL, and in fact it is
+ * impossible to create a URL instance for a scheme for which no handler is
+ * available.  Equality and hashing depend upon both the scheme and the
+ * Internet address of the host, if any; comparison is not defined.  In other
+ * words, a URL is a structured string that supports the syntactic operation of
+ * resolution as well as the network I/O operations of looking up the host and
+ * opening a connection to the specified resource.
+ *
+ *
+ * @author Mark Reinhold
+ * @since 1.4
+ *
+ * @see <a href="http://www.ietf.org/rfc/rfc2279.txt">RFC&nbsp;2279: UTF-8, a transformation format of ISO 10646</a>
+ * @see <a href="http://www.ietf.org/rfc/rfc2373.txt">RFC&nbsp;2373: IPv6 Addressing Architecture</a>
+ * @see <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396: Uniform Resource Identifiers (URI): Generic Syntax</a>
+ * @see <a href="http://www.ietf.org/rfc/rfc2732.txt">RFC&nbsp;2732: Format for Literal IPv6 Addresses in URLs</a>
+ */
+
+public final class URI
+    implements Comparable<URI>, Serializable
+{
+
+    // Note: Comments containing the word "ASSERT" indicate places where a
+    // throw of an InternalError should be replaced by an appropriate assertion
+    // statement once asserts are enabled in the build.
+
+    static final long serialVersionUID = -6052424284110960213L;
+
+
+    // -- Properties and components of this instance --
+
+    // Components of all URIs: [<scheme>:]<scheme-specific-part>[#<fragment>]
+    private transient String scheme;            // null ==> relative URI
+    private transient String fragment;
+
+    // Hierarchical URI components: [//<authority>]<path>[?<query>]
+    private transient String authority;         // Registry or server
+
+    // Server-based authority: [<userInfo>@]<host>[:<port>]
+    private transient String userInfo;
+    private transient String host;              // null ==> registry-based
+    private transient int port = -1;            // -1 ==> undefined
+
+    // Remaining components of hierarchical URIs
+    private transient String path;              // null ==> opaque
+    private transient String query;
+
+    // The remaining fields may be computed on demand
+
+    private volatile transient String schemeSpecificPart;
+    private volatile transient int hash;        // Zero ==> undefined
+
+    private volatile transient String decodedUserInfo = null;
+    private volatile transient String decodedAuthority = null;
+    private volatile transient String decodedPath = null;
+    private volatile transient String decodedQuery = null;
+    private volatile transient String decodedFragment = null;
+    private volatile transient String decodedSchemeSpecificPart = null;
+
+    /**
+     * The string form of this URI.
+     *
+     * @serial
+     */
+    private volatile String string;             // The only serializable field
+
+
+
+    // -- Constructors and factories --
+
+    private URI() { }                           // Used internally
+
+    /**
+     * Constructs a URI by parsing the given string.
+     *
+     * <p> This constructor parses the given string exactly as specified by the
+     * grammar in <a
+     * href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>,
+     * Appendix&nbsp;A, <b><i>except for the following deviations:</i></b> </p>
+     *
+     * <ul>
+     *
+     *   <li><p> An empty authority component is permitted as long as it is
+     *   followed by a non-empty path, a query component, or a fragment
+     *   component.  This allows the parsing of URIs such as
+     *   {@code "file:///foo/bar"}, which seems to be the intent of
+     *   RFC&nbsp;2396 although the grammar does not permit it.  If the
+     *   authority component is empty then the user-information, host, and port
+     *   components are undefined. </p></li>
+     *
+     *   <li><p> Empty relative paths are permitted; this seems to be the
+     *   intent of RFC&nbsp;2396 although the grammar does not permit it.  The
+     *   primary consequence of this deviation is that a standalone fragment
+     *   such as {@code "#foo"} parses as a relative URI with an empty path
+     *   and the given fragment, and can be usefully <a
+     *   href="#resolve-frag">resolved</a> against a base URI.
+     *
+     *   <li><p> IPv4 addresses in host components are parsed rigorously, as
+     *   specified by <a
+     *   href="http://www.ietf.org/rfc/rfc2732.txt">RFC&nbsp;2732</a>: Each
+     *   element of a dotted-quad address must contain no more than three
+     *   decimal digits.  Each element is further constrained to have a value
+     *   no greater than 255. </p></li>
+     *
+     *   <li> <p> Hostnames in host components that comprise only a single
+     *   domain label are permitted to start with an <i>alphanum</i>
+     *   character. This seems to be the intent of <a
+     *   href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>
+     *   section&nbsp;3.2.2 although the grammar does not permit it. The
+     *   consequence of this deviation is that the authority component of a
+     *   hierarchical URI such as {@code s://123}, will parse as a server-based
+     *   authority. </p></li>
+     *
+     *   <li><p> IPv6 addresses are permitted for the host component.  An IPv6
+     *   address must be enclosed in square brackets ({@code '['} and
+     *   {@code ']'}) as specified by <a
+     *   href="http://www.ietf.org/rfc/rfc2732.txt">RFC&nbsp;2732</a>.  The
+     *   IPv6 address itself must parse according to <a
+     *   href="http://www.ietf.org/rfc/rfc2373.txt">RFC&nbsp;2373</a>.  IPv6
+     *   addresses are further constrained to describe no more than sixteen
+     *   bytes of address information, a constraint implicit in RFC&nbsp;2373
+     *   but not expressible in the grammar. </p></li>
+     *
+     *   <li><p> Characters in the <i>other</i> category are permitted wherever
+     *   RFC&nbsp;2396 permits <i>escaped</i> octets, that is, in the
+     *   user-information, path, query, and fragment components, as well as in
+     *   the authority component if the authority is registry-based.  This
+     *   allows URIs to contain Unicode characters beyond those in the US-ASCII
+     *   character set. </p></li>
+     *
+     * </ul>
+     *
+     * @param  str   The string to be parsed into a URI
+     *
+     * @throws  NullPointerException
+     *          If {@code str} is {@code null}
+     *
+     * @throws  URISyntaxException
+     *          If the given string violates RFC&nbsp;2396, as augmented
+     *          by the above deviations
+     */
+    public URI(String str) throws URISyntaxException {
+        new Parser(str).parse(false);
+    }
+
+    /**
+     * Constructs a hierarchical URI from the given components.
+     *
+     * <p> If a scheme is given then the path, if also given, must either be
+     * empty or begin with a slash character ({@code '/'}).  Otherwise a
+     * component of the new URI may be left undefined by passing {@code null}
+     * for the corresponding parameter or, in the case of the {@code port}
+     * parameter, by passing {@code -1}.
+     *
+     * <p> This constructor first builds a URI string from the given components
+     * according to the rules specified in <a
+     * href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>,
+     * section&nbsp;5.2, step&nbsp;7: </p>
+     *
+     * <ol>
+     *
+     *   <li><p> Initially, the result string is empty. </p></li>
+     *
+     *   <li><p> If a scheme is given then it is appended to the result,
+     *   followed by a colon character ({@code ':'}).  </p></li>
+     *
+     *   <li><p> If user information, a host, or a port are given then the
+     *   string {@code "//"} is appended.  </p></li>
+     *
+     *   <li><p> If user information is given then it is appended, followed by
+     *   a commercial-at character ({@code '@'}).  Any character not in the
+     *   <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
+     *   categories is <a href="#quote">quoted</a>.  </p></li>
+     *
+     *   <li><p> If a host is given then it is appended.  If the host is a
+     *   literal IPv6 address but is not enclosed in square brackets
+     *   ({@code '['} and {@code ']'}) then the square brackets are added.
+     *   </p></li>
+     *
+     *   <li><p> If a port number is given then a colon character
+     *   ({@code ':'}) is appended, followed by the port number in decimal.
+     *   </p></li>
+     *
+     *   <li><p> If a path is given then it is appended.  Any character not in
+     *   the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
+     *   categories, and not equal to the slash character ({@code '/'}) or the
+     *   commercial-at character ({@code '@'}), is quoted.  </p></li>
+     *
+     *   <li><p> If a query is given then a question-mark character
+     *   ({@code '?'}) is appended, followed by the query.  Any character that
+     *   is not a <a href="#legal-chars">legal URI character</a> is quoted.
+     *   </p></li>
+     *
+     *   <li><p> Finally, if a fragment is given then a hash character
+     *   ({@code '#'}) is appended, followed by the fragment.  Any character
+     *   that is not a legal URI character is quoted.  </p></li>
+     *
+     * </ol>
+     *
+     * <p> The resulting URI string is then parsed as if by invoking the {@link
+     * #URI(String)} constructor and then invoking the {@link
+     * #parseServerAuthority()} method upon the result; this may cause a {@link
+     * URISyntaxException} to be thrown.  </p>
+     *
+     * @param   scheme    Scheme name
+     * @param   userInfo  User name and authorization information
+     * @param   host      Host name
+     * @param   port      Port number
+     * @param   path      Path
+     * @param   query     Query
+     * @param   fragment  Fragment
+     *
+     * @throws URISyntaxException
+     *         If both a scheme and a path are given but the path is relative,
+     *         if the URI string constructed from the given components violates
+     *         RFC&nbsp;2396, or if the authority component of the string is
+     *         present but cannot be parsed as a server-based authority
+     */
+    public URI(String scheme,
+               String userInfo, String host, int port,
+               String path, String query, String fragment)
+        throws URISyntaxException
+    {
+        String s = toString(scheme, null,
+                            null, userInfo, host, port,
+                            path, query, fragment);
+        checkPath(s, scheme, path);
+        new Parser(s).parse(true);
+    }
+
+    /**
+     * Constructs a hierarchical URI from the given components.
+     *
+     * <p> If a scheme is given then the path, if also given, must either be
+     * empty or begin with a slash character ({@code '/'}).  Otherwise a
+     * component of the new URI may be left undefined by passing {@code null}
+     * for the corresponding parameter.
+     *
+     * <p> This constructor first builds a URI string from the given components
+     * according to the rules specified in <a
+     * href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>,
+     * section&nbsp;5.2, step&nbsp;7: </p>
+     *
+     * <ol>
+     *
+     *   <li><p> Initially, the result string is empty.  </p></li>
+     *
+     *   <li><p> If a scheme is given then it is appended to the result,
+     *   followed by a colon character ({@code ':'}).  </p></li>
+     *
+     *   <li><p> If an authority is given then the string {@code "//"} is
+     *   appended, followed by the authority.  If the authority contains a
+     *   literal IPv6 address then the address must be enclosed in square
+     *   brackets ({@code '['} and {@code ']'}).  Any character not in the
+     *   <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
+     *   categories, and not equal to the commercial-at character
+     *   ({@code '@'}), is <a href="#quote">quoted</a>.  </p></li>
+     *
+     *   <li><p> If a path is given then it is appended.  Any character not in
+     *   the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
+     *   categories, and not equal to the slash character ({@code '/'}) or the
+     *   commercial-at character ({@code '@'}), is quoted.  </p></li>
+     *
+     *   <li><p> If a query is given then a question-mark character
+     *   ({@code '?'}) is appended, followed by the query.  Any character that
+     *   is not a <a href="#legal-chars">legal URI character</a> is quoted.
+     *   </p></li>
+     *
+     *   <li><p> Finally, if a fragment is given then a hash character
+     *   ({@code '#'}) is appended, followed by the fragment.  Any character
+     *   that is not a legal URI character is quoted.  </p></li>
+     *
+     * </ol>
+     *
+     * <p> The resulting URI string is then parsed as if by invoking the {@link
+     * #URI(String)} constructor and then invoking the {@link
+     * #parseServerAuthority()} method upon the result; this may cause a {@link
+     * URISyntaxException} to be thrown.  </p>
+     *
+     * @param   scheme     Scheme name
+     * @param   authority  Authority
+     * @param   path       Path
+     * @param   query      Query
+     * @param   fragment   Fragment
+     *
+     * @throws URISyntaxException
+     *         If both a scheme and a path are given but the path is relative,
+     *         if the URI string constructed from the given components violates
+     *         RFC&nbsp;2396, or if the authority component of the string is
+     *         present but cannot be parsed as a server-based authority
+     */
+    public URI(String scheme,
+               String authority,
+               String path, String query, String fragment)
+        throws URISyntaxException
+    {
+        String s = toString(scheme, null,
+                            authority, null, null, -1,
+                            path, query, fragment);
+        checkPath(s, scheme, path);
+        new Parser(s).parse(false);
+    }
+
+    /**
+     * Constructs a hierarchical URI from the given components.
+     *
+     * <p> A component may be left undefined by passing {@code null}.
+     *
+     * <p> This convenience constructor works as if by invoking the
+     * seven-argument constructor as follows:
+     *
+     * <blockquote>
+     * {@code new} {@link #URI(String, String, String, int, String, String, String)
+     * URI}{@code (scheme, null, host, -1, path, null, fragment);}
+     * </blockquote>
+     *
+     * @param   scheme    Scheme name
+     * @param   host      Host name
+     * @param   path      Path
+     * @param   fragment  Fragment
+     *
+     * @throws  URISyntaxException
+     *          If the URI string constructed from the given components
+     *          violates RFC&nbsp;2396
+     */
+    public URI(String scheme, String host, String path, String fragment)
+        throws URISyntaxException
+    {
+        this(scheme, null, host, -1, path, null, fragment);
+    }
+
+    /**
+     * Constructs a URI from the given components.
+     *
+     * <p> A component may be left undefined by passing {@code null}.
+     *
+     * <p> This constructor first builds a URI in string form using the given
+     * components as follows:  </p>
+     *
+     * <ol>
+     *
+     *   <li><p> Initially, the result string is empty.  </p></li>
+     *
+     *   <li><p> If a scheme is given then it is appended to the result,
+     *   followed by a colon character ({@code ':'}).  </p></li>
+     *
+     *   <li><p> If a scheme-specific part is given then it is appended.  Any
+     *   character that is not a <a href="#legal-chars">legal URI character</a>
+     *   is <a href="#quote">quoted</a>.  </p></li>
+     *
+     *   <li><p> Finally, if a fragment is given then a hash character
+     *   ({@code '#'}) is appended to the string, followed by the fragment.
+     *   Any character that is not a legal URI character is quoted.  </p></li>
+     *
+     * </ol>
+     *
+     * <p> The resulting URI string is then parsed in order to create the new
+     * URI instance as if by invoking the {@link #URI(String)} constructor;
+     * this may cause a {@link URISyntaxException} to be thrown.  </p>
+     *
+     * @param   scheme    Scheme name
+     * @param   ssp       Scheme-specific part
+     * @param   fragment  Fragment
+     *
+     * @throws  URISyntaxException
+     *          If the URI string constructed from the given components
+     *          violates RFC&nbsp;2396
+     */
+    public URI(String scheme, String ssp, String fragment)
+        throws URISyntaxException
+    {
+        new Parser(toString(scheme, ssp,
+                            null, null, null, -1,
+                            null, null, fragment))
+            .parse(false);
+    }
+
+    /**
+     * Creates a URI by parsing the given string.
+     *
+     * <p> This convenience factory method works as if by invoking the {@link
+     * #URI(String)} constructor; any {@link URISyntaxException} thrown by the
+     * constructor is caught and wrapped in a new {@link
+     * IllegalArgumentException} object, which is then thrown.
+     *
+     * <p> This method is provided for use in situations where it is known that
+     * the given string is a legal URI, for example for URI constants declared
+     * within in a program, and so it would be considered a programming error
+     * for the string not to parse as such.  The constructors, which throw
+     * {@link URISyntaxException} directly, should be used situations where a
+     * URI is being constructed from user input or from some other source that
+     * may be prone to errors.  </p>
+     *
+     * @param  str   The string to be parsed into a URI
+     * @return The new URI
+     *
+     * @throws  NullPointerException
+     *          If {@code str} is {@code null}
+     *
+     * @throws  IllegalArgumentException
+     *          If the given string violates RFC&nbsp;2396
+     */
+    public static URI create(String str) {
+        try {
+            return new URI(str);
+        } catch (URISyntaxException x) {
+            throw new IllegalArgumentException(x.getMessage(), x);
+        }
+    }
+
+
+    // -- Operations --
+
+    /**
+     * Attempts to parse this URI's authority component, if defined, into
+     * user-information, host, and port components.
+     *
+     * <p> If this URI's authority component has already been recognized as
+     * being server-based then it will already have been parsed into
+     * user-information, host, and port components.  In this case, or if this
+     * URI has no authority component, this method simply returns this URI.
+     *
+     * <p> Otherwise this method attempts once more to parse the authority
+     * component into user-information, host, and port components, and throws
+     * an exception describing why the authority component could not be parsed
+     * in that way.
+     *
+     * <p> This method is provided because the generic URI syntax specified in
+     * <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>
+     * cannot always distinguish a malformed server-based authority from a
+     * legitimate registry-based authority.  It must therefore treat some
+     * instances of the former as instances of the latter.  The authority
+     * component in the URI string {@code "//foo:bar"}, for example, is not a
+     * legal server-based authority but it is legal as a registry-based
+     * authority.
+     *
+     * <p> In many common situations, for example when working URIs that are
+     * known to be either URNs or URLs, the hierarchical URIs being used will
+     * always be server-based.  They therefore must either be parsed as such or
+     * treated as an error.  In these cases a statement such as
+     *
+     * <blockquote>
+     * {@code URI }<i>u</i>{@code  = new URI(str).parseServerAuthority();}
+     * </blockquote>
+     *
+     * <p> can be used to ensure that <i>u</i> always refers to a URI that, if
+     * it has an authority component, has a server-based authority with proper
+     * user-information, host, and port components.  Invoking this method also
+     * ensures that if the authority could not be parsed in that way then an
+     * appropriate diagnostic message can be issued based upon the exception
+     * that is thrown. </p>
+     *
+     * @return  A URI whose authority field has been parsed
+     *          as a server-based authority
+     *
+     * @throws  URISyntaxException
+     *          If the authority component of this URI is defined
+     *          but cannot be parsed as a server-based authority
+     *          according to RFC&nbsp;2396
+     */
+    public URI parseServerAuthority()
+        throws URISyntaxException
+    {
+        // We could be clever and cache the error message and index from the
+        // exception thrown during the original parse, but that would require
+        // either more fields or a more-obscure representation.
+        if ((host != null) || (authority == null))
+            return this;
+        defineString();
+        new Parser(string).parse(true);
+        return this;
+    }
+
+    /**
+     * Normalizes this URI's path.
+     *
+     * <p> If this URI is opaque, or if its path is already in normal form,
+     * then this URI is returned.  Otherwise a new URI is constructed that is
+     * identical to this URI except that its path is computed by normalizing
+     * this URI's path in a manner consistent with <a
+     * href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>,
+     * section&nbsp;5.2, step&nbsp;6, sub-steps&nbsp;c through&nbsp;f; that is:
+     * </p>
+     *
+     * <ol>
+     *
+     *   <li><p> All {@code "."} segments are removed. </p></li>
+     *
+     *   <li><p> If a {@code ".."} segment is preceded by a non-{@code ".."}
+     *   segment then both of these segments are removed.  This step is
+     *   repeated until it is no longer applicable. </p></li>
+     *
+     *   <li><p> If the path is relative, and if its first segment contains a
+     *   colon character ({@code ':'}), then a {@code "."} segment is
+     *   prepended.  This prevents a relative URI with a path such as
+     *   {@code "a:b/c/d"} from later being re-parsed as an opaque URI with a
+     *   scheme of {@code "a"} and a scheme-specific part of {@code "b/c/d"}.
+     *   <b><i>(Deviation from RFC&nbsp;2396)</i></b> </p></li>
+     *
+     * </ol>
+     *
+     * <p> A normalized path will begin with one or more {@code ".."} segments
+     * if there were insufficient non-{@code ".."} segments preceding them to
+     * allow their removal.  A normalized path will begin with a {@code "."}
+     * segment if one was inserted by step 3 above.  Otherwise, a normalized
+     * path will not contain any {@code "."} or {@code ".."} segments. </p>
+     *
+     * @return  A URI equivalent to this URI,
+     *          but whose path is in normal form
+     */
+    public URI normalize() {
+        return normalize(this);
+    }
+
+    /**
+     * Resolves the given URI against this URI.
+     *
+     * <p> If the given URI is already absolute, or if this URI is opaque, then
+     * the given URI is returned.
+     *
+     * <p><a name="resolve-frag"></a> If the given URI's fragment component is
+     * defined, its path component is empty, and its scheme, authority, and
+     * query components are undefined, then a URI with the given fragment but
+     * with all other components equal to those of this URI is returned.  This
+     * allows a URI representing a standalone fragment reference, such as
+     * {@code "#foo"}, to be usefully resolved against a base URI.
+     *
+     * <p> Otherwise this method constructs a new hierarchical URI in a manner
+     * consistent with <a
+     * href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>,
+     * section&nbsp;5.2; that is: </p>
+     *
+     * <ol>
+     *
+     *   <li><p> A new URI is constructed with this URI's scheme and the given
+     *   URI's query and fragment components. </p></li>
+     *
+     *   <li><p> If the given URI has an authority component then the new URI's
+     *   authority and path are taken from the given URI. </p></li>
+     *
+     *   <li><p> Otherwise the new URI's authority component is copied from
+     *   this URI, and its path is computed as follows: </p>
+     *
+     *   <ol>
+     *
+     *     <li><p> If the given URI's path is absolute then the new URI's path
+     *     is taken from the given URI. </p></li>
+     *
+     *     <li><p> Otherwise the given URI's path is relative, and so the new
+     *     URI's path is computed by resolving the path of the given URI
+     *     against the path of this URI.  This is done by concatenating all but
+     *     the last segment of this URI's path, if any, with the given URI's
+     *     path and then normalizing the result as if by invoking the {@link
+     *     #normalize() normalize} method. </p></li>
+     *
+     *   </ol></li>
+     *
+     * </ol>
+     *
+     * <p> The result of this method is absolute if, and only if, either this
+     * URI is absolute or the given URI is absolute.  </p>
+     *
+     * @param  uri  The URI to be resolved against this URI
+     * @return The resulting URI
+     *
+     * @throws  NullPointerException
+     *          If {@code uri} is {@code null}
+     */
+    public URI resolve(URI uri) {
+        return resolve(this, uri);
+    }
+
+    /**
+     * Constructs a new URI by parsing the given string and then resolving it
+     * against this URI.
+     *
+     * <p> This convenience method works as if invoking it were equivalent to
+     * evaluating the expression {@link #resolve(java.net.URI)
+     * resolve}{@code (URI.}{@link #create(String) create}{@code (str))}. </p>
+     *
+     * @param  str   The string to be parsed into a URI
+     * @return The resulting URI
+     *
+     * @throws  NullPointerException
+     *          If {@code str} is {@code null}
+     *
+     * @throws  IllegalArgumentException
+     *          If the given string violates RFC&nbsp;2396
+     */
+    public URI resolve(String str) {
+        return resolve(URI.create(str));
+    }
+
+    /**
+     * Relativizes the given URI against this URI.
+     *
+     * <p> The relativization of the given URI against this URI is computed as
+     * follows: </p>
+     *
+     * <ol>
+     *
+     *   <li><p> If either this URI or the given URI are opaque, or if the
+     *   scheme and authority components of the two URIs are not identical, or
+     *   if the path of this URI is not a prefix of the path of the given URI,
+     *   then the given URI is returned. </p></li>
+     *
+     *   <li><p> Otherwise a new relative hierarchical URI is constructed with
+     *   query and fragment components taken from the given URI and with a path
+     *   component computed by removing this URI's path from the beginning of
+     *   the given URI's path. </p></li>
+     *
+     * </ol>
+     *
+     * @param  uri  The URI to be relativized against this URI
+     * @return The resulting URI
+     *
+     * @throws  NullPointerException
+     *          If {@code uri} is {@code null}
+     */
+    public URI relativize(URI uri) {
+        return relativize(this, uri);
+    }
+
+    /**
+     * Constructs a URL from this URI.
+     *
+     * <p> This convenience method works as if invoking it were equivalent to
+     * evaluating the expression {@code new URL(this.toString())} after
+     * first checking that this URI is absolute. </p>
+     *
+     * @return  A URL constructed from this URI
+     *
+     * @throws  IllegalArgumentException
+     *          If this URL is not absolute
+     *
+     * @throws  MalformedURLException
+     *          If a protocol handler for the URL could not be found,
+     *          or if some other error occurred while constructing the URL
+     */
+    public URL toURL()
+        throws MalformedURLException {
+        if (!isAbsolute())
+            throw new IllegalArgumentException("URI is not absolute");
+        return new URL(toString());
+    }
+
+    // -- Component access methods --
+
+    /**
+     * Returns the scheme component of this URI.
+     *
+     * <p> The scheme component of a URI, if defined, only contains characters
+     * in the <i>alphanum</i> category and in the string {@code "-.+"}.  A
+     * scheme always starts with an <i>alpha</i> character. <p>
+     *
+     * The scheme component of a URI cannot contain escaped octets, hence this
+     * method does not perform any decoding.
+     *
+     * @return  The scheme component of this URI,
+     *          or {@code null} if the scheme is undefined
+     */
+    public String getScheme() {
+        return scheme;
+    }
+
+    /**
+     * Tells whether or not this URI is absolute.
+     *
+     * <p> A URI is absolute if, and only if, it has a scheme component. </p>
+     *
+     * @return  {@code true} if, and only if, this URI is absolute
+     */
+    public boolean isAbsolute() {
+        return scheme != null;
+    }
+
+    /**
+     * Tells whether or not this URI is opaque.
+     *
+     * <p> A URI is opaque if, and only if, it is absolute and its
+     * scheme-specific part does not begin with a slash character ('/').
+     * An opaque URI has a scheme, a scheme-specific part, and possibly
+     * a fragment; all other components are undefined. </p>
+     *
+     * @return  {@code true} if, and only if, this URI is opaque
+     */
+    public boolean isOpaque() {
+        return path == null;
+    }
+
+    /**
+     * Returns the raw scheme-specific part of this URI.  The scheme-specific
+     * part is never undefined, though it may be empty.
+     *
+     * <p> The scheme-specific part of a URI only contains legal URI
+     * characters. </p>
+     *
+     * @return  The raw scheme-specific part of this URI
+     *          (never {@code null})
+     */
+    public String getRawSchemeSpecificPart() {
+        defineSchemeSpecificPart();
+        return schemeSpecificPart;
+    }
+
+    /**
+     * Returns the decoded scheme-specific part of this URI.
+     *
+     * <p> The string returned by this method is equal to that returned by the
+     * {@link #getRawSchemeSpecificPart() getRawSchemeSpecificPart} method
+     * except that all sequences of escaped octets are <a
+     * href="#decode">decoded</a>.  </p>
+     *
+     * @return  The decoded scheme-specific part of this URI
+     *          (never {@code null})
+     */
+    public String getSchemeSpecificPart() {
+        if (decodedSchemeSpecificPart == null)
+            decodedSchemeSpecificPart = decode(getRawSchemeSpecificPart());
+        return decodedSchemeSpecificPart;
+    }
+
+    /**
+     * Returns the raw authority component of this URI.
+     *
+     * <p> The authority component of a URI, if defined, only contains the
+     * commercial-at character ({@code '@'}) and characters in the
+     * <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, and <i>other</i>
+     * categories.  If the authority is server-based then it is further
+     * constrained to have valid user-information, host, and port
+     * components. </p>
+     *
+     * @return  The raw authority component of this URI,
+     *          or {@code null} if the authority is undefined
+     */
+    public String getRawAuthority() {
+        return authority;
+    }
+
+    /**
+     * Returns the decoded authority component of this URI.
+     *
+     * <p> The string returned by this method is equal to that returned by the
+     * {@link #getRawAuthority() getRawAuthority} method except that all
+     * sequences of escaped octets are <a href="#decode">decoded</a>.  </p>
+     *
+     * @return  The decoded authority component of this URI,
+     *          or {@code null} if the authority is undefined
+     */
+    public String getAuthority() {
+        if (decodedAuthority == null)
+            decodedAuthority = decode(authority);
+        return decodedAuthority;
+    }
+
+    /**
+     * Returns the raw user-information component of this URI.
+     *
+     * <p> The user-information component of a URI, if defined, only contains
+     * characters in the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, and
+     * <i>other</i> categories. </p>
+     *
+     * @return  The raw user-information component of this URI,
+     *          or {@code null} if the user information is undefined
+     */
+    public String getRawUserInfo() {
+        return userInfo;
+    }
+
+    /**
+     * Returns the decoded user-information component of this URI.
+     *
+     * <p> The string returned by this method is equal to that returned by the
+     * {@link #getRawUserInfo() getRawUserInfo} method except that all
+     * sequences of escaped octets are <a href="#decode">decoded</a>.  </p>
+     *
+     * @return  The decoded user-information component of this URI,
+     *          or {@code null} if the user information is undefined
+     */
+    public String getUserInfo() {
+        if ((decodedUserInfo == null) && (userInfo != null))
+            decodedUserInfo = decode(userInfo);
+        return decodedUserInfo;
+    }
+
+    /**
+     * Returns the host component of this URI.
+     *
+     * <p> The host component of a URI, if defined, will have one of the
+     * following forms: </p>
+     *
+     * <ul>
+     *
+     *   <li><p> A domain name consisting of one or more <i>labels</i>
+     *   separated by period characters ({@code '.'}), optionally followed by
+     *   a period character.  Each label consists of <i>alphanum</i> characters
+     *   as well as hyphen characters ({@code '-'}), though hyphens never
+     *   occur as the first or last characters in a label. The rightmost
+     *   label of a domain name consisting of two or more labels, begins
+     *   with an <i>alpha</i> character. </li>
+     *
+     *   <li><p> A dotted-quad IPv4 address of the form
+     *   <i>digit</i>{@code +.}<i>digit</i>{@code +.}<i>digit</i>{@code +.}<i>digit</i>{@code +},
+     *   where no <i>digit</i> sequence is longer than three characters and no
+     *   sequence has a value larger than 255. </p></li>
+     *
+     *   <li><p> An IPv6 address enclosed in square brackets ({@code '['} and
+     *   {@code ']'}) and consisting of hexadecimal digits, colon characters
+     *   ({@code ':'}), and possibly an embedded IPv4 address.  The full
+     *   syntax of IPv6 addresses is specified in <a
+     *   href="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC&nbsp;2373: IPv6
+     *   Addressing Architecture</i></a>.  </p></li>
+     *
+     * </ul>
+     *
+     * The host component of a URI cannot contain escaped octets, hence this
+     * method does not perform any decoding.
+     *
+     * @return  The host component of this URI,
+     *          or {@code null} if the host is undefined
+     */
+    public String getHost() {
+        return host;
+    }
+
+    /**
+     * Returns the port number of this URI.
+     *
+     * <p> The port component of a URI, if defined, is a non-negative
+     * integer. </p>
+     *
+     * @return  The port component of this URI,
+     *          or {@code -1} if the port is undefined
+     */
+    public int getPort() {
+        return port;
+    }
+
+    /**
+     * Returns the raw path component of this URI.
+     *
+     * <p> The path component of a URI, if defined, only contains the slash
+     * character ({@code '/'}), the commercial-at character ({@code '@'}),
+     * and characters in the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>,
+     * and <i>other</i> categories. </p>
+     *
+     * @return  The path component of this URI,
+     *          or {@code null} if the path is undefined
+     */
+    public String getRawPath() {
+        return path;
+    }
+
+    /**
+     * Returns the decoded path component of this URI.
+     *
+     * <p> The string returned by this method is equal to that returned by the
+     * {@link #getRawPath() getRawPath} method except that all sequences of
+     * escaped octets are <a href="#decode">decoded</a>.  </p>
+     *
+     * @return  The decoded path component of this URI,
+     *          or {@code null} if the path is undefined
+     */
+    public String getPath() {
+        if ((decodedPath == null) && (path != null))
+            decodedPath = decode(path);
+        return decodedPath;
+    }
+
+    /**
+     * Returns the raw query component of this URI.
+     *
+     * <p> The query component of a URI, if defined, only contains legal URI
+     * characters. </p>
+     *
+     * @return  The raw query component of this URI,
+     *          or {@code null} if the query is undefined
+     */
+    public String getRawQuery() {
+        return query;
+    }
+
+    /**
+     * Returns the decoded query component of this URI.
+     *
+     * <p> The string returned by this method is equal to that returned by the
+     * {@link #getRawQuery() getRawQuery} method except that all sequences of
+     * escaped octets are <a href="#decode">decoded</a>.  </p>
+     *
+     * @return  The decoded query component of this URI,
+     *          or {@code null} if the query is undefined
+     */
+    public String getQuery() {
+        if ((decodedQuery == null) && (query != null))
+            decodedQuery = decode(query);
+        return decodedQuery;
+    }
+
+    /**
+     * Returns the raw fragment component of this URI.
+     *
+     * <p> The fragment component of a URI, if defined, only contains legal URI
+     * characters. </p>
+     *
+     * @return  The raw fragment component of this URI,
+     *          or {@code null} if the fragment is undefined
+     */
+    public String getRawFragment() {
+        return fragment;
+    }
+
+    /**
+     * Returns the decoded fragment component of this URI.
+     *
+     * <p> The string returned by this method is equal to that returned by the
+     * {@link #getRawFragment() getRawFragment} method except that all
+     * sequences of escaped octets are <a href="#decode">decoded</a>.  </p>
+     *
+     * @return  The decoded fragment component of this URI,
+     *          or {@code null} if the fragment is undefined
+     */
+    public String getFragment() {
+        if ((decodedFragment == null) && (fragment != null))
+            decodedFragment = decode(fragment);
+        return decodedFragment;
+    }
+
+
+    // -- Equality, comparison, hash code, toString, and serialization --
+
+    /**
+     * Tests this URI for equality with another object.
+     *
+     * <p> If the given object is not a URI then this method immediately
+     * returns {@code false}.
+     *
+     * <p> For two URIs to be considered equal requires that either both are
+     * opaque or both are hierarchical.  Their schemes must either both be
+     * undefined or else be equal without regard to case. Their fragments
+     * must either both be undefined or else be equal.
+     *
+     * <p> For two opaque URIs to be considered equal, their scheme-specific
+     * parts must be equal.
+     *
+     * <p> For two hierarchical URIs to be considered equal, their paths must
+     * be equal and their queries must either both be undefined or else be
+     * equal.  Their authorities must either both be undefined, or both be
+     * registry-based, or both be server-based.  If their authorities are
+     * defined and are registry-based, then they must be equal.  If their
+     * authorities are defined and are server-based, then their hosts must be
+     * equal without regard to case, their port numbers must be equal, and
+     * their user-information components must be equal.
+     *
+     * <p> When testing the user-information, path, query, fragment, authority,
+     * or scheme-specific parts of two URIs for equality, the raw forms rather
+     * than the encoded forms of these components are compared and the
+     * hexadecimal digits of escaped octets are compared without regard to
+     * case.
+     *
+     * <p> This method satisfies the general contract of the {@link
+     * java.lang.Object#equals(Object) Object.equals} method. </p>
+     *
+     * @param   ob   The object to which this object is to be compared
+     *
+     * @return  {@code true} if, and only if, the given object is a URI that
+     *          is identical to this URI
+     */
+    public boolean equals(Object ob) {
+        if (ob == this)
+            return true;
+        if (!(ob instanceof URI))
+            return false;
+        URI that = (URI)ob;
+        if (this.isOpaque() != that.isOpaque()) return false;
+        if (!equalIgnoringCase(this.scheme, that.scheme)) return false;
+        if (!equal(this.fragment, that.fragment)) return false;
+
+        // Opaque
+        if (this.isOpaque())
+            return equal(this.schemeSpecificPart, that.schemeSpecificPart);
+
+        // Hierarchical
+        if (!equal(this.path, that.path)) return false;
+        if (!equal(this.query, that.query)) return false;
+
+        // Authorities
+        if (this.authority == that.authority) return true;
+        if (this.host != null) {
+            // Server-based
+            if (!equal(this.userInfo, that.userInfo)) return false;
+            if (!equalIgnoringCase(this.host, that.host)) return false;
+            if (this.port != that.port) return false;
+        } else if (this.authority != null) {
+            // Registry-based
+            if (!equal(this.authority, that.authority)) return false;
+        } else if (this.authority != that.authority) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns a hash-code value for this URI.  The hash code is based upon all
+     * of the URI's components, and satisfies the general contract of the
+     * {@link java.lang.Object#hashCode() Object.hashCode} method.
+     *
+     * @return  A hash-code value for this URI
+     */
+    public int hashCode() {
+        if (hash != 0)
+            return hash;
+        int h = hashIgnoringCase(0, scheme);
+        h = hash(h, fragment);
+        if (isOpaque()) {
+            h = hash(h, schemeSpecificPart);
+        } else {
+            h = hash(h, path);
+            h = hash(h, query);
+            if (host != null) {
+                h = hash(h, userInfo);
+                h = hashIgnoringCase(h, host);
+                h += 1949 * port;
+            } else {
+                h = hash(h, authority);
+            }
+        }
+        hash = h;
+        return h;
+    }
+
+    /**
+     * Compares this URI to another object, which must be a URI.
+     *
+     * <p> When comparing corresponding components of two URIs, if one
+     * component is undefined but the other is defined then the first is
+     * considered to be less than the second.  Unless otherwise noted, string
+     * components are ordered according to their natural, case-sensitive
+     * ordering as defined by the {@link java.lang.String#compareTo(Object)
+     * String.compareTo} method.  String components that are subject to
+     * encoding are compared by comparing their raw forms rather than their
+     * encoded forms.
+     *
+     * <p> The ordering of URIs is defined as follows: </p>
+     *
+     * <ul>
+     *
+     *   <li><p> Two URIs with different schemes are ordered according the
+     *   ordering of their schemes, without regard to case. </p></li>
+     *
+     *   <li><p> A hierarchical URI is considered to be less than an opaque URI
+     *   with an identical scheme. </p></li>
+     *
+     *   <li><p> Two opaque URIs with identical schemes are ordered according
+     *   to the ordering of their scheme-specific parts. </p></li>
+     *
+     *   <li><p> Two opaque URIs with identical schemes and scheme-specific
+     *   parts are ordered according to the ordering of their
+     *   fragments. </p></li>
+     *
+     *   <li><p> Two hierarchical URIs with identical schemes are ordered
+     *   according to the ordering of their authority components: </p>
+     *
+     *   <ul>
+     *
+     *     <li><p> If both authority components are server-based then the URIs
+     *     are ordered according to their user-information components; if these
+     *     components are identical then the URIs are ordered according to the
+     *     ordering of their hosts, without regard to case; if the hosts are
+     *     identical then the URIs are ordered according to the ordering of
+     *     their ports. </p></li>
+     *
+     *     <li><p> If one or both authority components are registry-based then
+     *     the URIs are ordered according to the ordering of their authority
+     *     components. </p></li>
+     *
+     *   </ul></li>
+     *
+     *   <li><p> Finally, two hierarchical URIs with identical schemes and
+     *   authority components are ordered according to the ordering of their
+     *   paths; if their paths are identical then they are ordered according to
+     *   the ordering of their queries; if the queries are identical then they
+     *   are ordered according to the order of their fragments. </p></li>
+     *
+     * </ul>
+     *
+     * <p> This method satisfies the general contract of the {@link
+     * java.lang.Comparable#compareTo(Object) Comparable.compareTo}
+     * method. </p>
+     *
+     * @param   that
+     *          The object to which this URI is to be compared
+     *
+     * @return  A negative integer, zero, or a positive integer as this URI is
+     *          less than, equal to, or greater than the given URI
+     *
+     * @throws  ClassCastException
+     *          If the given object is not a URI
+     */
+    public int compareTo(URI that) {
+        int c;
+
+        if ((c = compareIgnoringCase(this.scheme, that.scheme)) != 0)
+            return c;
+
+        if (this.isOpaque()) {
+            if (that.isOpaque()) {
+                // Both opaque
+                if ((c = compare(this.schemeSpecificPart,
+                                 that.schemeSpecificPart)) != 0)
+                    return c;
+                return compare(this.fragment, that.fragment);
+            }
+            return +1;                  // Opaque > hierarchical
+        } else if (that.isOpaque()) {
+            return -1;                  // Hierarchical < opaque
+        }
+
+        // Hierarchical
+        if ((this.host != null) && (that.host != null)) {
+            // Both server-based
+            if ((c = compare(this.userInfo, that.userInfo)) != 0)
+                return c;
+            if ((c = compareIgnoringCase(this.host, that.host)) != 0)
+                return c;
+            if ((c = this.port - that.port) != 0)
+                return c;
+        } else {
+            // If one or both authorities are registry-based then we simply
+            // compare them in the usual, case-sensitive way.  If one is
+            // registry-based and one is server-based then the strings are
+            // guaranteed to be unequal, hence the comparison will never return
+            // zero and the compareTo and equals methods will remain
+            // consistent.
+            if ((c = compare(this.authority, that.authority)) != 0) return c;
+        }
+
+        if ((c = compare(this.path, that.path)) != 0) return c;
+        if ((c = compare(this.query, that.query)) != 0) return c;
+        return compare(this.fragment, that.fragment);
+    }
+
+    /**
+     * Returns the content of this URI as a string.
+     *
+     * <p> If this URI was created by invoking one of the constructors in this
+     * class then a string equivalent to the original input string, or to the
+     * string computed from the originally-given components, as appropriate, is
+     * returned.  Otherwise this URI was created by normalization, resolution,
+     * or relativization, and so a string is constructed from this URI's
+     * components according to the rules specified in <a
+     * href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>,
+     * section&nbsp;5.2, step&nbsp;7. </p>
+     *
+     * @return  The string form of this URI
+     */
+    public String toString() {
+        defineString();
+        return string;
+    }
+
+    /**
+     * Returns the content of this URI as a US-ASCII string.
+     *
+     * <p> If this URI does not contain any characters in the <i>other</i>
+     * category then an invocation of this method will return the same value as
+     * an invocation of the {@link #toString() toString} method.  Otherwise
+     * this method works as if by invoking that method and then <a
+     * href="#encode">encoding</a> the result.  </p>
+     *
+     * @return  The string form of this URI, encoded as needed
+     *          so that it only contains characters in the US-ASCII
+     *          charset
+     */
+    public String toASCIIString() {
+        defineString();
+        return encode(string);
+    }
+
+
+    // -- Serialization support --
+
+    /**
+     * Saves the content of this URI to the given serial stream.
+     *
+     * <p> The only serializable field of a URI instance is its {@code string}
+     * field.  That field is given a value, if it does not have one already,
+     * and then the {@link java.io.ObjectOutputStream#defaultWriteObject()}
+     * method of the given object-output stream is invoked. </p>
+     *
+     * @param  os  The object-output stream to which this object
+     *             is to be written
+     */
+    private void writeObject(ObjectOutputStream os)
+        throws IOException
+    {
+        defineString();
+        os.defaultWriteObject();        // Writes the string field only
+    }
+
+    /**
+     * Reconstitutes a URI from the given serial stream.
+     *
+     * <p> The {@link java.io.ObjectInputStream#defaultReadObject()} method is
+     * invoked to read the value of the {@code string} field.  The result is
+     * then parsed in the usual way.
+     *
+     * @param  is  The object-input stream from which this object
+     *             is being read
+     */
+    private void readObject(ObjectInputStream is)
+        throws ClassNotFoundException, IOException
+    {
+        port = -1;                      // Argh
+        is.defaultReadObject();
+        try {
+            new Parser(string).parse(false);
+        } catch (URISyntaxException x) {
+            IOException y = new InvalidObjectException("Invalid URI");
+            y.initCause(x);
+            throw y;
+        }
+    }
+
+
+    // -- End of public methods --
+
+
+    // -- Utility methods for string-field comparison and hashing --
+
+    // These methods return appropriate values for null string arguments,
+    // thereby simplifying the equals, hashCode, and compareTo methods.
+    //
+    // The case-ignoring methods should only be applied to strings whose
+    // characters are all known to be US-ASCII.  Because of this restriction,
+    // these methods are faster than the similar methods in the String class.
+
+    // US-ASCII only
+    private static int toLower(char c) {
+        if ((c >= 'A') && (c <= 'Z'))
+            return c + ('a' - 'A');
+        return c;
+    }
+
+    // US-ASCII only
+    private static int toUpper(char c) {
+        if ((c >= 'a') && (c <= 'z'))
+            return c - ('a' - 'A');
+        return c;
+    }
+
+    private static boolean equal(String s, String t) {
+        if (s == t) return true;
+        if ((s != null) && (t != null)) {
+            if (s.length() != t.length())
+                return false;
+            if (s.indexOf('%') < 0)
+                return s.equals(t);
+            int n = s.length();
+            for (int i = 0; i < n;) {
+                char c = s.charAt(i);
+                char d = t.charAt(i);
+                if (c != '%') {
+                    if (c != d)
+                        return false;
+                    i++;
+                    continue;
+                }
+                if (d != '%')
+                    return false;
+                i++;
+                if (toLower(s.charAt(i)) != toLower(t.charAt(i)))
+                    return false;
+                i++;
+                if (toLower(s.charAt(i)) != toLower(t.charAt(i)))
+                    return false;
+                i++;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    // US-ASCII only
+    private static boolean equalIgnoringCase(String s, String t) {
+        if (s == t) return true;
+        if ((s != null) && (t != null)) {
+            int n = s.length();
+            if (t.length() != n)
+                return false;
+            for (int i = 0; i < n; i++) {
+                if (toLower(s.charAt(i)) != toLower(t.charAt(i)))
+                    return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    private static int hash(int hash, String s) {
+        if (s == null) return hash;
+        return s.indexOf('%') < 0 ? hash * 127 + s.hashCode()
+                                  : normalizedHash(hash, s);
+    }
+
+
+    private static int normalizedHash(int hash, String s) {
+        int h = 0;
+        for (int index = 0; index < s.length(); index++) {
+            char ch = s.charAt(index);
+            h = 31 * h + ch;
+            if (ch == '%') {
+                /*
+                 * Process the next two encoded characters
+                 */
+                for (int i = index + 1; i < index + 3; i++)
+                    h = 31 * h + toUpper(s.charAt(i));
+                index += 2;
+            }
+        }
+        return hash * 127 + h;
+    }
+
+    // US-ASCII only
+    private static int hashIgnoringCase(int hash, String s) {
+        if (s == null) return hash;
+        int h = hash;
+        int n = s.length();
+        for (int i = 0; i < n; i++)
+            h = 31 * h + toLower(s.charAt(i));
+        return h;
+    }
+
+    private static int compare(String s, String t) {
+        if (s == t) return 0;
+        if (s != null) {
+            if (t != null)
+                return s.compareTo(t);
+            else
+                return +1;
+        } else {
+            return -1;
+        }
+    }
+
+    // US-ASCII only
+    private static int compareIgnoringCase(String s, String t) {
+        if (s == t) return 0;
+        if (s != null) {
+            if (t != null) {
+                int sn = s.length();
+                int tn = t.length();
+                int n = sn < tn ? sn : tn;
+                for (int i = 0; i < n; i++) {
+                    int c = toLower(s.charAt(i)) - toLower(t.charAt(i));
+                    if (c != 0)
+                        return c;
+                }
+                return sn - tn;
+            }
+            return +1;
+        } else {
+            return -1;
+        }
+    }
+
+
+    // -- String construction --
+
+    // If a scheme is given then the path, if given, must be absolute
+    //
+    private static void checkPath(String s, String scheme, String path)
+        throws URISyntaxException
+    {
+        if (scheme != null) {
+            if ((path != null)
+                && ((path.length() > 0) && (path.charAt(0) != '/')))
+                throw new URISyntaxException(s,
+                                             "Relative path in absolute URI");
+        }
+    }
+
+    private void appendAuthority(StringBuffer sb,
+                                 String authority,
+                                 String userInfo,
+                                 String host,
+                                 int port)
+    {
+        if (host != null) {
+            sb.append("//");
+            if (userInfo != null) {
+                sb.append(quote(userInfo, L_USERINFO, H_USERINFO));
+                sb.append('@');
+            }
+            boolean needBrackets = ((host.indexOf(':') >= 0)
+                                    && !host.startsWith("[")
+                                    && !host.endsWith("]"));
+            if (needBrackets) sb.append('[');
+            sb.append(host);
+            if (needBrackets) sb.append(']');
+            if (port != -1) {
+                sb.append(':');
+                sb.append(port);
+            }
+        } else if (authority != null) {
+            sb.append("//");
+            if (authority.startsWith("[")) {
+                // authority should (but may not) contain an embedded IPv6 address
+                int end = authority.indexOf("]");
+                String doquote = authority, dontquote = "";
+                if (end != -1 && authority.indexOf(":") != -1) {
+                    // the authority contains an IPv6 address
+                    if (end == authority.length()) {
+                        dontquote = authority;
+                        doquote = "";
+                    } else {
+                        dontquote = authority.substring(0 , end + 1);
+                        doquote = authority.substring(end + 1);
+                    }
+                }
+                sb.append(dontquote);
+                sb.append(quote(doquote,
+                            L_REG_NAME | L_SERVER,
+                            H_REG_NAME | H_SERVER));
+            } else {
+                sb.append(quote(authority,
+                            L_REG_NAME | L_SERVER,
+                            H_REG_NAME | H_SERVER));
+            }
+        }
+    }
+
+    private void appendSchemeSpecificPart(StringBuffer sb,
+                                          String opaquePart,
+                                          String authority,
+                                          String userInfo,
+                                          String host,
+                                          int port,
+                                          String path,
+                                          String query)
+    {
+        if (opaquePart != null) {
+            /* check if SSP begins with an IPv6 address
+             * because we must not quote a literal IPv6 address
+             */
+            if (opaquePart.startsWith("//[")) {
+                int end =  opaquePart.indexOf("]");
+                if (end != -1 && opaquePart.indexOf(":")!=-1) {
+                    String doquote, dontquote;
+                    if (end == opaquePart.length()) {
+                        dontquote = opaquePart;
+                        doquote = "";
+                    } else {
+                        dontquote = opaquePart.substring(0,end+1);
+                        doquote = opaquePart.substring(end+1);
+                    }
+                    sb.append (dontquote);
+                    sb.append(quote(doquote, L_URIC, H_URIC));
+                }
+            } else {
+                sb.append(quote(opaquePart, L_URIC, H_URIC));
+            }
+        } else {
+            appendAuthority(sb, authority, userInfo, host, port);
+            if (path != null)
+                sb.append(quote(path, L_PATH, H_PATH));
+            if (query != null) {
+                sb.append('?');
+                sb.append(quote(query, L_URIC, H_URIC));
+            }
+        }
+    }
+
+    private void appendFragment(StringBuffer sb, String fragment) {
+        if (fragment != null) {
+            sb.append('#');
+            sb.append(quote(fragment, L_URIC, H_URIC));
+        }
+    }
+
+    private String toString(String scheme,
+                            String opaquePart,
+                            String authority,
+                            String userInfo,
+                            String host,
+                            int port,
+                            String path,
+                            String query,
+                            String fragment)
+    {
+        StringBuffer sb = new StringBuffer();
+        if (scheme != null) {
+            sb.append(scheme);
+            sb.append(':');
+        }
+        appendSchemeSpecificPart(sb, opaquePart,
+                                 authority, userInfo, host, port,
+                                 path, query);
+        appendFragment(sb, fragment);
+        return sb.toString();
+    }
+
+    private void defineSchemeSpecificPart() {
+        if (schemeSpecificPart != null) return;
+        StringBuffer sb = new StringBuffer();
+        appendSchemeSpecificPart(sb, null, getAuthority(), getUserInfo(),
+                                 host, port, getPath(), getQuery());
+        if (sb.length() == 0) return;
+        schemeSpecificPart = sb.toString();
+    }
+
+    private void defineString() {
+        if (string != null) return;
+
+        StringBuffer sb = new StringBuffer();
+        if (scheme != null) {
+            sb.append(scheme);
+            sb.append(':');
+        }
+        if (isOpaque()) {
+            sb.append(schemeSpecificPart);
+        } else {
+            if (host != null) {
+                sb.append("//");
+                if (userInfo != null) {
+                    sb.append(userInfo);
+                    sb.append('@');
+                }
+                boolean needBrackets = ((host.indexOf(':') >= 0)
+                                    && !host.startsWith("[")
+                                    && !host.endsWith("]"));
+                if (needBrackets) sb.append('[');
+                sb.append(host);
+                if (needBrackets) sb.append(']');
+                if (port != -1) {
+                    sb.append(':');
+                    sb.append(port);
+                }
+            } else if (authority != null) {
+                sb.append("//");
+                sb.append(authority);
+            }
+            if (path != null)
+                sb.append(path);
+            if (query != null) {
+                sb.append('?');
+                sb.append(query);
+            }
+        }
+        if (fragment != null) {
+            sb.append('#');
+            sb.append(fragment);
+        }
+        string = sb.toString();
+    }
+
+
+    // -- Normalization, resolution, and relativization --
+
+    // RFC2396 5.2 (6)
+    private static String resolvePath(String base, String child,
+                                      boolean absolute)
+    {
+        int i = base.lastIndexOf('/');
+        int cn = child.length();
+        String path = "";
+
+        if (cn == 0) {
+            // 5.2 (6a)
+            if (i >= 0)
+                path = base.substring(0, i + 1);
+        } else {
+            StringBuffer sb = new StringBuffer(base.length() + cn);
+            // 5.2 (6a)
+            if (i >= 0)
+                sb.append(base.substring(0, i + 1));
+            // 5.2 (6b)
+            sb.append(child);
+            path = sb.toString();
+        }
+
+        // 5.2 (6c-f)
+        // Android-changed: App compat. Remove leading dots when resolving path. http://b/25897693
+        // String np = normalize(path);
+        String np = normalize(path, true);
+
+        // 5.2 (6g): If the result is absolute but the path begins with "../",
+        // then we simply leave the path as-is
+
+        return np;
+    }
+
+    // RFC2396 5.2
+    private static URI resolve(URI base, URI child) {
+        // check if child if opaque first so that NPE is thrown
+        // if child is null.
+        if (child.isOpaque() || base.isOpaque())
+            return child;
+
+        // 5.2 (2): Reference to current document (lone fragment)
+        if ((child.scheme == null) && (child.authority == null)
+            && child.path.equals("") && (child.fragment != null)
+            && (child.query == null)) {
+            if ((base.fragment != null)
+                && child.fragment.equals(base.fragment)) {
+                return base;
+            }
+            URI ru = new URI();
+            ru.scheme = base.scheme;
+            ru.authority = base.authority;
+            ru.userInfo = base.userInfo;
+            ru.host = base.host;
+            ru.port = base.port;
+            ru.path = base.path;
+            ru.fragment = child.fragment;
+            ru.query = base.query;
+            return ru;
+        }
+
+        // 5.2 (3): Child is absolute
+        if (child.scheme != null)
+            return child;
+
+        URI ru = new URI();             // Resolved URI
+        ru.scheme = base.scheme;
+        ru.query = child.query;
+        ru.fragment = child.fragment;
+
+        // 5.2 (4): Authority
+        if (child.authority == null) {
+            ru.authority = base.authority;
+            ru.host = base.host;
+            ru.userInfo = base.userInfo;
+            ru.port = base.port;
+
+            // BEGIN Android-changed: App Compat. Handle null and empty path using RFC 3986 logic
+            // http://b/25897693
+            if (child.path == null || child.path.isEmpty()) {
+                // This is an additional path from RFC 3986 RI, which fixes following RFC 2396
+                // "normal" examples:
+                // Base: http://a/b/c/d;p?q
+                //   "?y" = "http://a/b/c/d;p?y"
+                //   ""   = "http://a/b/c/d;p?q"
+                // http://b/25897693
+                ru.path = base.path;
+                ru.query = child.query != null ? child.query : base.query;
+            // END Android-changed: App Compat. Handle null and empty path using RFC 3986 logic
+            } else if ((child.path.length() > 0) && (child.path.charAt(0) == '/')) {
+                // 5.2 (5): Child path is absolute
+                //
+                // Android-changed: App Compat. Remove leading dots in path.
+                // There is an additional step from RFC 3986 RI, requiring to remove dots for
+                // absolute path as well.
+                // http://b/25897693
+                // ru.path = child.path;
+                ru.path = normalize(child.path, true);
+            } else {
+                // 5.2 (6): Resolve relative path
+                ru.path = resolvePath(base.path, child.path, base.isAbsolute());
+            }
+        } else {
+            ru.authority = child.authority;
+            ru.host = child.host;
+            ru.userInfo = child.userInfo;
+            ru.host = child.host;
+            ru.port = child.port;
+            ru.path = child.path;
+        }
+
+        // 5.2 (7): Recombine (nothing to do here)
+        return ru;
+    }
+
+    // If the given URI's path is normal then return the URI;
+    // o.w., return a new URI containing the normalized path.
+    //
+    private static URI normalize(URI u) {
+        if (u.isOpaque() || (u.path == null) || (u.path.length() == 0))
+            return u;
+
+        String np = normalize(u.path);
+        if (np == u.path)
+            return u;
+
+        URI v = new URI();
+        v.scheme = u.scheme;
+        v.fragment = u.fragment;
+        v.authority = u.authority;
+        v.userInfo = u.userInfo;
+        v.host = u.host;
+        v.port = u.port;
+        v.path = np;
+        v.query = u.query;
+        return v;
+    }
+
+    // If both URIs are hierarchical, their scheme and authority components are
+    // identical, and the base path is a prefix of the child's path, then
+    // return a relative URI that, when resolved against the base, yields the
+    // child; otherwise, return the child.
+    //
+    private static URI relativize(URI base, URI child) {
+        // check if child if opaque first so that NPE is thrown
+        // if child is null.
+        if (child.isOpaque() || base.isOpaque())
+            return child;
+        if (!equalIgnoringCase(base.scheme, child.scheme)
+            || !equal(base.authority, child.authority))
+            return child;
+
+        String bp = normalize(base.path);
+        String cp = normalize(child.path);
+        if (!bp.equals(cp)) {
+            // Android-changed: App Compat. Interpret ambiguous base path as a file, not a directory
+            // Upstream would append '/' to bp if not present, interpreting it as a directory; thus,
+            // /a/b/c relative to /a/b would become /c, whereas Android would relativize to /b/c.
+            // The spec is pretty vague about this but the Android behavior is kept because several
+            // tests enforce it.
+            // if (!bp.endsWith("/"))
+            //     bp = bp + "/";
+            if (bp.indexOf('/') != -1) {
+                bp = bp.substring(0, bp.lastIndexOf('/') + 1);
+            }
+
+            if (!cp.startsWith(bp))
+                return child;
+        }
+
+        URI v = new URI();
+        v.path = cp.substring(bp.length());
+        v.query = child.query;
+        v.fragment = child.fragment;
+        return v;
+    }
+
+
+
+    // -- Path normalization --
+
+    // The following algorithm for path normalization avoids the creation of a
+    // string object for each segment, as well as the use of a string buffer to
+    // compute the final result, by using a single char array and editing it in
+    // place.  The array is first split into segments, replacing each slash
+    // with '\0' and creating a segment-index array, each element of which is
+    // the index of the first char in the corresponding segment.  We then walk
+    // through both arrays, removing ".", "..", and other segments as necessary
+    // by setting their entries in the index array to -1.  Finally, the two
+    // arrays are used to rejoin the segments and compute the final result.
+    //
+    // This code is based upon src/solaris/native/java/io/canonicalize_md.c
+
+
+    // Check the given path to see if it might need normalization.  A path
+    // might need normalization if it contains duplicate slashes, a "."
+    // segment, or a ".." segment.  Return -1 if no further normalization is
+    // possible, otherwise return the number of segments found.
+    //
+    // This method takes a string argument rather than a char array so that
+    // this test can be performed without invoking path.toCharArray().
+    //
+    static private int needsNormalization(String path) {
+        boolean normal = true;
+        int ns = 0;                     // Number of segments
+        int end = path.length() - 1;    // Index of last char in path
+        int p = 0;                      // Index of next char in path
+
+        // Skip initial slashes
+        while (p <= end) {
+            if (path.charAt(p) != '/') break;
+            p++;
+        }
+        if (p > 1) normal = false;
+
+        // Scan segments
+        while (p <= end) {
+
+            // Looking at "." or ".." ?
+            if ((path.charAt(p) == '.')
+                && ((p == end)
+                    || ((path.charAt(p + 1) == '/')
+                        || ((path.charAt(p + 1) == '.')
+                            && ((p + 1 == end)
+                                || (path.charAt(p + 2) == '/')))))) {
+                normal = false;
+            }
+            ns++;
+
+            // Find beginning of next segment
+            while (p <= end) {
+                if (path.charAt(p++) != '/')
+                    continue;
+
+                // Skip redundant slashes
+                while (p <= end) {
+                    if (path.charAt(p) != '/') break;
+                    normal = false;
+                    p++;
+                }
+
+                break;
+            }
+        }
+
+        return normal ? -1 : ns;
+    }
+
+
+    // Split the given path into segments, replacing slashes with nulls and
+    // filling in the given segment-index array.
+    //
+    // Preconditions:
+    //   segs.length == Number of segments in path
+    //
+    // Postconditions:
+    //   All slashes in path replaced by '\0'
+    //   segs[i] == Index of first char in segment i (0 <= i < segs.length)
+    //
+    static private void split(char[] path, int[] segs) {
+        int end = path.length - 1;      // Index of last char in path
+        int p = 0;                      // Index of next char in path
+        int i = 0;                      // Index of current segment
+
+        // Skip initial slashes
+        while (p <= end) {
+            if (path[p] != '/') break;
+            path[p] = '\0';
+            p++;
+        }
+
+        while (p <= end) {
+
+            // Note start of segment
+            segs[i++] = p++;
+
+            // Find beginning of next segment
+            while (p <= end) {
+                if (path[p++] != '/')
+                    continue;
+                path[p - 1] = '\0';
+
+                // Skip redundant slashes
+                while (p <= end) {
+                    if (path[p] != '/') break;
+                    path[p++] = '\0';
+                }
+                break;
+            }
+        }
+
+        if (i != segs.length)
+            throw new InternalError();  // ASSERT
+    }
+
+
+    // Join the segments in the given path according to the given segment-index
+    // array, ignoring those segments whose index entries have been set to -1,
+    // and inserting slashes as needed.  Return the length of the resulting
+    // path.
+    //
+    // Preconditions:
+    //   segs[i] == -1 implies segment i is to be ignored
+    //   path computed by split, as above, with '\0' having replaced '/'
+    //
+    // Postconditions:
+    //   path[0] .. path[return value] == Resulting path
+    //
+    static private int join(char[] path, int[] segs) {
+        int ns = segs.length;           // Number of segments
+        int end = path.length - 1;      // Index of last char in path
+        int p = 0;                      // Index of next path char to write
+
+        if (path[p] == '\0') {
+            // Restore initial slash for absolute paths
+            path[p++] = '/';
+        }
+
+        for (int i = 0; i < ns; i++) {
+            int q = segs[i];            // Current segment
+            if (q == -1)
+                // Ignore this segment
+                continue;
+
+            if (p == q) {
+                // We're already at this segment, so just skip to its end
+                while ((p <= end) && (path[p] != '\0'))
+                    p++;
+                if (p <= end) {
+                    // Preserve trailing slash
+                    path[p++] = '/';
+                }
+            } else if (p < q) {
+                // Copy q down to p
+                while ((q <= end) && (path[q] != '\0'))
+                    path[p++] = path[q++];
+                if (q <= end) {
+                    // Preserve trailing slash
+                    path[p++] = '/';
+                }
+            } else
+                throw new InternalError(); // ASSERT false
+        }
+
+        return p;
+    }
+
+
+    // Remove "." segments from the given path, and remove segment pairs
+    // consisting of a non-".." segment followed by a ".." segment.
+    //
+    // Android-changed: App compat. Remove leading dots when resolving path. http://b/25897693
+    // private static void removeDots(char[] path, int[] segs) {
+    private static void removeDots(char[] path, int[] segs, boolean removeLeading) {
+        int ns = segs.length;
+        int end = path.length - 1;
+
+        for (int i = 0; i < ns; i++) {
+            int dots = 0;               // Number of dots found (0, 1, or 2)
+
+            // Find next occurrence of "." or ".."
+            do {
+                int p = segs[i];
+                if (path[p] == '.') {
+                    if (p == end) {
+                        dots = 1;
+                        break;
+                    } else if (path[p + 1] == '\0') {
+                        dots = 1;
+                        break;
+                    } else if ((path[p + 1] == '.')
+                               && ((p + 1 == end)
+                                   || (path[p + 2] == '\0'))) {
+                        dots = 2;
+                        break;
+                    }
+                }
+                i++;
+            } while (i < ns);
+            if ((i > ns) || (dots == 0))
+                break;
+
+            if (dots == 1) {
+                // Remove this occurrence of "."
+                segs[i] = -1;
+            } else {
+                // If there is a preceding non-".." segment, remove both that
+                // segment and this occurrence of ".."
+                int j;
+                for (j = i - 1; j >= 0; j--) {
+                    if (segs[j] != -1) break;
+                }
+                if (j >= 0) {
+                    int q = segs[j];
+                    if (!((path[q] == '.')
+                          && (path[q + 1] == '.')
+                          && (path[q + 2] == '\0'))) {
+                        segs[i] = -1;
+                        segs[j] = -1;
+                    }
+                // Android-added: App compat. Remove leading dots when resolving path.
+                // This is a leading ".." segment. Per RFC 3986 RI, this should be removed as
+                // well. This fixes RFC 2396 "abnormal" examples.
+                // http://b/25897693
+                } else if (removeLeading) {
+                    segs[i] = -1;
+                }
+            }
+        }
+    }
+
+
+    // DEVIATION: If the normalized path is relative, and if the first
+    // segment could be parsed as a scheme name, then prepend a "." segment
+    //
+    private static void maybeAddLeadingDot(char[] path, int[] segs) {
+
+        if (path[0] == '\0')
+            // The path is absolute
+            return;
+
+        int ns = segs.length;
+        int f = 0;                      // Index of first segment
+        while (f < ns) {
+            if (segs[f] >= 0)
+                break;
+            f++;
+        }
+        if ((f >= ns) || (f == 0))
+            // The path is empty, or else the original first segment survived,
+            // in which case we already know that no leading "." is needed
+            return;
+
+        int p = segs[f];
+        while ((p < path.length) && (path[p] != ':') && (path[p] != '\0')) p++;
+        if (p >= path.length || path[p] == '\0')
+            // No colon in first segment, so no "." needed
+            return;
+
+        // At this point we know that the first segment is unused,
+        // hence we can insert a "." segment at that position
+        path[0] = '.';
+        path[1] = '\0';
+        segs[0] = 0;
+    }
+
+
+    // Normalize the given path string.  A normal path string has no empty
+    // segments (i.e., occurrences of "//"), no segments equal to ".", and no
+    // segments equal to ".." that are preceded by a segment not equal to "..".
+    // In contrast to Unix-style pathname normalization, for URI paths we
+    // always retain trailing slashes.
+    //
+    private static String normalize(String ps) {
+        // BEGIN Android-changed: App compat. Remove leading dots when resolving path.
+        // Controlled by the "boolean removeLeading" argument added to normalize().
+        return normalize(ps, false);
+    }
+
+    private static String normalize(String ps, boolean removeLeading) {
+        // END Android-changed: App compat. Remove leading dots when resolving path.
+        // Does this path need normalization?
+        int ns = needsNormalization(ps);        // Number of segments
+        if (ns < 0)
+            // Nope -- just return it
+            return ps;
+
+        char[] path = ps.toCharArray();         // Path in char-array form
+
+        // Split path into segments
+        int[] segs = new int[ns];               // Segment-index array
+        split(path, segs);
+
+        // Remove dots
+        // Android-changed: App compat. Remove leading dots when resolving path.
+        // removeDots(path, segs);
+        removeDots(path, segs, removeLeading);
+
+        // Prevent scheme-name confusion
+        maybeAddLeadingDot(path, segs);
+
+        // Join the remaining segments and return the result
+        String s = new String(path, 0, join(path, segs));
+        if (s.equals(ps)) {
+            // string was already normalized
+            return ps;
+        }
+        return s;
+    }
+
+
+
+    // -- Character classes for parsing --
+
+    // RFC2396 precisely specifies which characters in the US-ASCII charset are
+    // permissible in the various components of a URI reference.  We here
+    // define a set of mask pairs to aid in enforcing these restrictions.  Each
+    // mask pair consists of two longs, a low mask and a high mask.  Taken
+    // together they represent a 128-bit mask, where bit i is set iff the
+    // character with value i is permitted.
+    //
+    // This approach is more efficient than sequentially searching arrays of
+    // permitted characters.  It could be made still more efficient by
+    // precompiling the mask information so that a character's presence in a
+    // given mask could be determined by a single table lookup.
+
+    // Compute the low-order mask for the characters in the given string
+    private static long lowMask(String chars) {
+        int n = chars.length();
+        long m = 0;
+        for (int i = 0; i < n; i++) {
+            char c = chars.charAt(i);
+            if (c < 64)
+                m |= (1L << c);
+        }
+        return m;
+    }
+
+    // Compute the high-order mask for the characters in the given string
+    private static long highMask(String chars) {
+        int n = chars.length();
+        long m = 0;
+        for (int i = 0; i < n; i++) {
+            char c = chars.charAt(i);
+            if ((c >= 64) && (c < 128))
+                m |= (1L << (c - 64));
+        }
+        return m;
+    }
+
+    // Compute a low-order mask for the characters
+    // between first and last, inclusive
+    private static long lowMask(char first, char last) {
+        long m = 0;
+        int f = Math.max(Math.min(first, 63), 0);
+        int l = Math.max(Math.min(last, 63), 0);
+        for (int i = f; i <= l; i++)
+            m |= 1L << i;
+        return m;
+    }
+
+    // Compute a high-order mask for the characters
+    // between first and last, inclusive
+    private static long highMask(char first, char last) {
+        long m = 0;
+        int f = Math.max(Math.min(first, 127), 64) - 64;
+        int l = Math.max(Math.min(last, 127), 64) - 64;
+        for (int i = f; i <= l; i++)
+            m |= 1L << i;
+        return m;
+    }
+
+    // Tell whether the given character is permitted by the given mask pair
+    private static boolean match(char c, long lowMask, long highMask) {
+        if (c == 0) // 0 doesn't have a slot in the mask. So, it never matches.
+            return false;
+        if (c < 64)
+            return ((1L << c) & lowMask) != 0;
+        if (c < 128)
+            return ((1L << (c - 64)) & highMask) != 0;
+        return false;
+    }
+
+    // Character-class masks, in reverse order from RFC2396 because
+    // initializers for static fields cannot make forward references.
+
+    // digit    = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
+    //            "8" | "9"
+    private static final long L_DIGIT = lowMask('0', '9');
+    private static final long H_DIGIT = 0L;
+
+    // upalpha  = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
+    //            "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
+    //            "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
+    private static final long L_UPALPHA = 0L;
+    private static final long H_UPALPHA = highMask('A', 'Z');
+
+    // lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
+    //            "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
+    //            "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
+    private static final long L_LOWALPHA = 0L;
+    private static final long H_LOWALPHA = highMask('a', 'z');
+
+    // alpha         = lowalpha | upalpha
+    private static final long L_ALPHA = L_LOWALPHA | L_UPALPHA;
+    private static final long H_ALPHA = H_LOWALPHA | H_UPALPHA;
+
+    // alphanum      = alpha | digit
+    private static final long L_ALPHANUM = L_DIGIT | L_ALPHA;
+    private static final long H_ALPHANUM = H_DIGIT | H_ALPHA;
+
+    // hex           = digit | "A" | "B" | "C" | "D" | "E" | "F" |
+    //                         "a" | "b" | "c" | "d" | "e" | "f"
+    private static final long L_HEX = L_DIGIT;
+    private static final long H_HEX = highMask('A', 'F') | highMask('a', 'f');
+
+    // mark          = "-" | "_" | "." | "!" | "~" | "*" | "'" |
+    //                 "(" | ")"
+    private static final long L_MARK = lowMask("-_.!~*'()");
+    private static final long H_MARK = highMask("-_.!~*'()");
+
+    // unreserved    = alphanum | mark
+    private static final long L_UNRESERVED = L_ALPHANUM | L_MARK;
+    private static final long H_UNRESERVED = H_ALPHANUM | H_MARK;
+
+    // reserved      = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
+    //                 "$" | "," | "[" | "]"
+    // Added per RFC2732: "[", "]"
+    private static final long L_RESERVED = lowMask(";/?:@&=+$,[]");
+    private static final long H_RESERVED = highMask(";/?:@&=+$,[]");
+
+    // The zero'th bit is used to indicate that escape pairs and non-US-ASCII
+    // characters are allowed; this is handled by the scanEscape method below.
+    private static final long L_ESCAPED = 1L;
+    private static final long H_ESCAPED = 0L;
+
+    // uric          = reserved | unreserved | escaped
+    private static final long L_URIC = L_RESERVED | L_UNRESERVED | L_ESCAPED;
+    private static final long H_URIC = H_RESERVED | H_UNRESERVED | H_ESCAPED;
+
+    // pchar         = unreserved | escaped |
+    //                 ":" | "@" | "&" | "=" | "+" | "$" | ","
+    private static final long L_PCHAR
+        = L_UNRESERVED | L_ESCAPED | lowMask(":@&=+$,");
+    private static final long H_PCHAR
+        = H_UNRESERVED | H_ESCAPED | highMask(":@&=+$,");
+
+    // All valid path characters
+    private static final long L_PATH = L_PCHAR | lowMask(";/");
+    private static final long H_PATH = H_PCHAR | highMask(";/");
+
+    // Dash, for use in domainlabel and toplabel
+    private static final long L_DASH = lowMask("-");
+    private static final long H_DASH = highMask("-");
+
+    // BEGIN Android-added: Allow underscore in hostname.
+    // UNDERSCORE, for use in domainlabel and toplabel
+    private static final long L_UNDERSCORE = lowMask("_");
+    private static final long H_UNDERSCORE = highMask("_");
+    // END Android-added: Allow underscore in hostname.
+
+    // Dot, for use in hostnames
+    private static final long L_DOT = lowMask(".");
+    private static final long H_DOT = highMask(".");
+
+    // userinfo      = *( unreserved | escaped |
+    //                    ";" | ":" | "&" | "=" | "+" | "$" | "," )
+    private static final long L_USERINFO
+        = L_UNRESERVED | L_ESCAPED | lowMask(";:&=+$,");
+    private static final long H_USERINFO
+        = H_UNRESERVED | H_ESCAPED | highMask(";:&=+$,");
+
+    // reg_name      = 1*( unreserved | escaped | "$" | "," |
+    //                     ";" | ":" | "@" | "&" | "=" | "+" )
+    private static final long L_REG_NAME
+        = L_UNRESERVED | L_ESCAPED | lowMask("$,;:@&=+");
+    private static final long H_REG_NAME
+        = H_UNRESERVED | H_ESCAPED | highMask("$,;:@&=+");
+
+    // All valid characters for server-based authorities
+    private static final long L_SERVER
+        = L_USERINFO | L_ALPHANUM | L_DASH | lowMask(".:@[]");
+    private static final long H_SERVER
+        = H_USERINFO | H_ALPHANUM | H_DASH | highMask(".:@[]");
+
+    // Special case of server authority that represents an IPv6 address
+    // In this case, a % does not signify an escape sequence
+    private static final long L_SERVER_PERCENT
+        = L_SERVER | lowMask("%");
+    private static final long H_SERVER_PERCENT
+        = H_SERVER | highMask("%");
+    private static final long L_LEFT_BRACKET = lowMask("[");
+    private static final long H_LEFT_BRACKET = highMask("[");
+
+    // scheme        = alpha *( alpha | digit | "+" | "-" | "." )
+    private static final long L_SCHEME = L_ALPHA | L_DIGIT | lowMask("+-.");
+    private static final long H_SCHEME = H_ALPHA | H_DIGIT | highMask("+-.");
+
+    // uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
+    //                 "&" | "=" | "+" | "$" | ","
+    private static final long L_URIC_NO_SLASH
+        = L_UNRESERVED | L_ESCAPED | lowMask(";?:@&=+$,");
+    private static final long H_URIC_NO_SLASH
+        = H_UNRESERVED | H_ESCAPED | highMask(";?:@&=+$,");
+
+
+    // -- Escaping and encoding --
+
+    private final static char[] hexDigits = {
+        '0', '1', '2', '3', '4', '5', '6', '7',
+        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+    };
+
+    private static void appendEscape(StringBuffer sb, byte b) {
+        sb.append('%');
+        sb.append(hexDigits[(b >> 4) & 0x0f]);
+        sb.append(hexDigits[(b >> 0) & 0x0f]);
+    }
+
+    private static void appendEncoded(StringBuffer sb, char c) {
+        ByteBuffer bb = null;
+        try {
+            bb = ThreadLocalCoders.encoderFor("UTF-8")
+                .encode(CharBuffer.wrap("" + c));
+        } catch (CharacterCodingException x) {
+            assert false;
+        }
+        while (bb.hasRemaining()) {
+            int b = bb.get() & 0xff;
+            if (b >= 0x80)
+                appendEscape(sb, (byte)b);
+            else
+                sb.append((char)b);
+        }
+    }
+
+    // Quote any characters in s that are not permitted
+    // by the given mask pair
+    //
+    private static String quote(String s, long lowMask, long highMask) {
+        int n = s.length();
+        StringBuffer sb = null;
+        boolean allowNonASCII = ((lowMask & L_ESCAPED) != 0);
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            if (c < '\u0080') {
+                if (!match(c, lowMask, highMask)) {
+                    if (sb == null) {
+                        sb = new StringBuffer();
+                        sb.append(s.substring(0, i));
+                    }
+                    appendEscape(sb, (byte)c);
+                } else {
+                    if (sb != null)
+                        sb.append(c);
+                }
+            } else if (allowNonASCII
+                       && (Character.isSpaceChar(c)
+                           || Character.isISOControl(c))) {
+                if (sb == null) {
+                    sb = new StringBuffer();
+                    sb.append(s.substring(0, i));
+                }
+                appendEncoded(sb, c);
+            } else {
+                if (sb != null)
+                    sb.append(c);
+            }
+        }
+        return (sb == null) ? s : sb.toString();
+    }
+
+    // Encodes all characters >= \u0080 into escaped, normalized UTF-8 octets,
+    // assuming that s is otherwise legal
+    //
+    private static String encode(String s) {
+        int n = s.length();
+        if (n == 0)
+            return s;
+
+        // First check whether we actually need to encode
+        for (int i = 0;;) {
+            if (s.charAt(i) >= '\u0080')
+                break;
+            if (++i >= n)
+                return s;
+        }
+
+        String ns = Normalizer.normalize(s, Normalizer.Form.NFC);
+        ByteBuffer bb = null;
+        try {
+            bb = ThreadLocalCoders.encoderFor("UTF-8")
+                .encode(CharBuffer.wrap(ns));
+        } catch (CharacterCodingException x) {
+            assert false;
+        }
+
+        StringBuffer sb = new StringBuffer();
+        while (bb.hasRemaining()) {
+            int b = bb.get() & 0xff;
+            if (b >= 0x80)
+                appendEscape(sb, (byte)b);
+            else
+                sb.append((char)b);
+        }
+        return sb.toString();
+    }
+
+    private static int decode(char c) {
+        if ((c >= '0') && (c <= '9'))
+            return c - '0';
+        if ((c >= 'a') && (c <= 'f'))
+            return c - 'a' + 10;
+        if ((c >= 'A') && (c <= 'F'))
+            return c - 'A' + 10;
+        assert false;
+        return -1;
+    }
+
+    private static byte decode(char c1, char c2) {
+        return (byte)(  ((decode(c1) & 0xf) << 4)
+                      | ((decode(c2) & 0xf) << 0));
+    }
+
+    // Evaluates all escapes in s, applying UTF-8 decoding if needed.  Assumes
+    // that escapes are well-formed syntactically, i.e., of the form %XX.  If a
+    // sequence of escaped octets is not valid UTF-8 then the erroneous octets
+    // are replaced with '\uFFFD'.
+    // Exception: any "%" found between "[]" is left alone. It is an IPv6 literal
+    //            with a scope_id
+    //
+    private static String decode(String s) {
+        if (s == null)
+            return s;
+        int n = s.length();
+        if (n == 0)
+            return s;
+        if (s.indexOf('%') < 0)
+            return s;
+
+        StringBuffer sb = new StringBuffer(n);
+        ByteBuffer bb = ByteBuffer.allocate(n);
+        CharBuffer cb = CharBuffer.allocate(n);
+        CharsetDecoder dec = ThreadLocalCoders.decoderFor("UTF-8")
+            .onMalformedInput(CodingErrorAction.REPLACE)
+            .onUnmappableCharacter(CodingErrorAction.REPLACE);
+
+        // This is not horribly efficient, but it will do for now
+        char c = s.charAt(0);
+        boolean betweenBrackets = false;
+
+        for (int i = 0; i < n;) {
+            assert c == s.charAt(i);    // Loop invariant
+            if (c == '[') {
+                betweenBrackets = true;
+            } else if (betweenBrackets && c == ']') {
+                betweenBrackets = false;
+            }
+            if (c != '%' || betweenBrackets) {
+                sb.append(c);
+                if (++i >= n)
+                    break;
+                c = s.charAt(i);
+                continue;
+            }
+            bb.clear();
+            int ui = i;
+            for (;;) {
+                assert (n - i >= 2);
+                bb.put(decode(s.charAt(++i), s.charAt(++i)));
+                if (++i >= n)
+                    break;
+                c = s.charAt(i);
+                if (c != '%')
+                    break;
+            }
+            bb.flip();
+            cb.clear();
+            dec.reset();
+            CoderResult cr = dec.decode(bb, cb, true);
+            assert cr.isUnderflow();
+            cr = dec.flush(cb);
+            assert cr.isUnderflow();
+            sb.append(cb.flip().toString());
+        }
+
+        return sb.toString();
+    }
+
+
+    // -- Parsing --
+
+    // For convenience we wrap the input URI string in a new instance of the
+    // following internal class.  This saves always having to pass the input
+    // string as an argument to each internal scan/parse method.
+
+    private class Parser {
+
+        private String input;           // URI input string
+        private boolean requireServerAuthority = false;
+
+        Parser(String s) {
+            input = s;
+            string = s;
+        }
+
+        // -- Methods for throwing URISyntaxException in various ways --
+
+        private void fail(String reason) throws URISyntaxException {
+            throw new URISyntaxException(input, reason);
+        }
+
+        private void fail(String reason, int p) throws URISyntaxException {
+            throw new URISyntaxException(input, reason, p);
+        }
+
+        private void failExpecting(String expected, int p)
+            throws URISyntaxException
+        {
+            fail("Expected " + expected, p);
+        }
+
+        private void failExpecting(String expected, String prior, int p)
+            throws URISyntaxException
+        {
+            fail("Expected " + expected + " following " + prior, p);
+        }
+
+
+        // -- Simple access to the input string --
+
+        // Return a substring of the input string
+        //
+        private String substring(int start, int end) {
+            return input.substring(start, end);
+        }
+
+        // Return the char at position p,
+        // assuming that p < input.length()
+        //
+        private char charAt(int p) {
+            return input.charAt(p);
+        }
+
+        // Tells whether start < end and, if so, whether charAt(start) == c
+        //
+        private boolean at(int start, int end, char c) {
+            return (start < end) && (charAt(start) == c);
+        }
+
+        // Tells whether start + s.length() < end and, if so,
+        // whether the chars at the start position match s exactly
+        //
+        private boolean at(int start, int end, String s) {
+            int p = start;
+            int sn = s.length();
+            if (sn > end - p)
+                return false;
+            int i = 0;
+            while (i < sn) {
+                if (charAt(p++) != s.charAt(i)) {
+                    break;
+                }
+                i++;
+            }
+            return (i == sn);
+        }
+
+
+        // -- Scanning --
+
+        // The various scan and parse methods that follow use a uniform
+        // convention of taking the current start position and end index as
+        // their first two arguments.  The start is inclusive while the end is
+        // exclusive, just as in the String class, i.e., a start/end pair
+        // denotes the left-open interval [start, end) of the input string.
+        //
+        // These methods never proceed past the end position.  They may return
+        // -1 to indicate outright failure, but more often they simply return
+        // the position of the first char after the last char scanned.  Thus
+        // a typical idiom is
+        //
+        //     int p = start;
+        //     int q = scan(p, end, ...);
+        //     if (q > p)
+        //         // We scanned something
+        //         ...;
+        //     else if (q == p)
+        //         // We scanned nothing
+        //         ...;
+        //     else if (q == -1)
+        //         // Something went wrong
+        //         ...;
+
+
+        // Scan a specific char: If the char at the given start position is
+        // equal to c, return the index of the next char; otherwise, return the
+        // start position.
+        //
+        private int scan(int start, int end, char c) {
+            if ((start < end) && (charAt(start) == c))
+                return start + 1;
+            return start;
+        }
+
+        // Scan forward from the given start position.  Stop at the first char
+        // in the err string (in which case -1 is returned), or the first char
+        // in the stop string (in which case the index of the preceding char is
+        // returned), or the end of the input string (in which case the length
+        // of the input string is returned).  May return the start position if
+        // nothing matches.
+        //
+        private int scan(int start, int end, String err, String stop) {
+            int p = start;
+            while (p < end) {
+                char c = charAt(p);
+                if (err.indexOf(c) >= 0)
+                    return -1;
+                if (stop.indexOf(c) >= 0)
+                    break;
+                p++;
+            }
+            return p;
+        }
+
+        // Scan a potential escape sequence, starting at the given position,
+        // with the given first char (i.e., charAt(start) == c).
+        //
+        // This method assumes that if escapes are allowed then visible
+        // non-US-ASCII chars are also allowed.
+        //
+        private int scanEscape(int start, int n, char first)
+            throws URISyntaxException
+        {
+            int p = start;
+            char c = first;
+            if (c == '%') {
+                // Process escape pair
+                if ((p + 3 <= n)
+                    && match(charAt(p + 1), L_HEX, H_HEX)
+                    && match(charAt(p + 2), L_HEX, H_HEX)) {
+                    return p + 3;
+                }
+                fail("Malformed escape pair", p);
+            } else if ((c > 128)
+                       && !Character.isSpaceChar(c)
+                       && !Character.isISOControl(c)) {
+                // Allow unescaped but visible non-US-ASCII chars
+                return p + 1;
+            }
+            return p;
+        }
+
+        // Scan chars that match the given mask pair
+        //
+        private int scan(int start, int n, long lowMask, long highMask)
+            throws URISyntaxException
+        {
+            int p = start;
+            while (p < n) {
+                char c = charAt(p);
+                if (match(c, lowMask, highMask)) {
+                    p++;
+                    continue;
+                }
+                if ((lowMask & L_ESCAPED) != 0) {
+                    int q = scanEscape(p, n, c);
+                    if (q > p) {
+                        p = q;
+                        continue;
+                    }
+                }
+                break;
+            }
+            return p;
+        }
+
+        // Check that each of the chars in [start, end) matches the given mask
+        //
+        private void checkChars(int start, int end,
+                                long lowMask, long highMask,
+                                String what)
+            throws URISyntaxException
+        {
+            int p = scan(start, end, lowMask, highMask);
+            if (p < end)
+                fail("Illegal character in " + what, p);
+        }
+
+        // Check that the char at position p matches the given mask
+        //
+        private void checkChar(int p,
+                               long lowMask, long highMask,
+                               String what)
+            throws URISyntaxException
+        {
+            checkChars(p, p + 1, lowMask, highMask, what);
+        }
+
+
+        // -- Parsing --
+
+        // [<scheme>:]<scheme-specific-part>[#<fragment>]
+        //
+        void parse(boolean rsa) throws URISyntaxException {
+            requireServerAuthority = rsa;
+            int ssp;                    // Start of scheme-specific part
+            int n = input.length();
+            int p = scan(0, n, "/?#", ":");
+            if ((p >= 0) && at(p, n, ':')) {
+                if (p == 0)
+                    failExpecting("scheme name", 0);
+                checkChar(0, L_ALPHA, H_ALPHA, "scheme name");
+                checkChars(1, p, L_SCHEME, H_SCHEME, "scheme name");
+                scheme = substring(0, p);
+                p++;                    // Skip ':'
+                ssp = p;
+                if (at(p, n, '/')) {
+                    p = parseHierarchical(p, n);
+                } else {
+                    int q = scan(p, n, "", "#");
+                    if (q <= p)
+                        failExpecting("scheme-specific part", p);
+                    checkChars(p, q, L_URIC, H_URIC, "opaque part");
+                    p = q;
+                }
+            } else {
+                ssp = 0;
+                p = parseHierarchical(0, n);
+            }
+            schemeSpecificPart = substring(ssp, p);
+            if (at(p, n, '#')) {
+                checkChars(p + 1, n, L_URIC, H_URIC, "fragment");
+                fragment = substring(p + 1, n);
+                p = n;
+            }
+            if (p < n)
+                fail("end of URI", p);
+        }
+
+        // [//authority]<path>[?<query>]
+        //
+        // DEVIATION from RFC2396: We allow an empty authority component as
+        // long as it's followed by a non-empty path, query component, or
+        // fragment component.  This is so that URIs such as "file:///foo/bar"
+        // will parse.  This seems to be the intent of RFC2396, though the
+        // grammar does not permit it.  If the authority is empty then the
+        // userInfo, host, and port components are undefined.
+        //
+        // DEVIATION from RFC2396: We allow empty relative paths.  This seems
+        // to be the intent of RFC2396, but the grammar does not permit it.
+        // The primary consequence of this deviation is that "#f" parses as a
+        // relative URI with an empty path.
+        //
+        private int parseHierarchical(int start, int n)
+            throws URISyntaxException
+        {
+            int p = start;
+            if (at(p, n, '/') && at(p + 1, n, '/')) {
+                p += 2;
+                int q = scan(p, n, "", "/?#");
+                if (q > p) {
+                    p = parseAuthority(p, q);
+                } else if (q < n) {
+                    // DEVIATION: Allow empty authority prior to non-empty
+                    // path, query component or fragment identifier
+                } else
+                    failExpecting("authority", p);
+            }
+            int q = scan(p, n, "", "?#"); // DEVIATION: May be empty
+            checkChars(p, q, L_PATH, H_PATH, "path");
+            path = substring(p, q);
+            p = q;
+            if (at(p, n, '?')) {
+                p++;
+                q = scan(p, n, "", "#");
+                checkChars(p, q, L_URIC, H_URIC, "query");
+                query = substring(p, q);
+                p = q;
+            }
+            return p;
+        }
+
+        // authority     = server | reg_name
+        //
+        // Ambiguity: An authority that is a registry name rather than a server
+        // might have a prefix that parses as a server.  We use the fact that
+        // the authority component is always followed by '/' or the end of the
+        // input string to resolve this: If the complete authority did not
+        // parse as a server then we try to parse it as a registry name.
+        //
+        private int parseAuthority(int start, int n)
+            throws URISyntaxException
+        {
+            int p = start;
+            int q = p;
+            URISyntaxException ex = null;
+
+            boolean serverChars;
+            boolean regChars;
+
+            if (scan(p, n, "", "]") > p) {
+                // contains a literal IPv6 address, therefore % is allowed
+                serverChars = (scan(p, n, L_SERVER_PERCENT, H_SERVER_PERCENT) == n);
+            } else {
+                serverChars = (scan(p, n, L_SERVER, H_SERVER) == n);
+            }
+            regChars = (scan(p, n, L_REG_NAME, H_REG_NAME) == n);
+
+            if (regChars && !serverChars) {
+                // Must be a registry-based authority
+                authority = substring(p, n);
+                return n;
+            }
+
+            if (serverChars) {
+                // Might be (probably is) a server-based authority, so attempt
+                // to parse it as such.  If the attempt fails, try to treat it
+                // as a registry-based authority.
+                try {
+                    q = parseServer(p, n);
+                    if (q < n)
+                        failExpecting("end of authority", q);
+                    authority = substring(p, n);
+                } catch (URISyntaxException x) {
+                    // Undo results of failed parse
+                    userInfo = null;
+                    host = null;
+                    port = -1;
+                    if (requireServerAuthority) {
+                        // If we're insisting upon a server-based authority,
+                        // then just re-throw the exception
+                        throw x;
+                    } else {
+                        // Save the exception in case it doesn't parse as a
+                        // registry either
+                        ex = x;
+                        q = p;
+                    }
+                }
+            }
+
+            if (q < n) {
+                if (regChars) {
+                    // Registry-based authority
+                    authority = substring(p, n);
+                } else if (ex != null) {
+                    // Re-throw exception; it was probably due to
+                    // a malformed IPv6 address
+                    throw ex;
+                } else {
+                    fail("Illegal character in authority", q);
+                }
+            }
+
+            return n;
+        }
+
+
+        // [<userinfo>@]<host>[:<port>]
+        //
+        private int parseServer(int start, int n)
+            throws URISyntaxException
+        {
+            int p = start;
+            int q;
+
+            // userinfo
+            q = scan(p, n, "/?#", "@");
+            if ((q >= p) && at(q, n, '@')) {
+                checkChars(p, q, L_USERINFO, H_USERINFO, "user info");
+                userInfo = substring(p, q);
+                p = q + 1;              // Skip '@'
+            }
+
+            // hostname, IPv4 address, or IPv6 address
+            if (at(p, n, '[')) {
+                // DEVIATION from RFC2396: Support IPv6 addresses, per RFC2732
+                p++;
+                q = scan(p, n, "/?#", "]");
+                if ((q > p) && at(q, n, ']')) {
+                    // look for a "%" scope id
+                    int r = scan (p, q, "", "%");
+                    if (r > p) {
+                        parseIPv6Reference(p, r);
+                        if (r+1 == q) {
+                            fail ("scope id expected");
+                        }
+                        checkChars (r+1, q, L_ALPHANUM, H_ALPHANUM,
+                                                "scope id");
+                    } else {
+                        parseIPv6Reference(p, q);
+                    }
+                    host = substring(p-1, q+1);
+                    p = q + 1;
+                } else {
+                    failExpecting("closing bracket for IPv6 address", q);
+                }
+            } else {
+                q = parseIPv4Address(p, n);
+                if (q <= p)
+                    q = parseHostname(p, n);
+                p = q;
+            }
+
+            // port
+            if (at(p, n, ':')) {
+                p++;
+                q = scan(p, n, "", "/");
+                if (q > p) {
+                    checkChars(p, q, L_DIGIT, H_DIGIT, "port number");
+                    try {
+                        port = Integer.parseInt(substring(p, q));
+                    } catch (NumberFormatException x) {
+                        fail("Malformed port number", p);
+                    }
+                    p = q;
+                }
+            }
+            if (p < n)
+                failExpecting("port number", p);
+
+            return p;
+        }
+
+        // Scan a string of decimal digits whose value fits in a byte
+        //
+        private int scanByte(int start, int n)
+            throws URISyntaxException
+        {
+            int p = start;
+            int q = scan(p, n, L_DIGIT, H_DIGIT);
+            if (q <= p) return q;
+            if (Integer.parseInt(substring(p, q)) > 255) return p;
+            return q;
+        }
+
+        // Scan an IPv4 address.
+        //
+        // If the strict argument is true then we require that the given
+        // interval contain nothing besides an IPv4 address; if it is false
+        // then we only require that it start with an IPv4 address.
+        //
+        // If the interval does not contain or start with (depending upon the
+        // strict argument) a legal IPv4 address characters then we return -1
+        // immediately; otherwise we insist that these characters parse as a
+        // legal IPv4 address and throw an exception on failure.
+        //
+        // We assume that any string of decimal digits and dots must be an IPv4
+        // address.  It won't parse as a hostname anyway, so making that
+        // assumption here allows more meaningful exceptions to be thrown.
+        //
+        private int scanIPv4Address(int start, int n, boolean strict)
+            throws URISyntaxException
+        {
+            int p = start;
+            int q;
+            int m = scan(p, n, L_DIGIT | L_DOT, H_DIGIT | H_DOT);
+            if ((m <= p) || (strict && (m != n)))
+                return -1;
+            for (;;) {
+                // Per RFC2732: At most three digits per byte
+                // Further constraint: Each element fits in a byte
+                if ((q = scanByte(p, m)) <= p) break;   p = q;
+                if ((q = scan(p, m, '.')) <= p) break;  p = q;
+                if ((q = scanByte(p, m)) <= p) break;   p = q;
+                if ((q = scan(p, m, '.')) <= p) break;  p = q;
+                if ((q = scanByte(p, m)) <= p) break;   p = q;
+                if ((q = scan(p, m, '.')) <= p) break;  p = q;
+                if ((q = scanByte(p, m)) <= p) break;   p = q;
+                if (q < m) break;
+                return q;
+            }
+            fail("Malformed IPv4 address", q);
+            return -1;
+        }
+
+        // Take an IPv4 address: Throw an exception if the given interval
+        // contains anything except an IPv4 address
+        //
+        private int takeIPv4Address(int start, int n, String expected)
+            throws URISyntaxException
+        {
+            int p = scanIPv4Address(start, n, true);
+            if (p <= start)
+                failExpecting(expected, start);
+            return p;
+        }
+
+        // Attempt to parse an IPv4 address, returning -1 on failure but
+        // allowing the given interval to contain [:<characters>] after
+        // the IPv4 address.
+        //
+        private int parseIPv4Address(int start, int n) {
+            int p;
+
+            try {
+                p = scanIPv4Address(start, n, false);
+            } catch (URISyntaxException x) {
+                return -1;
+            } catch (NumberFormatException nfe) {
+                return -1;
+            }
+
+            if (p > start && p < n) {
+                // IPv4 address is followed by something - check that
+                // it's a ":" as this is the only valid character to
+                // follow an address.
+                if (charAt(p) != ':') {
+                    p = -1;
+                }
+            }
+
+            if (p > start)
+                host = substring(start, p);
+
+            return p;
+        }
+
+        // Android-changed: Allow underscore in hostname.
+        // Added "_" to the grammars for domainLabel and topLabel.
+        // hostname      = domainlabel [ "." ] | 1*( domainlabel "." ) toplabel [ "." ]
+        // domainlabel   = alphanum | alphanum *( alphanum | "-" | "_" ) alphanum
+        // toplabel      = alpha | alpha *( alphanum | "-" | "_" ) alphanum
+        //
+        private int parseHostname(int start, int n)
+            throws URISyntaxException
+        {
+            int p = start;
+            int q;
+            int l = -1;                 // Start of last parsed label
+
+            do {
+                // Android-changed: Allow underscore in hostname.
+                // RFC 2396 only allows alphanumeric characters and hyphens, but real,
+                // large Internet hosts in the wild use underscore, so we have to allow it.
+                // http://code.google.com/p/android/issues/detail?id=37577
+                // http://b/17579865
+                // http://b/18016625
+                // http://b/18023709
+
+                // domainlabel = alphanum [ *( alphanum | "-" | "_" ) alphanum ]
+                q = scan(p, n, L_ALPHANUM, H_ALPHANUM);
+                if (q <= p)
+                    break;
+                l = p;
+                if (q > p) {
+                    p = q;
+                    // Android-changed: Allow underscore in hostname.
+                    // q = scan(p, n, L_ALPHANUM | L_DASH, H_ALPHANUM | H_DASH);
+                    q = scan(p, n, L_ALPHANUM | L_DASH | L_UNDERSCORE, H_ALPHANUM | H_DASH | H_UNDERSCORE);
+                    if (q > p) {
+                        if (charAt(q - 1) == '-')
+                            fail("Illegal character in hostname", q - 1);
+                        p = q;
+                    }
+                }
+                q = scan(p, n, '.');
+                if (q <= p)
+                    break;
+                p = q;
+            } while (p < n);
+
+            if ((p < n) && !at(p, n, ':'))
+                fail("Illegal character in hostname", p);
+
+            if (l < 0)
+                failExpecting("hostname", start);
+
+            // for a fully qualified hostname check that the rightmost
+            // label starts with an alpha character.
+            if (l > start && !match(charAt(l), L_ALPHA, H_ALPHA)) {
+                fail("Illegal character in hostname", l);
+            }
+
+            host = substring(start, p);
+            return p;
+        }
+
+
+        // IPv6 address parsing, from RFC2373: IPv6 Addressing Architecture
+        //
+        // Bug: The grammar in RFC2373 Appendix B does not allow addresses of
+        // the form ::12.34.56.78, which are clearly shown in the examples
+        // earlier in the document.  Here is the original grammar:
+        //
+        //   IPv6address = hexpart [ ":" IPv4address ]
+        //   hexpart     = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ]
+        //   hexseq      = hex4 *( ":" hex4)
+        //   hex4        = 1*4HEXDIG
+        //
+        // We therefore use the following revised grammar:
+        //
+        //   IPv6address = hexseq [ ":" IPv4address ]
+        //                 | hexseq [ "::" [ hexpost ] ]
+        //                 | "::" [ hexpost ]
+        //   hexpost     = hexseq | hexseq ":" IPv4address | IPv4address
+        //   hexseq      = hex4 *( ":" hex4)
+        //   hex4        = 1*4HEXDIG
+        //
+        // This covers all and only the following cases:
+        //
+        //   hexseq
+        //   hexseq : IPv4address
+        //   hexseq ::
+        //   hexseq :: hexseq
+        //   hexseq :: hexseq : IPv4address
+        //   hexseq :: IPv4address
+        //   :: hexseq
+        //   :: hexseq : IPv4address
+        //   :: IPv4address
+        //   ::
+        //
+        // Additionally we constrain the IPv6 address as follows :-
+        //
+        //  i.  IPv6 addresses without compressed zeros should contain
+        //      exactly 16 bytes.
+        //
+        //  ii. IPv6 addresses with compressed zeros should contain
+        //      less than 16 bytes.
+
+        private int ipv6byteCount = 0;
+
+        private int parseIPv6Reference(int start, int n)
+            throws URISyntaxException
+        {
+            int p = start;
+            int q;
+            boolean compressedZeros = false;
+
+            q = scanHexSeq(p, n);
+
+            if (q > p) {
+                p = q;
+                if (at(p, n, "::")) {
+                    compressedZeros = true;
+                    p = scanHexPost(p + 2, n);
+                } else if (at(p, n, ':')) {
+                    p = takeIPv4Address(p + 1,  n, "IPv4 address");
+                    ipv6byteCount += 4;
+                }
+            } else if (at(p, n, "::")) {
+                compressedZeros = true;
+                p = scanHexPost(p + 2, n);
+            }
+            if (p < n)
+                fail("Malformed IPv6 address", start);
+            if (ipv6byteCount > 16)
+                fail("IPv6 address too long", start);
+            if (!compressedZeros && ipv6byteCount < 16)
+                fail("IPv6 address too short", start);
+            if (compressedZeros && ipv6byteCount == 16)
+                fail("Malformed IPv6 address", start);
+
+            return p;
+        }
+
+        private int scanHexPost(int start, int n)
+            throws URISyntaxException
+        {
+            int p = start;
+            int q;
+
+            if (p == n)
+                return p;
+
+            q = scanHexSeq(p, n);
+            if (q > p) {
+                p = q;
+                if (at(p, n, ':')) {
+                    p++;
+                    p = takeIPv4Address(p, n, "hex digits or IPv4 address");
+                    ipv6byteCount += 4;
+                }
+            } else {
+                p = takeIPv4Address(p, n, "hex digits or IPv4 address");
+                ipv6byteCount += 4;
+            }
+            return p;
+        }
+
+        // Scan a hex sequence; return -1 if one could not be scanned
+        //
+        private int scanHexSeq(int start, int n)
+            throws URISyntaxException
+        {
+            int p = start;
+            int q;
+
+            q = scan(p, n, L_HEX, H_HEX);
+            if (q <= p)
+                return -1;
+            if (at(q, n, '.'))          // Beginning of IPv4 address
+                return -1;
+            if (q > p + 4)
+                fail("IPv6 hexadecimal digit sequence too long", p);
+            ipv6byteCount += 2;
+            p = q;
+            while (p < n) {
+                if (!at(p, n, ':'))
+                    break;
+                if (at(p + 1, n, ':'))
+                    break;              // "::"
+                p++;
+                q = scan(p, n, L_HEX, H_HEX);
+                if (q <= p)
+                    failExpecting("digits for an IPv6 address", p);
+                if (at(q, n, '.')) {    // Beginning of IPv4 address
+                    p--;
+                    break;
+                }
+                if (q > p + 4)
+                    fail("IPv6 hexadecimal digit sequence too long", p);
+                ipv6byteCount += 2;
+                p = q;
+            }
+
+            return p;
+        }
+
+    }
+
+}
diff --git a/java/net/URISyntaxException.java b/java/net/URISyntaxException.java
new file mode 100644
index 0000000..8072c37
--- /dev/null
+++ b/java/net/URISyntaxException.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+
+/**
+ * Checked exception thrown to indicate that a string could not be parsed as a
+ * URI reference.
+ *
+ * @author Mark Reinhold
+ * @see URI
+ * @since 1.4
+ */
+
+public class URISyntaxException
+    extends Exception
+{
+    private static final long serialVersionUID = 2137979680897488891L;
+
+    private String input;
+    private int index;
+
+    /**
+     * Constructs an instance from the given input string, reason, and error
+     * index.
+     *
+     * @param  input   The input string
+     * @param  reason  A string explaining why the input could not be parsed
+     * @param  index   The index at which the parse error occurred,
+     *                 or {@code -1} if the index is not known
+     *
+     * @throws  NullPointerException
+     *          If either the input or reason strings are {@code null}
+     *
+     * @throws  IllegalArgumentException
+     *          If the error index is less than {@code -1}
+     */
+    public URISyntaxException(String input, String reason, int index) {
+        super(reason);
+        if ((input == null) || (reason == null))
+            throw new NullPointerException();
+        if (index < -1)
+            throw new IllegalArgumentException();
+        this.input = input;
+        this.index = index;
+    }
+
+    /**
+     * Constructs an instance from the given input string and reason.  The
+     * resulting object will have an error index of {@code -1}.
+     *
+     * @param  input   The input string
+     * @param  reason  A string explaining why the input could not be parsed
+     *
+     * @throws  NullPointerException
+     *          If either the input or reason strings are {@code null}
+     */
+    public URISyntaxException(String input, String reason) {
+        this(input, reason, -1);
+    }
+
+    /**
+     * Returns the input string.
+     *
+     * @return  The input string
+     */
+    public String getInput() {
+        return input;
+    }
+
+    /**
+     * Returns a string explaining why the input string could not be parsed.
+     *
+     * @return  The reason string
+     */
+    public String getReason() {
+        return super.getMessage();
+    }
+
+    /**
+     * Returns an index into the input string of the position at which the
+     * parse error occurred, or {@code -1} if this position is not known.
+     *
+     * @return  The error index
+     */
+    public int getIndex() {
+        return index;
+    }
+
+    /**
+     * Returns a string describing the parse error.  The resulting string
+     * consists of the reason string followed by a colon character
+     * ({@code ':'}), a space, and the input string.  If the error index is
+     * defined then the string {@code " at index "} followed by the index, in
+     * decimal, is inserted after the reason string and before the colon
+     * character.
+     *
+     * @return  A string describing the parse error
+     */
+    public String getMessage() {
+        StringBuffer sb = new StringBuffer();
+        sb.append(getReason());
+        if (index > -1) {
+            sb.append(" at index ");
+            sb.append(index);
+        }
+        sb.append(": ");
+        sb.append(input);
+        return sb.toString();
+    }
+
+}
diff --git a/java/net/URL.java b/java/net/URL.java
new file mode 100644
index 0000000..74dec92
--- /dev/null
+++ b/java/net/URL.java
@@ -0,0 +1,1627 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream.GetField;
+import java.io.ObjectStreamException;
+import java.io.ObjectStreamField;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+import java.util.StringTokenizer;
+import sun.security.util.SecurityConstants;
+
+/**
+ * Class {@code URL} represents a Uniform Resource
+ * Locator, a pointer to a "resource" on the World
+ * Wide Web. A resource can be something as simple as a file or a
+ * directory, or it can be a reference to a more complicated object,
+ * such as a query to a database or to a search engine. More
+ * information on the types of URLs and their formats can be found at:
+ * <a href=
+ * "http://web.archive.org/web/20051219043731/http://archive.ncsa.uiuc.edu/SDG/Software/Mosaic/Demo/url-primer.html">
+ * <i>Types of URL</i></a>
+ * <p>
+ * In general, a URL can be broken into several parts. Consider the
+ * following example:
+ * <blockquote><pre>
+ *     http://www.example.com/docs/resource1.html
+ * </pre></blockquote>
+ * <p>
+ * The URL above indicates that the protocol to use is
+ * {@code http} (HyperText Transfer Protocol) and that the
+ * information resides on a host machine named
+ * {@code www.example.com}. The information on that host
+ * machine is named {@code /docs/resource1.html}. The exact
+ * meaning of this name on the host machine is both protocol
+ * dependent and host dependent. The information normally resides in
+ * a file, but it could be generated on the fly. This component of
+ * the URL is called the <i>path</i> component.
+ * <p>
+ * A URL can optionally specify a "port", which is the
+ * port number to which the TCP connection is made on the remote host
+ * machine. If the port is not specified, the default port for
+ * the protocol is used instead. For example, the default port for
+ * {@code http} is {@code 80}. An alternative port could be
+ * specified as:
+ * <blockquote><pre>
+ *     http://www.example.com:1080/docs/resource1.html
+ * </pre></blockquote>
+ * <p>
+ * The syntax of {@code URL} is defined by  <a
+ * href="http://www.ietf.org/rfc/rfc2396.txt"><i>RFC&nbsp;2396: Uniform
+ * Resource Identifiers (URI): Generic Syntax</i></a>, amended by <a
+ * href="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC&nbsp;2732: Format for
+ * Literal IPv6 Addresses in URLs</i></a>. The Literal IPv6 address format
+ * also supports scope_ids. The syntax and usage of scope_ids is described
+ * <a href="Inet6Address.html#scoped">here</a>.
+ * <p>
+ * A URL may have appended to it a "fragment", also known
+ * as a "ref" or a "reference". The fragment is indicated by the sharp
+ * sign character "#" followed by more characters. For example,
+ * <blockquote><pre>
+ *     http://java.sun.com/index.html#chapter1
+ * </pre></blockquote>
+ * <p>
+ * This fragment is not technically part of the URL. Rather, it
+ * indicates that after the specified resource is retrieved, the
+ * application is specifically interested in that part of the
+ * document that has the tag {@code chapter1} attached to it. The
+ * meaning of a tag is resource specific.
+ * <p>
+ * An application can also specify a "relative URL",
+ * which contains only enough information to reach the resource
+ * relative to another URL. Relative URLs are frequently used within
+ * HTML pages. For example, if the contents of the URL:
+ * <blockquote><pre>
+ *     http://java.sun.com/index.html
+ * </pre></blockquote>
+ * contained within it the relative URL:
+ * <blockquote><pre>
+ *     FAQ.html
+ * </pre></blockquote>
+ * it would be a shorthand for:
+ * <blockquote><pre>
+ *     http://java.sun.com/FAQ.html
+ * </pre></blockquote>
+ * <p>
+ * The relative URL need not specify all the components of a URL. If
+ * the protocol, host name, or port number is missing, the value is
+ * inherited from the fully specified URL. The file component must be
+ * specified. The optional fragment is not inherited.
+ * <p>
+ * The URL class does not itself encode or decode any URL components
+ * according to the escaping mechanism defined in RFC2396. It is the
+ * responsibility of the caller to encode any fields, which need to be
+ * escaped prior to calling URL, and also to decode any escaped fields,
+ * that are returned from URL. Furthermore, because URL has no knowledge
+ * of URL escaping, it does not recognise equivalence between the encoded
+ * or decoded form of the same URL. For example, the two URLs:<br>
+ * <pre>    http://foo.com/hello world/ and http://foo.com/hello%20world</pre>
+ * would be considered not equal to each other.
+ * <p>
+ * Note, the {@link java.net.URI} class does perform escaping of its
+ * component fields in certain circumstances. The recommended way
+ * to manage the encoding and decoding of URLs is to use {@link java.net.URI},
+ * and to convert between these two classes using {@link #toURI()} and
+ * {@link URI#toURL()}.
+ * <p>
+ * The {@link URLEncoder} and {@link URLDecoder} classes can also be
+ * used, but only for HTML form encoding, which is not the same
+ * as the encoding scheme defined in RFC2396.
+ *
+ * @author  James Gosling
+ * @since JDK1.0
+ */
+public final class URL implements java.io.Serializable {
+
+    // Android-changed: Custom built-in URLStreamHandlers for http, https.
+    // static final String BUILTIN_HANDLERS_PREFIX = "sun.net.www.protocol";
+    private static final Set<String> BUILTIN_HANDLER_CLASS_NAMES = createBuiltinHandlerClassNames();
+    static final long serialVersionUID = -7627629688361524110L;
+
+    /**
+     * The property which specifies the package prefix list to be scanned
+     * for protocol handlers.  The value of this property (if any) should
+     * be a vertical bar delimited list of package names to search through
+     * for a protocol handler to load.  The policy of this class is that
+     * all protocol handlers will be in a class called <protocolname>.Handler,
+     * and each package in the list is examined in turn for a matching
+     * handler.  If none are found (or the property is not specified), the
+     * default package prefix, sun.net.www.protocol, is used.  The search
+     * proceeds from the first package in the list to the last and stops
+     * when a match is found.
+     */
+    private static final String protocolPathProp = "java.protocol.handler.pkgs";
+
+    /**
+     * The protocol to use (ftp, http, nntp, ... etc.) .
+     * @serial
+     */
+    private String protocol;
+
+    /**
+     * The host name to connect to.
+     * @serial
+     */
+    private String host;
+
+    /**
+     * The protocol port to connect to.
+     * @serial
+     */
+    private int port = -1;
+
+    /**
+     * The specified file name on that host. {@code file} is
+     * defined as {@code path[?query]}
+     * @serial
+     */
+    private String file;
+
+    /**
+     * The query part of this URL.
+     */
+    private transient String query;
+
+    /**
+     * The authority part of this URL.
+     * @serial
+     */
+    private String authority;
+
+    /**
+     * The path part of this URL.
+     */
+    private transient String path;
+
+    /**
+     * The userinfo part of this URL.
+     */
+    private transient String userInfo;
+
+    /**
+     * # reference.
+     * @serial
+     */
+    private String ref;
+
+    /**
+     * The host's IP address, used in equals and hashCode.
+     * Computed on demand. An uninitialized or unknown hostAddress is null.
+     */
+    transient InetAddress hostAddress;
+
+    /**
+     * The URLStreamHandler for this URL.
+     */
+    transient URLStreamHandler handler;
+
+    /* Our hash code.
+     * @serial
+     */
+    private int hashCode = -1;
+
+    private transient UrlDeserializedState tempState;
+
+    /**
+     * Creates a {@code URL} object from the specified
+     * {@code protocol}, {@code host}, {@code port}
+     * number, and {@code file}.<p>
+     *
+     * {@code host} can be expressed as a host name or a literal
+     * IP address. If IPv6 literal address is used, it should be
+     * enclosed in square brackets ({@code '['} and {@code ']'}), as
+     * specified by <a
+     * href="http://www.ietf.org/rfc/rfc2732.txt">RFC&nbsp;2732</a>;
+     * However, the literal IPv6 address format defined in <a
+     * href="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC&nbsp;2373: IP
+     * Version 6 Addressing Architecture</i></a> is also accepted.<p>
+     *
+     * Specifying a {@code port} number of {@code -1}
+     * indicates that the URL should use the default port for the
+     * protocol.<p>
+     *
+     * If this is the first URL object being created with the specified
+     * protocol, a <i>stream protocol handler</i> object, an instance of
+     * class {@code URLStreamHandler}, is created for that protocol:
+     * <ol>
+     * <li>If the application has previously set up an instance of
+     *     {@code URLStreamHandlerFactory} as the stream handler factory,
+     *     then the {@code createURLStreamHandler} method of that instance
+     *     is called with the protocol string as an argument to create the
+     *     stream protocol handler.
+     * <li>If no {@code URLStreamHandlerFactory} has yet been set up,
+     *     or if the factory's {@code createURLStreamHandler} method
+     *     returns {@code null}, then the constructor finds the
+     *     value of the system property:
+     *     <blockquote><pre>
+     *         java.protocol.handler.pkgs
+     *     </pre></blockquote>
+     *     If the value of that system property is not {@code null},
+     *     it is interpreted as a list of packages separated by a vertical
+     *     slash character '{@code |}'. The constructor tries to load
+     *     the class named:
+     *     <blockquote><pre>
+     *         &lt;<i>package</i>&gt;.&lt;<i>protocol</i>&gt;.Handler
+     *     </pre></blockquote>
+     *     where &lt;<i>package</i>&gt; is replaced by the name of the package
+     *     and &lt;<i>protocol</i>&gt; is replaced by the name of the protocol.
+     *     If this class does not exist, or if the class exists but it is not
+     *     a subclass of {@code URLStreamHandler}, then the next package
+     *     in the list is tried.
+     * <li>If the previous step fails to find a protocol handler, then the
+     *     constructor tries to load from a system default package.
+     *     <blockquote><pre>
+     *         &lt;<i>system default package</i>&gt;.&lt;<i>protocol</i>&gt;.Handler
+     *     </pre></blockquote>
+     *     If this class does not exist, or if the class exists but it is not a
+     *     subclass of {@code URLStreamHandler}, then a
+     *     {@code MalformedURLException} is thrown.
+     * </ol>
+     *
+     * <p>Protocol handlers for the following protocols are guaranteed
+     * to exist on the search path :-
+     * <blockquote><pre>
+     *     http, https, file, and jar
+     * </pre></blockquote>
+     * Protocol handlers for additional protocols may also be
+     * available.
+     *
+     * <p>No validation of the inputs is performed by this constructor.
+     *
+     * @param      protocol   the name of the protocol to use.
+     * @param      host       the name of the host.
+     * @param      port       the port number on the host.
+     * @param      file       the file on the host
+     * @exception  MalformedURLException  if an unknown protocol is specified.
+     * @see        java.lang.System#getProperty(java.lang.String)
+     * @see        java.net.URL#setURLStreamHandlerFactory(
+     *                  java.net.URLStreamHandlerFactory)
+     * @see        java.net.URLStreamHandler
+     * @see        java.net.URLStreamHandlerFactory#createURLStreamHandler(
+     *                  java.lang.String)
+     */
+    public URL(String protocol, String host, int port, String file)
+        throws MalformedURLException
+    {
+        this(protocol, host, port, file, null);
+    }
+
+    /**
+     * Creates a URL from the specified {@code protocol}
+     * name, {@code host} name, and {@code file} name. The
+     * default port for the specified protocol is used.
+     * <p>
+     * This method is equivalent to calling the four-argument
+     * constructor with the arguments being {@code protocol},
+     * {@code host}, {@code -1}, and {@code file}.
+     *
+     * No validation of the inputs is performed by this constructor.
+     *
+     * @param      protocol   the name of the protocol to use.
+     * @param      host       the name of the host.
+     * @param      file       the file on the host.
+     * @exception  MalformedURLException  if an unknown protocol is specified.
+     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
+     *                  int, java.lang.String)
+     */
+    public URL(String protocol, String host, String file)
+            throws MalformedURLException {
+        this(protocol, host, -1, file);
+    }
+
+    /**
+     * Creates a {@code URL} object from the specified
+     * {@code protocol}, {@code host}, {@code port}
+     * number, {@code file}, and {@code handler}. Specifying
+     * a {@code port} number of {@code -1} indicates that
+     * the URL should use the default port for the protocol. Specifying
+     * a {@code handler} of {@code null} indicates that the URL
+     * should use a default stream handler for the protocol, as outlined
+     * for:
+     *     java.net.URL#URL(java.lang.String, java.lang.String, int,
+     *                      java.lang.String)
+     *
+     * <p>If the handler is not null and there is a security manager,
+     * the security manager's {@code checkPermission}
+     * method is called with a
+     * {@code NetPermission("specifyStreamHandler")} permission.
+     * This may result in a SecurityException.
+     *
+     * No validation of the inputs is performed by this constructor.
+     *
+     * @param      protocol   the name of the protocol to use.
+     * @param      host       the name of the host.
+     * @param      port       the port number on the host.
+     * @param      file       the file on the host
+     * @param      handler    the stream handler for the URL.
+     * @exception  MalformedURLException  if an unknown protocol is specified.
+     * @exception  SecurityException
+     *        if a security manager exists and its
+     *        {@code checkPermission} method doesn't allow
+     *        specifying a stream handler explicitly.
+     * @see        java.lang.System#getProperty(java.lang.String)
+     * @see        java.net.URL#setURLStreamHandlerFactory(
+     *                  java.net.URLStreamHandlerFactory)
+     * @see        java.net.URLStreamHandler
+     * @see        java.net.URLStreamHandlerFactory#createURLStreamHandler(
+     *                  java.lang.String)
+     * @see        SecurityManager#checkPermission
+     * @see        java.net.NetPermission
+     */
+    public URL(String protocol, String host, int port, String file,
+               URLStreamHandler handler) throws MalformedURLException {
+        if (handler != null) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                // check for permission to specify a handler
+                checkSpecifyHandler(sm);
+            }
+        }
+
+        protocol = protocol.toLowerCase();
+        this.protocol = protocol;
+        if (host != null) {
+
+            /**
+             * if host is a literal IPv6 address,
+             * we will make it conform to RFC 2732
+             */
+            if (host.indexOf(':') >= 0 && !host.startsWith("[")) {
+                host = "["+host+"]";
+            }
+            this.host = host;
+
+            if (port < -1) {
+                throw new MalformedURLException("Invalid port number :" +
+                                                    port);
+            }
+            this.port = port;
+            authority = (port == -1) ? host : host + ":" + port;
+        }
+
+        // Android-changed: App compat. Prepend '/' if host is null / empty
+        // Parts parts = new Parts(file);
+        Parts parts = new Parts(file, host);
+        path = parts.getPath();
+        query = parts.getQuery();
+
+        if (query != null) {
+            this.file = path + "?" + query;
+        } else {
+            this.file = path;
+        }
+        ref = parts.getRef();
+
+        // Note: we don't do validation of the URL here. Too risky to change
+        // right now, but worth considering for future reference. -br
+        if (handler == null &&
+            (handler = getURLStreamHandler(protocol)) == null) {
+            throw new MalformedURLException("unknown protocol: " + protocol);
+        }
+        this.handler = handler;
+    }
+
+    /**
+     * Creates a {@code URL} object from the {@code String}
+     * representation.
+     * <p>
+     * This constructor is equivalent to a call to the two-argument
+     * constructor with a {@code null} first argument.
+     *
+     * @param      spec   the {@code String} to parse as a URL.
+     * @exception  MalformedURLException  if no protocol is specified, or an
+     *               unknown protocol is found, or {@code spec} is {@code null}.
+     * @see        java.net.URL#URL(java.net.URL, java.lang.String)
+     */
+    public URL(String spec) throws MalformedURLException {
+        this(null, spec);
+    }
+
+    /**
+     * Creates a URL by parsing the given spec within a specified context.
+     *
+     * The new URL is created from the given context URL and the spec
+     * argument as described in
+     * RFC2396 &quot;Uniform Resource Identifiers : Generic * Syntax&quot; :
+     * <blockquote><pre>
+     *          &lt;scheme&gt;://&lt;authority&gt;&lt;path&gt;?&lt;query&gt;#&lt;fragment&gt;
+     * </pre></blockquote>
+     * The reference is parsed into the scheme, authority, path, query and
+     * fragment parts. If the path component is empty and the scheme,
+     * authority, and query components are undefined, then the new URL is a
+     * reference to the current document. Otherwise, the fragment and query
+     * parts present in the spec are used in the new URL.
+     * <p>
+     * If the scheme component is defined in the given spec and does not match
+     * the scheme of the context, then the new URL is created as an absolute
+     * URL based on the spec alone. Otherwise the scheme component is inherited
+     * from the context URL.
+     * <p>
+     * If the authority component is present in the spec then the spec is
+     * treated as absolute and the spec authority and path will replace the
+     * context authority and path. If the authority component is absent in the
+     * spec then the authority of the new URL will be inherited from the
+     * context.
+     * <p>
+     * If the spec's path component begins with a slash character
+     * &quot;/&quot; then the
+     * path is treated as absolute and the spec path replaces the context path.
+     * <p>
+     * Otherwise, the path is treated as a relative path and is appended to the
+     * context path, as described in RFC2396. Also, in this case,
+     * the path is canonicalized through the removal of directory
+     * changes made by occurrences of &quot;..&quot; and &quot;.&quot;.
+     * <p>
+     * For a more detailed description of URL parsing, refer to RFC2396.
+     *
+     * @param      context   the context in which to parse the specification.
+     * @param      spec      the {@code String} to parse as a URL.
+     * @exception  MalformedURLException  if no protocol is specified, or an
+     *               unknown protocol is found, or {@code spec} is {@code null}.
+     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
+     *                  int, java.lang.String)
+     * @see        java.net.URLStreamHandler
+     * @see        java.net.URLStreamHandler#parseURL(java.net.URL,
+     *                  java.lang.String, int, int)
+     */
+    public URL(URL context, String spec) throws MalformedURLException {
+        this(context, spec, null);
+    }
+
+    /**
+     * Creates a URL by parsing the given spec with the specified handler
+     * within a specified context. If the handler is null, the parsing
+     * occurs as with the two argument constructor.
+     *
+     * @param      context   the context in which to parse the specification.
+     * @param      spec      the {@code String} to parse as a URL.
+     * @param      handler   the stream handler for the URL.
+     * @exception  MalformedURLException  if no protocol is specified, or an
+     *               unknown protocol is found, or {@code spec} is {@code null}.
+     * @exception  SecurityException
+     *        if a security manager exists and its
+     *        {@code checkPermission} method doesn't allow
+     *        specifying a stream handler.
+     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
+     *                  int, java.lang.String)
+     * @see        java.net.URLStreamHandler
+     * @see        java.net.URLStreamHandler#parseURL(java.net.URL,
+     *                  java.lang.String, int, int)
+     */
+    public URL(URL context, String spec, URLStreamHandler handler)
+        throws MalformedURLException
+    {
+        String original = spec;
+        int i, limit, c;
+        int start = 0;
+        String newProtocol = null;
+        boolean aRef=false;
+        boolean isRelative = false;
+
+        // Check for permission to specify a handler
+        if (handler != null) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                checkSpecifyHandler(sm);
+            }
+        }
+
+        try {
+            limit = spec.length();
+            while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) {
+                limit--;        //eliminate trailing whitespace
+            }
+            while ((start < limit) && (spec.charAt(start) <= ' ')) {
+                start++;        // eliminate leading whitespace
+            }
+
+            if (spec.regionMatches(true, start, "url:", 0, 4)) {
+                start += 4;
+            }
+            if (start < spec.length() && spec.charAt(start) == '#') {
+                /* we're assuming this is a ref relative to the context URL.
+                 * This means protocols cannot start w/ '#', but we must parse
+                 * ref URL's like: "hello:there" w/ a ':' in them.
+                 */
+                aRef=true;
+            }
+            for (i = start ; !aRef && (i < limit) &&
+                     ((c = spec.charAt(i)) != '/') ; i++) {
+                if (c == ':') {
+
+                    String s = spec.substring(start, i).toLowerCase();
+                    if (isValidProtocol(s)) {
+                        newProtocol = s;
+                        start = i + 1;
+                    }
+                    break;
+                }
+            }
+
+            // Only use our context if the protocols match.
+            protocol = newProtocol;
+            if ((context != null) && ((newProtocol == null) ||
+                            newProtocol.equalsIgnoreCase(context.protocol))) {
+                // inherit the protocol handler from the context
+                // if not specified to the constructor
+                if (handler == null) {
+                    handler = context.handler;
+                }
+
+                // If the context is a hierarchical URL scheme and the spec
+                // contains a matching scheme then maintain backwards
+                // compatibility and treat it as if the spec didn't contain
+                // the scheme; see 5.2.3 of RFC2396
+                if (context.path != null && context.path.startsWith("/"))
+                    newProtocol = null;
+
+                if (newProtocol == null) {
+                    protocol = context.protocol;
+                    authority = context.authority;
+                    userInfo = context.userInfo;
+                    host = context.host;
+                    port = context.port;
+                    file = context.file;
+                    path = context.path;
+                    isRelative = true;
+                }
+            }
+
+            if (protocol == null) {
+                throw new MalformedURLException("no protocol: "+original);
+            }
+
+            // Get the protocol handler if not specified or the protocol
+            // of the context could not be used
+            if (handler == null &&
+                (handler = getURLStreamHandler(protocol)) == null) {
+                throw new MalformedURLException("unknown protocol: "+protocol);
+            }
+
+            this.handler = handler;
+
+            i = spec.indexOf('#', start);
+            if (i >= 0) {
+                ref = spec.substring(i + 1, limit);
+                limit = i;
+            }
+
+            /*
+             * Handle special case inheritance of query and fragment
+             * implied by RFC2396 section 5.2.2.
+             */
+            if (isRelative && start == limit) {
+                query = context.query;
+                if (ref == null) {
+                    ref = context.ref;
+                }
+            }
+
+            handler.parseURL(this, spec, start, limit);
+
+        } catch(MalformedURLException e) {
+            throw e;
+        } catch(Exception e) {
+            MalformedURLException exception = new MalformedURLException(e.getMessage());
+            exception.initCause(e);
+            throw exception;
+        }
+    }
+
+    /*
+     * Returns true if specified string is a valid protocol name.
+     */
+    private boolean isValidProtocol(String protocol) {
+        int len = protocol.length();
+        if (len < 1)
+            return false;
+        char c = protocol.charAt(0);
+        if (!Character.isLetter(c))
+            return false;
+        for (int i = 1; i < len; i++) {
+            c = protocol.charAt(i);
+            if (!Character.isLetterOrDigit(c) && c != '.' && c != '+' &&
+                c != '-') {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /*
+     * Checks for permission to specify a stream handler.
+     */
+    private void checkSpecifyHandler(SecurityManager sm) {
+        sm.checkPermission(SecurityConstants.SPECIFY_HANDLER_PERMISSION);
+    }
+
+    /**
+     * Sets the fields of the URL. This is not a public method so that
+     * only URLStreamHandlers can modify URL fields. URLs are
+     * otherwise constant.
+     *
+     * @param protocol the name of the protocol to use
+     * @param host the name of the host
+       @param port the port number on the host
+     * @param file the file on the host
+     * @param ref the internal reference in the URL
+     */
+    void set(String protocol, String host, int port,
+             String file, String ref) {
+        synchronized (this) {
+            this.protocol = protocol;
+            this.host = host;
+            authority = port == -1 ? host : host + ":" + port;
+            this.port = port;
+            this.file = file;
+            this.ref = ref;
+            /* This is very important. We must recompute this after the
+             * URL has been changed. */
+            hashCode = -1;
+            hostAddress = null;
+            int q = file.lastIndexOf('?');
+            if (q != -1) {
+                query = file.substring(q+1);
+                path = file.substring(0, q);
+            } else
+                path = file;
+        }
+    }
+
+    /**
+     * Sets the specified 8 fields of the URL. This is not a public method so
+     * that only URLStreamHandlers can modify URL fields. URLs are otherwise
+     * constant.
+     *
+     * @param protocol the name of the protocol to use
+     * @param host the name of the host
+     * @param port the port number on the host
+     * @param authority the authority part for the url
+     * @param userInfo the username and password
+     * @param path the file on the host
+     * @param ref the internal reference in the URL
+     * @param query the query part of this URL
+     * @since 1.3
+     */
+    void set(String protocol, String host, int port,
+             String authority, String userInfo, String path,
+             String query, String ref) {
+        synchronized (this) {
+            this.protocol = protocol;
+            this.host = host;
+            this.port = port;
+            // Android-changed: App compat. Only include query part if it's nonempty.
+            // this.file = query == null ? path : path + "?" + query;
+            this.file = (query == null || query.isEmpty()) ? path : path + "?" + query;
+            this.userInfo = userInfo;
+            this.path = path;
+            this.ref = ref;
+            /* This is very important. We must recompute this after the
+             * URL has been changed. */
+            hashCode = -1;
+            hostAddress = null;
+            this.query = query;
+            this.authority = authority;
+        }
+    }
+
+    /**
+     * Gets the query part of this {@code URL}.
+     *
+     * @return  the query part of this {@code URL},
+     * or <CODE>null</CODE> if one does not exist
+     * @since 1.3
+     */
+    public String getQuery() {
+        return query;
+    }
+
+    /**
+     * Gets the path part of this {@code URL}.
+     *
+     * @return  the path part of this {@code URL}, or an
+     * empty string if one does not exist
+     * @since 1.3
+     */
+    public String getPath() {
+        return path;
+    }
+
+    /**
+     * Gets the userInfo part of this {@code URL}.
+     *
+     * @return  the userInfo part of this {@code URL}, or
+     * <CODE>null</CODE> if one does not exist
+     * @since 1.3
+     */
+    public String getUserInfo() {
+        return userInfo;
+    }
+
+    /**
+     * Gets the authority part of this {@code URL}.
+     *
+     * @return  the authority part of this {@code URL}
+     * @since 1.3
+     */
+    public String getAuthority() {
+        return authority;
+    }
+
+    /**
+     * Gets the port number of this {@code URL}.
+     *
+     * @return  the port number, or -1 if the port is not set
+     */
+    public int getPort() {
+        return port;
+    }
+
+    /**
+     * Gets the default port number of the protocol associated
+     * with this {@code URL}. If the URL scheme or the URLStreamHandler
+     * for the URL do not define a default port number,
+     * then -1 is returned.
+     *
+     * @return  the port number
+     * @since 1.4
+     */
+    public int getDefaultPort() {
+        return handler.getDefaultPort();
+    }
+
+    /**
+     * Gets the protocol name of this {@code URL}.
+     *
+     * @return  the protocol of this {@code URL}.
+     */
+    public String getProtocol() {
+        return protocol;
+    }
+
+    /**
+     * Gets the host name of this {@code URL}, if applicable.
+     * The format of the host conforms to RFC 2732, i.e. for a
+     * literal IPv6 address, this method will return the IPv6 address
+     * enclosed in square brackets ({@code '['} and {@code ']'}).
+     *
+     * @return  the host name of this {@code URL}.
+     */
+    public String getHost() {
+        return host;
+    }
+
+    /**
+     * Gets the file name of this {@code URL}.
+     * The returned file portion will be
+     * the same as <CODE>getPath()</CODE>, plus the concatenation of
+     * the value of <CODE>getQuery()</CODE>, if any. If there is
+     * no query portion, this method and <CODE>getPath()</CODE> will
+     * return identical results.
+     *
+     * @return  the file name of this {@code URL},
+     * or an empty string if one does not exist
+     */
+    public String getFile() {
+        return file;
+    }
+
+    /**
+     * Gets the anchor (also known as the "reference") of this
+     * {@code URL}.
+     *
+     * @return  the anchor (also known as the "reference") of this
+     *          {@code URL}, or <CODE>null</CODE> if one does not exist
+     */
+    public String getRef() {
+        return ref;
+    }
+
+    // Android-changed: Don't let URL.equals() attempt to resolve host names.
+    /**
+     * Compares this URL for equality with another object.<p>
+     *
+     * If the given object is not a URL then this method immediately returns
+     * {@code false}.<p>
+     *
+     * Two URL objects are equal if they have the same protocol, reference
+     * equivalent hosts, have the same port number on the host, and the same
+     * file and fragment of the file.<p>
+     *
+     * Returns true if this URL equals {@code o}. URLs are equal if they have
+     * the same protocol, host, port, file, and reference.
+     *
+     * <h3>Network I/O Warning</h3>
+     * <p>Some implementations of URL.equals() resolve host names over the
+     * network. This is problematic:
+     * <ul>
+     * <li><strong>The network may be slow.</strong> Many classes, including
+     * core collections like {@link java.util.Map Map} and {@link java.util.Set
+     * Set} expect that {@code equals} and {@code hashCode} will return quickly.
+     * By violating this assumption, this method posed potential performance
+     * problems.
+     * <li><strong>Equal IP addresses do not imply equal content.</strong>
+     * Virtual hosting permits unrelated sites to share an IP address. This
+     * method could report two otherwise unrelated URLs to be equal because
+     * they're hosted on the same server.</li>
+     * <li><strong>The network may not be available.</strong> Two URLs could be
+     * equal when a network is available and unequal otherwise.</li>
+     * <li><strong>The network may change.</strong> The IP address for a given
+     * host name varies by network and over time. This is problematic for mobile
+     * devices. Two URLs could be equal on some networks and unequal on
+     * others.</li>
+     * </ul>
+     * <p>This problem is fixed in Android 4.0 (Ice Cream Sandwich). In that
+     * release, URLs are only equal if their host names are equal (ignoring
+     * case).
+     *
+     * @param   obj   the URL to compare against.
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     */
+    public boolean equals(Object obj) {
+        if (!(obj instanceof URL))
+            return false;
+        URL u2 = (URL)obj;
+
+        return handler.equals(this, u2);
+    }
+
+    /**
+     * Creates an integer suitable for hash table indexing.<p>
+     *
+     * The hash code is based upon all the URL components relevant for URL
+     * comparison. As such, this operation is a blocking operation.<p>
+     *
+     * @return  a hash code for this {@code URL}.
+     */
+    public synchronized int hashCode() {
+        if (hashCode != -1)
+            return hashCode;
+
+        hashCode = handler.hashCode(this);
+        return hashCode;
+    }
+
+    /**
+     * Compares two URLs, excluding the fragment component.<p>
+     *
+     * Returns {@code true} if this {@code URL} and the
+     * {@code other} argument are equal without taking the
+     * fragment component into consideration.
+     *
+     * @param   other   the {@code URL} to compare against.
+     * @return  {@code true} if they reference the same remote object;
+     *          {@code false} otherwise.
+     */
+    public boolean sameFile(URL other) {
+        return handler.sameFile(this, other);
+    }
+
+    /**
+     * Constructs a string representation of this {@code URL}. The
+     * string is created by calling the {@code toExternalForm}
+     * method of the stream protocol handler for this object.
+     *
+     * @return  a string representation of this object.
+     * @see     java.net.URL#URL(java.lang.String, java.lang.String, int,
+     *                  java.lang.String)
+     * @see     java.net.URLStreamHandler#toExternalForm(java.net.URL)
+     */
+    public String toString() {
+        return toExternalForm();
+    }
+
+    /**
+     * Constructs a string representation of this {@code URL}. The
+     * string is created by calling the {@code toExternalForm}
+     * method of the stream protocol handler for this object.
+     *
+     * @return  a string representation of this object.
+     * @see     java.net.URL#URL(java.lang.String, java.lang.String,
+     *                  int, java.lang.String)
+     * @see     java.net.URLStreamHandler#toExternalForm(java.net.URL)
+     */
+    public String toExternalForm() {
+        return handler.toExternalForm(this);
+    }
+
+    /**
+     * Returns a {@link java.net.URI} equivalent to this URL.
+     * This method functions in the same way as {@code new URI (this.toString())}.
+     * <p>Note, any URL instance that complies with RFC 2396 can be converted
+     * to a URI. However, some URLs that are not strictly in compliance
+     * can not be converted to a URI.
+     *
+     * @exception URISyntaxException if this URL is not formatted strictly according to
+     *            to RFC2396 and cannot be converted to a URI.
+     *
+     * @return    a URI instance equivalent to this URL.
+     * @since 1.5
+     */
+    public URI toURI() throws URISyntaxException {
+        return new URI (toString());
+    }
+
+    /**
+     * Returns a {@link java.net.URLConnection URLConnection} instance that
+     * represents a connection to the remote object referred to by the
+     * {@code URL}.
+     *
+     * <P>A new instance of {@linkplain java.net.URLConnection URLConnection} is
+     * created every time when invoking the
+     * {@linkplain java.net.URLStreamHandler#openConnection(URL)
+     * URLStreamHandler.openConnection(URL)} method of the protocol handler for
+     * this URL.</P>
+     *
+     * <P>It should be noted that a URLConnection instance does not establish
+     * the actual network connection on creation. This will happen only when
+     * calling {@linkplain java.net.URLConnection#connect() URLConnection.connect()}.</P>
+     *
+     * <P>If for the URL's protocol (such as HTTP or JAR), there
+     * exists a public, specialized URLConnection subclass belonging
+     * to one of the following packages or one of their subpackages:
+     * java.lang, java.io, java.util, java.net, the connection
+     * returned will be of that subclass. For example, for HTTP an
+     * HttpURLConnection will be returned, and for JAR a
+     * JarURLConnection will be returned.</P>
+     *
+     * @return     a {@link java.net.URLConnection URLConnection} linking
+     *             to the URL.
+     * @exception  IOException  if an I/O exception occurs.
+     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
+     *             int, java.lang.String)
+     */
+    public URLConnection openConnection() throws java.io.IOException {
+        return handler.openConnection(this);
+    }
+
+    /**
+     * Same as {@link #openConnection()}, except that the connection will be
+     * made through the specified proxy; Protocol handlers that do not
+     * support proxing will ignore the proxy parameter and make a
+     * normal connection.
+     *
+     * Invoking this method preempts the system's default ProxySelector
+     * settings.
+     *
+     * @param      proxy the Proxy through which this connection
+     *             will be made. If direct connection is desired,
+     *             Proxy.NO_PROXY should be specified.
+     * @return     a {@code URLConnection} to the URL.
+     * @exception  IOException  if an I/O exception occurs.
+     * @exception  SecurityException if a security manager is present
+     *             and the caller doesn't have permission to connect
+     *             to the proxy.
+     * @exception  IllegalArgumentException will be thrown if proxy is null,
+     *             or proxy has the wrong type
+     * @exception  UnsupportedOperationException if the subclass that
+     *             implements the protocol handler doesn't support
+     *             this method.
+     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
+     *             int, java.lang.String)
+     * @see        java.net.URLConnection
+     * @see        java.net.URLStreamHandler#openConnection(java.net.URL,
+     *             java.net.Proxy)
+     * @since      1.5
+     */
+    public URLConnection openConnection(Proxy proxy)
+        throws java.io.IOException {
+        if (proxy == null) {
+            throw new IllegalArgumentException("proxy can not be null");
+        }
+
+        // Create a copy of Proxy as a security measure
+        Proxy p = proxy == Proxy.NO_PROXY ? Proxy.NO_PROXY : sun.net.ApplicationProxy.create(proxy);
+        SecurityManager sm = System.getSecurityManager();
+        if (p.type() != Proxy.Type.DIRECT && sm != null) {
+            InetSocketAddress epoint = (InetSocketAddress) p.address();
+            if (epoint.isUnresolved())
+                sm.checkConnect(epoint.getHostName(), epoint.getPort());
+            else
+                sm.checkConnect(epoint.getAddress().getHostAddress(),
+                                epoint.getPort());
+        }
+        return handler.openConnection(this, p);
+    }
+
+    /**
+     * Opens a connection to this {@code URL} and returns an
+     * {@code InputStream} for reading from that connection. This
+     * method is a shorthand for:
+     * <blockquote><pre>
+     *     openConnection().getInputStream()
+     * </pre></blockquote>
+     *
+     * @return     an input stream for reading from the URL connection.
+     * @exception  IOException  if an I/O exception occurs.
+     * @see        java.net.URL#openConnection()
+     * @see        java.net.URLConnection#getInputStream()
+     */
+    public final InputStream openStream() throws java.io.IOException {
+        return openConnection().getInputStream();
+    }
+
+    /**
+     * Gets the contents of this URL. This method is a shorthand for:
+     * <blockquote><pre>
+     *     openConnection().getContent()
+     * </pre></blockquote>
+     *
+     * @return     the contents of this URL.
+     * @exception  IOException  if an I/O exception occurs.
+     * @see        java.net.URLConnection#getContent()
+     */
+    public final Object getContent() throws java.io.IOException {
+        return openConnection().getContent();
+    }
+
+    /**
+     * Gets the contents of this URL. This method is a shorthand for:
+     * <blockquote><pre>
+     *     openConnection().getContent(Class[])
+     * </pre></blockquote>
+     *
+     * @param classes an array of Java types
+     * @return     the content object of this URL that is the first match of
+     *               the types specified in the classes array.
+     *               null if none of the requested types are supported.
+     * @exception  IOException  if an I/O exception occurs.
+     * @see        java.net.URLConnection#getContent(Class[])
+     * @since 1.3
+     */
+    public final Object getContent(Class[] classes)
+    throws java.io.IOException {
+        return openConnection().getContent(classes);
+    }
+
+    /**
+     * The URLStreamHandler factory.
+     */
+    static URLStreamHandlerFactory factory;
+
+    /**
+     * Sets an application's {@code URLStreamHandlerFactory}.
+     * This method can be called at most once in a given Java Virtual
+     * Machine.
+     *
+     *<p> The {@code URLStreamHandlerFactory} instance is used to
+     *construct a stream protocol handler from a protocol name.
+     *
+     * <p> If there is a security manager, this method first calls
+     * the security manager's {@code checkSetFactory} method
+     * to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param      fac   the desired factory.
+     * @exception  Error  if the application has already set a factory.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkSetFactory} method doesn't allow
+     *             the operation.
+     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
+     *             int, java.lang.String)
+     * @see        java.net.URLStreamHandlerFactory
+     * @see        SecurityManager#checkSetFactory
+     */
+    public static void setURLStreamHandlerFactory(URLStreamHandlerFactory fac) {
+        synchronized (streamHandlerLock) {
+            if (factory != null) {
+                throw new Error("factory already defined");
+            }
+            SecurityManager security = System.getSecurityManager();
+            if (security != null) {
+                security.checkSetFactory();
+            }
+            handlers.clear();
+            factory = fac;
+        }
+    }
+
+    /**
+     * A table of protocol handlers.
+     */
+    static Hashtable<String,URLStreamHandler> handlers = new Hashtable<>();
+    private static Object streamHandlerLock = new Object();
+
+    /**
+     * Returns the Stream Handler.
+     * @param protocol the protocol to use
+     */
+    static URLStreamHandler getURLStreamHandler(String protocol) {
+
+        URLStreamHandler handler = handlers.get(protocol);
+        if (handler == null) {
+
+            boolean checkedWithFactory = false;
+
+            // Use the factory (if any)
+            if (factory != null) {
+                handler = factory.createURLStreamHandler(protocol);
+                checkedWithFactory = true;
+            }
+
+            // Try java protocol handler
+            if (handler == null) {
+                // Android-changed: Android doesn't need AccessController.
+                // Remove unnecessary use of reflection for sun classes
+                /*
+                packagePrefixList
+                    = java.security.AccessController.doPrivileged(
+                    new sun.security.action.GetPropertyAction(
+                        protocolPathProp,""));
+                if (packagePrefixList != "") {
+                    packagePrefixList += "|";
+                }
+
+                // REMIND: decide whether to allow the "null" class prefix
+                // or not.
+                packagePrefixList += "sun.net.www.protocol";
+                 */
+                final String packagePrefixList = System.getProperty(protocolPathProp,"");
+
+                StringTokenizer packagePrefixIter =
+                    new StringTokenizer(packagePrefixList, "|");
+
+                while (handler == null &&
+                       packagePrefixIter.hasMoreTokens()) {
+
+                    String packagePrefix =
+                      packagePrefixIter.nextToken().trim();
+                    try {
+                        String clsName = packagePrefix + "." + protocol +
+                          ".Handler";
+                        Class<?> cls = null;
+                        try {
+                            ClassLoader cl = ClassLoader.getSystemClassLoader();
+                            // BEGIN Android-changed: Fall back to thread's contextClassLoader.
+                            // http://b/25897689
+                            cls = Class.forName(clsName, true, cl);
+                        } catch (ClassNotFoundException e) {
+                            ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
+                            if (contextLoader != null) {
+                                cls = Class.forName(clsName, true, contextLoader);
+                            }
+                            // END Android-changed: Fall back to thread's contextClassLoader.
+                        }
+                        if (cls != null) {
+                            handler  =
+                              (URLStreamHandler)cls.newInstance();
+                        }
+                    } catch (ReflectiveOperationException ignored) {
+                    }
+                }
+            }
+
+            // BEGIN Android-added: Custom built-in URLStreamHandlers for http, https.
+            // Fallback to built-in stream handler.
+            if (handler == null) {
+                try {
+                    handler = createBuiltinHandler(protocol);
+                } catch (Exception e) {
+                    throw new AssertionError(e);
+                }
+            }
+            // END Android-added: Custom built-in URLStreamHandlers for http, https.
+
+            synchronized (streamHandlerLock) {
+
+                URLStreamHandler handler2 = null;
+
+                // Check again with hashtable just in case another
+                // thread created a handler since we last checked
+                handler2 = handlers.get(protocol);
+
+                if (handler2 != null) {
+                    return handler2;
+                }
+
+                // Check with factory if another thread set a
+                // factory since our last check
+                if (!checkedWithFactory && factory != null) {
+                    handler2 = factory.createURLStreamHandler(protocol);
+                }
+
+                if (handler2 != null) {
+                    // The handler from the factory must be given more
+                    // importance. Discard the default handler that
+                    // this thread created.
+                    handler = handler2;
+                }
+
+                // Insert this handler into the hashtable
+                if (handler != null) {
+                    handlers.put(protocol, handler);
+                }
+
+            }
+        }
+
+        return handler;
+
+    }
+
+    // BEGIN Android-added: Custom built-in URLStreamHandlers for http, https.
+    /**
+     * Returns an instance of the built-in handler for the given protocol, or null if none exists.
+     */
+    private static URLStreamHandler createBuiltinHandler(String protocol)
+            throws ClassNotFoundException, InstantiationException, IllegalAccessException {
+        URLStreamHandler handler = null;
+        if (protocol.equals("file")) {
+            handler = new sun.net.www.protocol.file.Handler();
+        } else if (protocol.equals("ftp")) {
+            handler = new sun.net.www.protocol.ftp.Handler();
+        } else if (protocol.equals("jar")) {
+            handler = new sun.net.www.protocol.jar.Handler();
+        } else if (protocol.equals("http")) {
+            handler = (URLStreamHandler)Class.
+                    forName("com.android.okhttp.HttpHandler").newInstance();
+        } else if (protocol.equals("https")) {
+            handler = (URLStreamHandler)Class.
+                    forName("com.android.okhttp.HttpsHandler").newInstance();
+        }
+        return handler;
+    }
+
+    /** Names of implementation classes returned by {@link #createBuiltinHandler(String)}. */
+    private static Set<String> createBuiltinHandlerClassNames() {
+        Set<String> result = new HashSet<>();
+        // Refer to class names rather than classes to avoid needlessly triggering <clinit>.
+        result.add("sun.net.www.protocol.file.Handler");
+        result.add("sun.net.www.protocol.ftp.Handler");
+        result.add("sun.net.www.protocol.jar.Handler");
+        result.add("com.android.okhttp.HttpHandler");
+        result.add("com.android.okhttp.HttpsHandler");
+        return Collections.unmodifiableSet(result);
+    }
+    // END Android-added: Custom built-in URLStreamHandlers for http, https.
+
+    /**
+     * @serialField    protocol String
+     *
+     * @serialField    host String
+     *
+     * @serialField    port int
+     *
+     * @serialField    authority String
+     *
+     * @serialField    file String
+     *
+     * @serialField    ref String
+     *
+     * @serialField    hashCode int
+     *
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("protocol", String.class),
+        new ObjectStreamField("host", String.class),
+        new ObjectStreamField("port", int.class),
+        new ObjectStreamField("authority", String.class),
+        new ObjectStreamField("file", String.class),
+        new ObjectStreamField("ref", String.class),
+    // Android-changed: App compat: hashCode should not be serialized.
+    //    new ObjectStreamField("hashCode", int.class), };
+    };
+
+    /**
+     * WriteObject is called to save the state of the URL to an
+     * ObjectOutputStream. The handler is not saved since it is
+     * specific to this system.
+     *
+     * @serialData the default write object value. When read back in,
+     * the reader must ensure that calling getURLStreamHandler with
+     * the protocol variable returns a valid URLStreamHandler and
+     * throw an IOException if it does not.
+     */
+    private synchronized void writeObject(java.io.ObjectOutputStream s)
+        throws IOException
+    {
+        s.defaultWriteObject(); // write the fields
+    }
+
+    /**
+     * readObject is called to restore the state of the URL from the
+     * stream.  It reads the components of the URL and finds the local
+     * stream handler.
+     */
+    private synchronized void readObject(java.io.ObjectInputStream s)
+            throws IOException, ClassNotFoundException {
+        GetField gf = s.readFields();
+        String protocol = (String)gf.get("protocol", null);
+        if (getURLStreamHandler(protocol) == null) {
+            throw new IOException("unknown protocol: " + protocol);
+        }
+        String host = (String)gf.get("host", null);
+        int port = gf.get("port", -1);
+        String authority = (String)gf.get("authority", null);
+        String file = (String)gf.get("file", null);
+        String ref = (String)gf.get("ref", null);
+        // Android-changed: App compat: hashCode should not be serialized.
+        // int hashCode = gf.get("hashCode", -1);
+        final int hashCode = -1;
+        if (authority == null
+                && ((host != null && host.length() > 0) || port != -1)) {
+            if (host == null)
+                host = "";
+            authority = (port == -1) ? host : host + ":" + port;
+        }
+        tempState = new UrlDeserializedState(protocol, host, port, authority,
+               file, ref, hashCode);
+    }
+
+    /**
+     * Replaces the de-serialized object with an URL object.
+     *
+     * @return a newly created object from the deserialzed state.
+     *
+     * @throws ObjectStreamException if a new object replacing this
+     * object could not be created
+     */
+
+   private Object readResolve() throws ObjectStreamException {
+
+        URLStreamHandler handler = null;
+        // already been checked in readObject
+        handler = getURLStreamHandler(tempState.getProtocol());
+
+        URL replacementURL = null;
+        if (isBuiltinStreamHandler(handler.getClass().getName())) {
+            replacementURL = fabricateNewURL();
+        } else {
+            replacementURL = setDeserializedFields(handler);
+        }
+        return replacementURL;
+    }
+
+    private URL setDeserializedFields(URLStreamHandler handler) {
+        URL replacementURL;
+        String userInfo = null;
+        String protocol = tempState.getProtocol();
+        String host = tempState.getHost();
+        int port = tempState.getPort();
+        String authority = tempState.getAuthority();
+        String file = tempState.getFile();
+        String ref = tempState.getRef();
+        int hashCode = tempState.getHashCode();
+
+
+        // Construct authority part
+        if (authority == null
+            && ((host != null && host.length() > 0) || port != -1)) {
+            if (host == null)
+                host = "";
+            authority = (port == -1) ? host : host + ":" + port;
+
+            // Handle hosts with userInfo in them
+            int at = host.lastIndexOf('@');
+            if (at != -1) {
+                userInfo = host.substring(0, at);
+                host = host.substring(at+1);
+            }
+        } else if (authority != null) {
+            // Construct user info part
+            int ind = authority.indexOf('@');
+            if (ind != -1)
+                userInfo = authority.substring(0, ind);
+        }
+
+        // Construct path and query part
+        String path = null;
+        String query = null;
+        if (file != null) {
+            // Fix: only do this if hierarchical?
+            int q = file.lastIndexOf('?');
+            if (q != -1) {
+                query = file.substring(q+1);
+                path = file.substring(0, q);
+            } else
+                path = file;
+        }
+
+        // Set the object fields.
+        this.protocol = protocol;
+        this.host = host;
+        this.port = port;
+        this.file = file;
+        this.authority = authority;
+        this.ref = ref;
+        this.hashCode = hashCode;
+        this.handler = handler;
+        this.query = query;
+        this.path = path;
+        this.userInfo = userInfo;
+        replacementURL = this;
+        return replacementURL;
+    }
+
+    private URL fabricateNewURL()
+                throws InvalidObjectException {
+        // create URL string from deserialized object
+        URL replacementURL = null;
+        String urlString = tempState.reconstituteUrlString();
+
+        try {
+            replacementURL = new URL(urlString);
+        } catch (MalformedURLException mEx) {
+            resetState();
+            InvalidObjectException invoEx = new InvalidObjectException(
+                    "Malformed URL: " + urlString);
+            invoEx.initCause(mEx);
+            throw invoEx;
+        }
+        replacementURL.setSerializedHashCode(tempState.getHashCode());
+        resetState();
+        return replacementURL;
+    }
+
+    private boolean isBuiltinStreamHandler(String handlerClassName) {
+        // Android-changed: Some built-in handlers (eg. HttpHandler) are not in sun.net.www.protocol.
+        // return (handlerClassName.startsWith(BUILTIN_HANDLERS_PREFIX));
+        return BUILTIN_HANDLER_CLASS_NAMES.contains(handlerClassName);
+    }
+
+    private void resetState() {
+        this.protocol = null;
+        this.host = null;
+        this.port = -1;
+        this.file = null;
+        this.authority = null;
+        this.ref = null;
+        this.hashCode = -1;
+        this.handler = null;
+        this.query = null;
+        this.path = null;
+        this.userInfo = null;
+        this.tempState = null;
+    }
+
+    private void setSerializedHashCode(int hc) {
+        this.hashCode = hc;
+    }
+}
+
+class Parts {
+    String path, query, ref;
+
+    // Android-changed: App compat. Prepend '/' if host is null / empty.
+    // Parts(String file)
+    Parts(String file, String host) {
+        int ind = file.indexOf('#');
+        ref = ind < 0 ? null: file.substring(ind + 1);
+        file = ind < 0 ? file: file.substring(0, ind);
+        int q = file.lastIndexOf('?');
+        if (q != -1) {
+            query = file.substring(q+1);
+            path = file.substring(0, q);
+        } else {
+            path = file;
+        }
+        // BEGIN Android-changed: App compat. Prepend '/' if host is null / empty.
+        if (path != null && path.length() > 0 && path.charAt(0) != '/' &&
+            host != null && !host.isEmpty()) {
+            path = '/' + path;
+        }
+        // END Android-changed: App compat. Prepend '/' if host is null / empty.
+    }
+
+    String getPath() {
+        return path;
+    }
+
+    String getQuery() {
+        return query;
+    }
+
+    String getRef() {
+        return ref;
+    }
+}
+
+final class UrlDeserializedState {
+    private final String protocol;
+    private final String host;
+    private final int port;
+    private final String authority;
+    private final String file;
+    private final String ref;
+    private final int hashCode;
+
+    public UrlDeserializedState(String protocol,
+                                String host, int port,
+                                String authority, String file,
+                                String ref, int hashCode) {
+        this.protocol = protocol;
+        this.host = host;
+        this.port = port;
+        this.authority = authority;
+        this.file = file;
+        this.ref = ref;
+        this.hashCode = hashCode;
+    }
+
+    String getProtocol() {
+        return protocol;
+    }
+
+    String getHost() {
+        return host;
+    }
+
+    String getAuthority () {
+        return authority;
+    }
+
+    int getPort() {
+        return port;
+    }
+
+    String getFile () {
+        return file;
+    }
+
+    String getRef () {
+        return ref;
+    }
+
+    int getHashCode () {
+        return hashCode;
+    }
+
+    String reconstituteUrlString() {
+
+        // pre-compute length of StringBuilder
+        int len = protocol.length() + 1;
+        if (authority != null && authority.length() > 0)
+            len += 2 + authority.length();
+        if (file != null) {
+            len += file.length();
+        }
+        if (ref != null)
+            len += 1 + ref.length();
+        StringBuilder result = new StringBuilder(len);
+        result.append(protocol);
+        result.append(":");
+        if (authority != null && authority.length() > 0) {
+            result.append("//");
+            result.append(authority);
+        }
+        if (file != null) {
+            result.append(file);
+        }
+        if (ref != null) {
+            result.append("#");
+            result.append(ref);
+        }
+        return result.toString();
+    }
+}
diff --git a/java/net/URLClassLoader.java b/java/net/URLClassLoader.java
new file mode 100644
index 0000000..6e8acb1
--- /dev/null
+++ b/java/net/URLClassLoader.java
@@ -0,0 +1,819 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FilePermission;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.CodeSigner;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.security.SecureClassLoader;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.jar.Attributes;
+import java.util.jar.Attributes.Name;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import sun.misc.Resource;
+import sun.misc.URLClassPath;
+import sun.net.www.ParseUtil;
+import sun.security.util.SecurityConstants;
+
+/**
+ * This class loader is used to load classes and resources from a search
+ * path of URLs referring to both JAR files and directories. Any URL that
+ * ends with a '/' is assumed to refer to a directory. Otherwise, the URL
+ * is assumed to refer to a JAR file which will be opened as needed.
+ * <p>
+ * The AccessControlContext of the thread that created the instance of
+ * URLClassLoader will be used when subsequently loading classes and
+ * resources.
+ * <p>
+ * The classes that are loaded are by default granted permission only to
+ * access the URLs specified when the URLClassLoader was created.
+ *
+ * @author  David Connelly
+ * @since   1.2
+ */
+public class URLClassLoader extends SecureClassLoader implements Closeable {
+    /* The search path for classes and resources */
+    private final URLClassPath ucp;
+
+    /* The context to be used when loading classes and resources */
+    private final AccessControlContext acc;
+
+    /**
+     * Constructs a new URLClassLoader for the given URLs. The URLs will be
+     * searched in the order specified for classes and resources after first
+     * searching in the specified parent class loader. Any URL that ends with
+     * a '/' is assumed to refer to a directory. Otherwise, the URL is assumed
+     * to refer to a JAR file which will be downloaded and opened as needed.
+     *
+     * <p>If there is a security manager, this method first
+     * calls the security manager's {@code checkCreateClassLoader} method
+     * to ensure creation of a class loader is allowed.
+     *
+     * @param urls the URLs from which to load classes and resources
+     * @param parent the parent class loader for delegation
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkCreateClassLoader} method doesn't allow
+     *             creation of a class loader.
+     * @exception  NullPointerException if {@code urls} is {@code null}.
+     * @see SecurityManager#checkCreateClassLoader
+     */
+    public URLClassLoader(URL[] urls, ClassLoader parent) {
+        super(parent);
+        // this is to make the stack depth consistent with 1.1
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkCreateClassLoader();
+        }
+        this.acc = AccessController.getContext();
+        ucp = new URLClassPath(urls, acc);
+    }
+
+    URLClassLoader(URL[] urls, ClassLoader parent,
+                   AccessControlContext acc) {
+        super(parent);
+        // this is to make the stack depth consistent with 1.1
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkCreateClassLoader();
+        }
+        this.acc = acc;
+        ucp = new URLClassPath(urls, acc);
+    }
+
+    /**
+     * Constructs a new URLClassLoader for the specified URLs using the
+     * default delegation parent {@code ClassLoader}. The URLs will
+     * be searched in the order specified for classes and resources after
+     * first searching in the parent class loader. Any URL that ends with
+     * a '/' is assumed to refer to a directory. Otherwise, the URL is
+     * assumed to refer to a JAR file which will be downloaded and opened
+     * as needed.
+     *
+     * <p>If there is a security manager, this method first
+     * calls the security manager's {@code checkCreateClassLoader} method
+     * to ensure creation of a class loader is allowed.
+     *
+     * @param urls the URLs from which to load classes and resources
+     *
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkCreateClassLoader} method doesn't allow
+     *             creation of a class loader.
+     * @exception  NullPointerException if {@code urls} is {@code null}.
+     * @see SecurityManager#checkCreateClassLoader
+     */
+    public URLClassLoader(URL[] urls) {
+        super();
+        // this is to make the stack depth consistent with 1.1
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkCreateClassLoader();
+        }
+        this.acc = AccessController.getContext();
+        ucp = new URLClassPath(urls, acc);
+    }
+
+    URLClassLoader(URL[] urls, AccessControlContext acc) {
+        super();
+        // this is to make the stack depth consistent with 1.1
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkCreateClassLoader();
+        }
+        this.acc = acc;
+        ucp = new URLClassPath(urls, acc);
+    }
+
+    /**
+     * Constructs a new URLClassLoader for the specified URLs, parent
+     * class loader, and URLStreamHandlerFactory. The parent argument
+     * will be used as the parent class loader for delegation. The
+     * factory argument will be used as the stream handler factory to
+     * obtain protocol handlers when creating new jar URLs.
+     *
+     * <p>If there is a security manager, this method first
+     * calls the security manager's {@code checkCreateClassLoader} method
+     * to ensure creation of a class loader is allowed.
+     *
+     * @param urls the URLs from which to load classes and resources
+     * @param parent the parent class loader for delegation
+     * @param factory the URLStreamHandlerFactory to use when creating URLs
+     *
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkCreateClassLoader} method doesn't allow
+     *             creation of a class loader.
+     * @exception  NullPointerException if {@code urls} is {@code null}.
+     * @see SecurityManager#checkCreateClassLoader
+     */
+    public URLClassLoader(URL[] urls, ClassLoader parent,
+                          URLStreamHandlerFactory factory) {
+        super(parent);
+        // this is to make the stack depth consistent with 1.1
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkCreateClassLoader();
+        }
+        acc = AccessController.getContext();
+        ucp = new URLClassPath(urls, factory, acc);
+    }
+
+    /* A map (used as a set) to keep track of closeable local resources
+     * (either JarFiles or FileInputStreams). We don't care about
+     * Http resources since they don't need to be closed.
+     *
+     * If the resource is coming from a jar file
+     * we keep a (weak) reference to the JarFile object which can
+     * be closed if URLClassLoader.close() called. Due to jar file
+     * caching there will typically be only one JarFile object
+     * per underlying jar file.
+     *
+     * For file resources, which is probably a less common situation
+     * we have to keep a weak reference to each stream.
+     */
+
+    private WeakHashMap<Closeable,Void>
+        closeables = new WeakHashMap<>();
+
+    /**
+     * Returns an input stream for reading the specified resource.
+     * If this loader is closed, then any resources opened by this method
+     * will be closed.
+     *
+     * <p> The search order is described in the documentation for {@link
+     * #getResource(String)}.  </p>
+     *
+     * @param  name
+     *         The resource name
+     *
+     * @return  An input stream for reading the resource, or {@code null}
+     *          if the resource could not be found
+     *
+     * @since  1.7
+     */
+    public InputStream getResourceAsStream(String name) {
+        URL url = getResource(name);
+        try {
+            if (url == null) {
+                return null;
+            }
+            URLConnection urlc = url.openConnection();
+            InputStream is = urlc.getInputStream();
+            if (urlc instanceof JarURLConnection) {
+                JarURLConnection juc = (JarURLConnection)urlc;
+                JarFile jar = juc.getJarFile();
+                synchronized (closeables) {
+                    if (!closeables.containsKey(jar)) {
+                        closeables.put(jar, null);
+                    }
+                }
+            } else if (urlc instanceof sun.net.www.protocol.file.FileURLConnection) {
+                synchronized (closeables) {
+                    closeables.put(is, null);
+                }
+            }
+            return is;
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+   /**
+    * Closes this URLClassLoader, so that it can no longer be used to load
+    * new classes or resources that are defined by this loader.
+    * Classes and resources defined by any of this loader's parents in the
+    * delegation hierarchy are still accessible. Also, any classes or resources
+    * that are already loaded, are still accessible.
+    * <p>
+    * In the case of jar: and file: URLs, it also closes any files
+    * that were opened by it. If another thread is loading a
+    * class when the {@code close} method is invoked, then the result of
+    * that load is undefined.
+    * <p>
+    * The method makes a best effort attempt to close all opened files,
+    * by catching {@link IOException}s internally. Unchecked exceptions
+    * and errors are not caught. Calling close on an already closed
+    * loader has no effect.
+    * <p>
+    * @exception IOException if closing any file opened by this class loader
+    * resulted in an IOException. Any such exceptions are caught internally.
+    * If only one is caught, then it is re-thrown. If more than one exception
+    * is caught, then the second and following exceptions are added
+    * as suppressed exceptions of the first one caught, which is then re-thrown.
+    *
+    * @exception SecurityException if a security manager is set, and it denies
+    *   {@link RuntimePermission}{@code ("closeClassLoader")}
+    *
+    * @since 1.7
+    */
+    public void close() throws IOException {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkPermission(new RuntimePermission("closeClassLoader"));
+        }
+        List<IOException> errors = ucp.closeLoaders();
+
+        // now close any remaining streams.
+
+        synchronized (closeables) {
+            Set<Closeable> keys = closeables.keySet();
+            for (Closeable c : keys) {
+                try {
+                    c.close();
+                } catch (IOException ioex) {
+                    errors.add(ioex);
+                }
+            }
+            closeables.clear();
+        }
+
+        if (errors.isEmpty()) {
+            return;
+        }
+
+        IOException firstex = errors.remove(0);
+
+        // Suppress any remaining exceptions
+
+        for (IOException error: errors) {
+            firstex.addSuppressed(error);
+        }
+        throw firstex;
+    }
+
+    /**
+     * Appends the specified URL to the list of URLs to search for
+     * classes and resources.
+     * <p>
+     * If the URL specified is {@code null} or is already in the
+     * list of URLs, or if this loader is closed, then invoking this
+     * method has no effect.
+     *
+     * @param url the URL to be added to the search path of URLs
+     */
+    protected void addURL(URL url) {
+        ucp.addURL(url);
+    }
+
+    /**
+     * Returns the search path of URLs for loading classes and resources.
+     * This includes the original list of URLs specified to the constructor,
+     * along with any URLs subsequently appended by the addURL() method.
+     * @return the search path of URLs for loading classes and resources.
+     */
+    public URL[] getURLs() {
+        return ucp.getURLs();
+    }
+
+    /**
+     * Finds and loads the class with the specified name from the URL search
+     * path. Any URLs referring to JAR files are loaded and opened as needed
+     * until the class is found.
+     *
+     * @param name the name of the class
+     * @return the resulting class
+     * @exception ClassNotFoundException if the class could not be found,
+     *            or if the loader is closed.
+     * @exception NullPointerException if {@code name} is {@code null}.
+     */
+    protected Class<?> findClass(final String name)
+        throws ClassNotFoundException
+    {
+        final Class<?> result;
+        try {
+            result = AccessController.doPrivileged(
+                new PrivilegedExceptionAction<Class<?>>() {
+                    public Class<?> run() throws ClassNotFoundException {
+                        String path = name.replace('.', '/').concat(".class");
+                        Resource res = ucp.getResource(path, false);
+                        if (res != null) {
+                            try {
+                                return defineClass(name, res);
+                            } catch (IOException e) {
+                                throw new ClassNotFoundException(name, e);
+                            }
+                        } else {
+                            return null;
+                        }
+                    }
+                }, acc);
+        } catch (java.security.PrivilegedActionException pae) {
+            throw (ClassNotFoundException) pae.getException();
+        }
+        if (result == null) {
+            throw new ClassNotFoundException(name);
+        }
+        return result;
+    }
+
+    /*
+     * Retrieve the package using the specified package name.
+     * If non-null, verify the package using the specified code
+     * source and manifest.
+     */
+    private Package getAndVerifyPackage(String pkgname,
+                                        Manifest man, URL url) {
+        Package pkg = getPackage(pkgname);
+        if (pkg != null) {
+            // Package found, so check package sealing.
+            if (pkg.isSealed()) {
+                // Verify that code source URL is the same.
+                if (!pkg.isSealed(url)) {
+                    throw new SecurityException(
+                        "sealing violation: package " + pkgname + " is sealed");
+                }
+            } else {
+                // Make sure we are not attempting to seal the package
+                // at this code source URL.
+                if ((man != null) && isSealed(pkgname, man)) {
+                    throw new SecurityException(
+                        "sealing violation: can't seal package " + pkgname +
+                        ": already loaded");
+                }
+            }
+        }
+        return pkg;
+    }
+
+    // Also called by VM to define Package for classes loaded from the CDS
+    // archive
+    private void definePackageInternal(String pkgname, Manifest man, URL url)
+    {
+        if (getAndVerifyPackage(pkgname, man, url) == null) {
+            try {
+                if (man != null) {
+                    definePackage(pkgname, man, url);
+                } else {
+                    definePackage(pkgname, null, null, null, null, null, null, null);
+                }
+            } catch (IllegalArgumentException iae) {
+                // parallel-capable class loaders: re-verify in case of a
+                // race condition
+                if (getAndVerifyPackage(pkgname, man, url) == null) {
+                    // Should never happen
+                    throw new AssertionError("Cannot find package " +
+                                             pkgname);
+                }
+            }
+        }
+    }
+
+    /*
+     * Defines a Class using the class bytes obtained from the specified
+     * Resource. The resulting Class must be resolved before it can be
+     * used.
+     */
+    private Class<?> defineClass(String name, Resource res) throws IOException {
+        long t0 = System.nanoTime();
+        int i = name.lastIndexOf('.');
+        URL url = res.getCodeSourceURL();
+        if (i != -1) {
+            String pkgname = name.substring(0, i);
+            // Check if package already loaded.
+            Manifest man = res.getManifest();
+            definePackageInternal(pkgname, man, url);
+        }
+        // Now read the class bytes and define the class
+        java.nio.ByteBuffer bb = res.getByteBuffer();
+        if (bb != null) {
+            // Use (direct) ByteBuffer:
+            CodeSigner[] signers = res.getCodeSigners();
+            CodeSource cs = new CodeSource(url, signers);
+            // Android-removed: Android doesn't use sun.misc.PerfCounter.
+            // sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
+            return defineClass(name, bb, cs);
+        } else {
+            byte[] b = res.getBytes();
+            // must read certificates AFTER reading bytes.
+            CodeSigner[] signers = res.getCodeSigners();
+            CodeSource cs = new CodeSource(url, signers);
+            // Android-removed: Android doesn't use sun.misc.PerfCounter.
+            // sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
+            return defineClass(name, b, 0, b.length, cs);
+        }
+    }
+
+    /**
+     * Defines a new package by name in this ClassLoader. The attributes
+     * contained in the specified Manifest will be used to obtain package
+     * version and sealing information. For sealed packages, the additional
+     * URL specifies the code source URL from which the package was loaded.
+     *
+     * @param name  the package name
+     * @param man   the Manifest containing package version and sealing
+     *              information
+     * @param url   the code source url for the package, or null if none
+     * @exception   IllegalArgumentException if the package name duplicates
+     *              an existing package either in this class loader or one
+     *              of its ancestors
+     * @return the newly defined Package object
+     */
+    protected Package definePackage(String name, Manifest man, URL url)
+        throws IllegalArgumentException
+    {
+        String path = name.replace('.', '/').concat("/");
+        String specTitle = null, specVersion = null, specVendor = null;
+        String implTitle = null, implVersion = null, implVendor = null;
+        String sealed = null;
+        URL sealBase = null;
+
+        Attributes attr = man.getAttributes(path);
+        if (attr != null) {
+            specTitle   = attr.getValue(Name.SPECIFICATION_TITLE);
+            specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
+            specVendor  = attr.getValue(Name.SPECIFICATION_VENDOR);
+            implTitle   = attr.getValue(Name.IMPLEMENTATION_TITLE);
+            implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
+            implVendor  = attr.getValue(Name.IMPLEMENTATION_VENDOR);
+            sealed      = attr.getValue(Name.SEALED);
+        }
+        attr = man.getMainAttributes();
+        if (attr != null) {
+            if (specTitle == null) {
+                specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
+            }
+            if (specVersion == null) {
+                specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
+            }
+            if (specVendor == null) {
+                specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
+            }
+            if (implTitle == null) {
+                implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
+            }
+            if (implVersion == null) {
+                implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
+            }
+            if (implVendor == null) {
+                implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
+            }
+            if (sealed == null) {
+                sealed = attr.getValue(Name.SEALED);
+            }
+        }
+        if ("true".equalsIgnoreCase(sealed)) {
+            sealBase = url;
+        }
+        return definePackage(name, specTitle, specVersion, specVendor,
+                             implTitle, implVersion, implVendor, sealBase);
+    }
+
+    /*
+     * Returns true if the specified package name is sealed according to the
+     * given manifest.
+     */
+    private boolean isSealed(String name, Manifest man) {
+        String path = name.replace('.', '/').concat("/");
+        Attributes attr = man.getAttributes(path);
+        String sealed = null;
+        if (attr != null) {
+            sealed = attr.getValue(Name.SEALED);
+        }
+        if (sealed == null) {
+            if ((attr = man.getMainAttributes()) != null) {
+                sealed = attr.getValue(Name.SEALED);
+            }
+        }
+        return "true".equalsIgnoreCase(sealed);
+    }
+
+    /**
+     * Finds the resource with the specified name on the URL search path.
+     *
+     * @param name the name of the resource
+     * @return a {@code URL} for the resource, or {@code null}
+     * if the resource could not be found, or if the loader is closed.
+     */
+    public URL findResource(final String name) {
+        /*
+         * The same restriction to finding classes applies to resources
+         */
+        URL url = AccessController.doPrivileged(
+            new PrivilegedAction<URL>() {
+                public URL run() {
+                    return ucp.findResource(name, true);
+                }
+            }, acc);
+
+        return url != null ? ucp.checkURL(url) : null;
+    }
+
+    /**
+     * Returns an Enumeration of URLs representing all of the resources
+     * on the URL search path having the specified name.
+     *
+     * @param name the resource name
+     * @exception IOException if an I/O exception occurs
+     * @return an {@code Enumeration} of {@code URL}s
+     *         If the loader is closed, the Enumeration will be empty.
+     */
+    public Enumeration<URL> findResources(final String name)
+        throws IOException
+    {
+        final Enumeration<URL> e = ucp.findResources(name, true);
+
+        return new Enumeration<URL>() {
+            private URL url = null;
+
+            private boolean next() {
+                if (url != null) {
+                    return true;
+                }
+                do {
+                    URL u = AccessController.doPrivileged(
+                        new PrivilegedAction<URL>() {
+                            public URL run() {
+                                if (!e.hasMoreElements())
+                                    return null;
+                                return e.nextElement();
+                            }
+                        }, acc);
+                    if (u == null)
+                        break;
+                    url = ucp.checkURL(u);
+                } while (url == null);
+                return url != null;
+            }
+
+            public URL nextElement() {
+                if (!next()) {
+                    throw new NoSuchElementException();
+                }
+                URL u = url;
+                url = null;
+                return u;
+            }
+
+            public boolean hasMoreElements() {
+                return next();
+            }
+        };
+    }
+
+    /**
+     * Returns the permissions for the given codesource object.
+     * The implementation of this method first calls super.getPermissions
+     * and then adds permissions based on the URL of the codesource.
+     * <p>
+     * If the protocol of this URL is "jar", then the permission granted
+     * is based on the permission that is required by the URL of the Jar
+     * file.
+     * <p>
+     * If the protocol is "file" and there is an authority component, then
+     * permission to connect to and accept connections from that authority
+     * may be granted. If the protocol is "file"
+     * and the path specifies a file, then permission to read that
+     * file is granted. If protocol is "file" and the path is
+     * a directory, permission is granted to read all files
+     * and (recursively) all files and subdirectories contained in
+     * that directory.
+     * <p>
+     * If the protocol is not "file", then permission
+     * to connect to and accept connections from the URL's host is granted.
+     * @param codesource the codesource
+     * @exception NullPointerException if {@code codesource} is {@code null}.
+     * @return the permissions granted to the codesource
+     */
+    protected PermissionCollection getPermissions(CodeSource codesource)
+    {
+        PermissionCollection perms = super.getPermissions(codesource);
+
+        URL url = codesource.getLocation();
+
+        Permission p;
+        URLConnection urlConnection;
+
+        try {
+            urlConnection = url.openConnection();
+            p = urlConnection.getPermission();
+        } catch (java.io.IOException ioe) {
+            p = null;
+            urlConnection = null;
+        }
+
+        if (p instanceof FilePermission) {
+            // if the permission has a separator char on the end,
+            // it means the codebase is a directory, and we need
+            // to add an additional permission to read recursively
+            String path = p.getName();
+            if (path.endsWith(File.separator)) {
+                path += "-";
+                p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
+            }
+        } else if ((p == null) && (url.getProtocol().equals("file"))) {
+            String path = url.getFile().replace('/', File.separatorChar);
+            path = ParseUtil.decode(path);
+            if (path.endsWith(File.separator))
+                path += "-";
+            p =  new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
+        } else {
+            /**
+             * Not loading from a 'file:' URL so we want to give the class
+             * permission to connect to and accept from the remote host
+             * after we've made sure the host is the correct one and is valid.
+             */
+            URL locUrl = url;
+            if (urlConnection instanceof JarURLConnection) {
+                locUrl = ((JarURLConnection)urlConnection).getJarFileURL();
+            }
+            String host = locUrl.getHost();
+            if (host != null && (host.length() > 0))
+                p = new SocketPermission(host,
+                                         SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION);
+        }
+
+        // make sure the person that created this class loader
+        // would have this permission
+
+        if (p != null) {
+            final SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                final Permission fp = p;
+                AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                    public Void run() throws SecurityException {
+                        sm.checkPermission(fp);
+                        return null;
+                    }
+                }, acc);
+            }
+            perms.add(p);
+        }
+        return perms;
+    }
+
+    /**
+     * Creates a new instance of URLClassLoader for the specified
+     * URLs and parent class loader. If a security manager is
+     * installed, the {@code loadClass} method of the URLClassLoader
+     * returned by this method will invoke the
+     * {@code SecurityManager.checkPackageAccess} method before
+     * loading the class.
+     *
+     * @param urls the URLs to search for classes and resources
+     * @param parent the parent class loader for delegation
+     * @exception  NullPointerException if {@code urls} is {@code null}.
+     * @return the resulting class loader
+     */
+    public static URLClassLoader newInstance(final URL[] urls,
+                                             final ClassLoader parent) {
+        // Save the caller's context
+        final AccessControlContext acc = AccessController.getContext();
+        // Need a privileged block to create the class loader
+        URLClassLoader ucl = AccessController.doPrivileged(
+            new PrivilegedAction<URLClassLoader>() {
+                public URLClassLoader run() {
+                    return new FactoryURLClassLoader(urls, parent, acc);
+                }
+            });
+        return ucl;
+    }
+
+    /**
+     * Creates a new instance of URLClassLoader for the specified
+     * URLs and default parent class loader. If a security manager is
+     * installed, the {@code loadClass} method of the URLClassLoader
+     * returned by this method will invoke the
+     * {@code SecurityManager.checkPackageAccess} before
+     * loading the class.
+     *
+     * @param urls the URLs to search for classes and resources
+     * @exception  NullPointerException if {@code urls} is {@code null}.
+     * @return the resulting class loader
+     */
+    public static URLClassLoader newInstance(final URL[] urls) {
+        // Save the caller's context
+        final AccessControlContext acc = AccessController.getContext();
+        // Need a privileged block to create the class loader
+        URLClassLoader ucl = AccessController.doPrivileged(
+            new PrivilegedAction<URLClassLoader>() {
+                public URLClassLoader run() {
+                    return new FactoryURLClassLoader(urls, acc);
+                }
+            });
+        return ucl;
+    }
+
+    static {
+        // Android-removed: SharedSecrets.setJavaNetAccess call. Android doesn't use it.
+        /*sun.misc.SharedSecrets.setJavaNetAccess (
+            new sun.misc.JavaNetAccess() {
+                public URLClassPath getURLClassPath (URLClassLoader u) {
+                    return u.ucp;
+                }
+
+                public String getOriginalHostName(InetAddress ia) {
+                    return ia.holder.getOriginalHostName();
+                }
+            }
+        );*/
+        ClassLoader.registerAsParallelCapable();
+    }
+}
+
+final class FactoryURLClassLoader extends URLClassLoader {
+
+    static {
+        ClassLoader.registerAsParallelCapable();
+    }
+
+    FactoryURLClassLoader(URL[] urls, ClassLoader parent,
+                          AccessControlContext acc) {
+        super(urls, parent, acc);
+    }
+
+    FactoryURLClassLoader(URL[] urls, AccessControlContext acc) {
+        super(urls, acc);
+    }
+
+    public final Class<?> loadClass(String name, boolean resolve)
+        throws ClassNotFoundException
+    {
+        // First check if we have permission to access the package. This
+        // should go away once we've added support for exported packages.
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            int i = name.lastIndexOf('.');
+            if (i != -1) {
+                sm.checkPackageAccess(name.substring(0, i));
+            }
+        }
+        return super.loadClass(name, resolve);
+    }
+}
diff --git a/java/net/URLConnection.java b/java/net/URLConnection.java
new file mode 100644
index 0000000..55ec26d
--- /dev/null
+++ b/java/net/URLConnection.java
@@ -0,0 +1,1820 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Hashtable;
+import java.util.Date;
+import java.util.StringTokenizer;
+import java.util.Collections;
+import java.util.Map;
+import java.util.List;
+import java.security.Permission;
+import java.security.AccessController;
+import sun.security.util.SecurityConstants;
+import sun.net.www.MessageHeader;
+
+/**
+ * The abstract class {@code URLConnection} is the superclass
+ * of all classes that represent a communications link between the
+ * application and a URL. Instances of this class can be used both to
+ * read from and to write to the resource referenced by the URL. In
+ * general, creating a connection to a URL is a multistep process:
+ *
+ * <center><table border=2 summary="Describes the process of creating a connection to a URL: openConnection() and connect() over time.">
+ * <tr><th>{@code openConnection()}</th>
+ *     <th>{@code connect()}</th></tr>
+ * <tr><td>Manipulate parameters that affect the connection to the remote
+ *         resource.</td>
+ *     <td>Interact with the resource; query header fields and
+ *         contents.</td></tr>
+ * </table>
+ * ----------------------------&gt;
+ * <br>time</center>
+ *
+ * <ol>
+ * <li>The connection object is created by invoking the
+ *     {@code openConnection} method on a URL.
+ * <li>The setup parameters and general request properties are manipulated.
+ * <li>The actual connection to the remote object is made, using the
+ *    {@code connect} method.
+ * <li>The remote object becomes available. The header fields and the contents
+ *     of the remote object can be accessed.
+ * </ol>
+ * <p>
+ * The setup parameters are modified using the following methods:
+ * <ul>
+ *   <li>{@code setAllowUserInteraction}
+ *   <li>{@code setDoInput}
+ *   <li>{@code setDoOutput}
+ *   <li>{@code setIfModifiedSince}
+ *   <li>{@code setUseCaches}
+ * </ul>
+ * <p>
+ * and the general request properties are modified using the method:
+ * <ul>
+ *   <li>{@code setRequestProperty}
+ * </ul>
+ * <p>
+ * Default values for the {@code AllowUserInteraction} and
+ * {@code UseCaches} parameters can be set using the methods
+ * {@code setDefaultAllowUserInteraction} and
+ * {@code setDefaultUseCaches}.
+ * <p>
+ * Each of the above {@code set} methods has a corresponding
+ * {@code get} method to retrieve the value of the parameter or
+ * general request property. The specific parameters and general
+ * request properties that are applicable are protocol specific.
+ * <p>
+ * The following methods are used to access the header fields and
+ * the contents after the connection is made to the remote object:
+ * <ul>
+ *   <li>{@code getContent}
+ *   <li>{@code getHeaderField}
+ *   <li>{@code getInputStream}
+ *   <li>{@code getOutputStream}
+ * </ul>
+ * <p>
+ * Certain header fields are accessed frequently. The methods:
+ * <ul>
+ *   <li>{@code getContentEncoding}
+ *   <li>{@code getContentLength}
+ *   <li>{@code getContentType}
+ *   <li>{@code getDate}
+ *   <li>{@code getExpiration}
+ *   <li>{@code getLastModifed}
+ * </ul>
+ * <p>
+ * provide convenient access to these fields. The
+ * {@code getContentType} method is used by the
+ * {@code getContent} method to determine the type of the remote
+ * object; subclasses may find it convenient to override the
+ * {@code getContentType} method.
+ * <p>
+ * In the common case, all of the pre-connection parameters and
+ * general request properties can be ignored: the pre-connection
+ * parameters and request properties default to sensible values. For
+ * most clients of this interface, there are only two interesting
+ * methods: {@code getInputStream} and {@code getContent},
+ * which are mirrored in the {@code URL} class by convenience methods.
+ * <p>
+ * More information on the request properties and header fields of
+ * an {@code http} connection can be found at:
+ * <blockquote><pre>
+ * <a href="http://www.ietf.org/rfc/rfc2616.txt">http://www.ietf.org/rfc/rfc2616.txt</a>
+ * </pre></blockquote>
+ *
+ * Invoking the {@code close()} methods on the {@code InputStream} or {@code OutputStream} of an
+ * {@code URLConnection} after a request may free network resources associated with this
+ * instance, unless particular protocol specifications specify different behaviours
+ * for it.
+ *
+ * @author  James Gosling
+ * @see     java.net.URL#openConnection()
+ * @see     java.net.URLConnection#connect()
+ * @see     java.net.URLConnection#getContent()
+ * @see     java.net.URLConnection#getContentEncoding()
+ * @see     java.net.URLConnection#getContentLength()
+ * @see     java.net.URLConnection#getContentType()
+ * @see     java.net.URLConnection#getDate()
+ * @see     java.net.URLConnection#getExpiration()
+ * @see     java.net.URLConnection#getHeaderField(int)
+ * @see     java.net.URLConnection#getHeaderField(java.lang.String)
+ * @see     java.net.URLConnection#getInputStream()
+ * @see     java.net.URLConnection#getLastModified()
+ * @see     java.net.URLConnection#getOutputStream()
+ * @see     java.net.URLConnection#setAllowUserInteraction(boolean)
+ * @see     java.net.URLConnection#setDefaultUseCaches(boolean)
+ * @see     java.net.URLConnection#setDoInput(boolean)
+ * @see     java.net.URLConnection#setDoOutput(boolean)
+ * @see     java.net.URLConnection#setIfModifiedSince(long)
+ * @see     java.net.URLConnection#setRequestProperty(java.lang.String, java.lang.String)
+ * @see     java.net.URLConnection#setUseCaches(boolean)
+ * @since   JDK1.0
+ */
+public abstract class URLConnection {
+
+   /**
+     * The URL represents the remote object on the World Wide Web to
+     * which this connection is opened.
+     * <p>
+     * The value of this field can be accessed by the
+     * {@code getURL} method.
+     * <p>
+     * The default value of this variable is the value of the URL
+     * argument in the {@code URLConnection} constructor.
+     *
+     * @see     java.net.URLConnection#getURL()
+     * @see     java.net.URLConnection#url
+     */
+    protected URL url;
+
+   /**
+     * This variable is set by the {@code setDoInput} method. Its
+     * value is returned by the {@code getDoInput} method.
+     * <p>
+     * A URL connection can be used for input and/or output. Setting the
+     * {@code doInput} flag to {@code true} indicates that
+     * the application intends to read data from the URL connection.
+     * <p>
+     * The default value of this field is {@code true}.
+     *
+     * @see     java.net.URLConnection#getDoInput()
+     * @see     java.net.URLConnection#setDoInput(boolean)
+     */
+    protected boolean doInput = true;
+
+   /**
+     * This variable is set by the {@code setDoOutput} method. Its
+     * value is returned by the {@code getDoOutput} method.
+     * <p>
+     * A URL connection can be used for input and/or output. Setting the
+     * {@code doOutput} flag to {@code true} indicates
+     * that the application intends to write data to the URL connection.
+     * <p>
+     * The default value of this field is {@code false}.
+     *
+     * @see     java.net.URLConnection#getDoOutput()
+     * @see     java.net.URLConnection#setDoOutput(boolean)
+     */
+    protected boolean doOutput = false;
+
+    private static boolean defaultAllowUserInteraction = false;
+
+   /**
+     * If {@code true}, this {@code URL} is being examined in
+     * a context in which it makes sense to allow user interactions such
+     * as popping up an authentication dialog. If {@code false},
+     * then no user interaction is allowed.
+     * <p>
+     * The value of this field can be set by the
+     * {@code setAllowUserInteraction} method.
+     * Its value is returned by the
+     * {@code getAllowUserInteraction} method.
+     * Its default value is the value of the argument in the last invocation
+     * of the {@code setDefaultAllowUserInteraction} method.
+     *
+     * @see     java.net.URLConnection#getAllowUserInteraction()
+     * @see     java.net.URLConnection#setAllowUserInteraction(boolean)
+     * @see     java.net.URLConnection#setDefaultAllowUserInteraction(boolean)
+     */
+    protected boolean allowUserInteraction = defaultAllowUserInteraction;
+
+    private static boolean defaultUseCaches = true;
+
+   /**
+     * If {@code true}, the protocol is allowed to use caching
+     * whenever it can. If {@code false}, the protocol must always
+     * try to get a fresh copy of the object.
+     * <p>
+     * This field is set by the {@code setUseCaches} method. Its
+     * value is returned by the {@code getUseCaches} method.
+     * <p>
+     * Its default value is the value given in the last invocation of the
+     * {@code setDefaultUseCaches} method.
+     *
+     * @see     java.net.URLConnection#setUseCaches(boolean)
+     * @see     java.net.URLConnection#getUseCaches()
+     * @see     java.net.URLConnection#setDefaultUseCaches(boolean)
+     */
+    protected boolean useCaches = defaultUseCaches;
+
+   /**
+     * Some protocols support skipping the fetching of the object unless
+     * the object has been modified more recently than a certain time.
+     * <p>
+     * A nonzero value gives a time as the number of milliseconds since
+     * January 1, 1970, GMT. The object is fetched only if it has been
+     * modified more recently than that time.
+     * <p>
+     * This variable is set by the {@code setIfModifiedSince}
+     * method. Its value is returned by the
+     * {@code getIfModifiedSince} method.
+     * <p>
+     * The default value of this field is {@code 0}, indicating
+     * that the fetching must always occur.
+     *
+     * @see     java.net.URLConnection#getIfModifiedSince()
+     * @see     java.net.URLConnection#setIfModifiedSince(long)
+     */
+    protected long ifModifiedSince = 0;
+
+   /**
+     * If {@code false}, this connection object has not created a
+     * communications link to the specified URL. If {@code true},
+     * the communications link has been established.
+     */
+    protected boolean connected = false;
+
+    /**
+     * @since 1.5
+     */
+    private int connectTimeout;
+    private int readTimeout;
+
+    /**
+     * @since 1.6
+     */
+    private MessageHeader requests;
+
+   /**
+    * @since   JDK1.1
+    */
+    private static FileNameMap fileNameMap;
+
+    // BEGIN Android-changed: Android has its own mime table.
+    /*
+    /**
+     * @since 1.2.2
+     *
+    private static boolean fileNameMapLoaded = false;
+
+    /**
+     * Loads filename map (a mimetable) from a data file. It will
+     * first try to load the user-specific table, defined
+     * by &quot;content.types.user.table&quot; property. If that fails,
+     * it tries to load the default built-in table.
+     *
+     * @return the FileNameMap
+     * @since 1.2
+     * @see #setFileNameMap(java.net.FileNameMap)
+     *
+    public static synchronized FileNameMap getFileNameMap() {
+        if ((fileNameMap == null) && !fileNameMapLoaded) {
+            fileNameMap = sun.net.www.MimeTable.loadTable();
+            fileNameMapLoaded = true;
+        }
+
+        return new FileNameMap() {
+            private FileNameMap map = fileNameMap;
+            public String getContentTypeFor(String fileName) {
+                return map.getContentTypeFor(fileName);
+            }
+        };
+    }
+    */
+    /**
+     * Returns a {@link FileNameMap} implementation suitable for guessing a
+     * content type based on a URL's "file" component.
+     *
+     * @see #guessContentTypeFromName(String)
+     * @see #setFileNameMap(java.net.FileNameMap)
+     *
+     */
+    public static synchronized FileNameMap getFileNameMap() {
+        if (fileNameMap == null) {
+            fileNameMap = new DefaultFileNameMap();
+        }
+        return fileNameMap;
+    }
+    // END Android-changed: Android has its own mime table.
+
+    /**
+     * Sets the FileNameMap.
+     * <p>
+     * If there is a security manager, this method first calls
+     * the security manager's {@code checkSetFactory} method
+     * to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param map the FileNameMap to be set
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkSetFactory} method doesn't allow the operation.
+     * @see        SecurityManager#checkSetFactory
+     * @see #getFileNameMap()
+     * @since 1.2
+     */
+    public static void setFileNameMap(FileNameMap map) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) sm.checkSetFactory();
+        fileNameMap = map;
+    }
+
+    /**
+     * Opens a communications link to the resource referenced by this
+     * URL, if such a connection has not already been established.
+     * <p>
+     * If the {@code connect} method is called when the connection
+     * has already been opened (indicated by the {@code connected}
+     * field having the value {@code true}), the call is ignored.
+     * <p>
+     * URLConnection objects go through two phases: first they are
+     * created, then they are connected.  After being created, and
+     * before being connected, various options can be specified
+     * (e.g., doInput and UseCaches).  After connecting, it is an
+     * error to try to set them.  Operations that depend on being
+     * connected, like getContentLength, will implicitly perform the
+     * connection, if necessary.
+     *
+     * @throws SocketTimeoutException if the timeout expires before
+     *               the connection can be established
+     * @exception  IOException  if an I/O error occurs while opening the
+     *               connection.
+     * @see java.net.URLConnection#connected
+     * @see #getConnectTimeout()
+     * @see #setConnectTimeout(int)
+     */
+    abstract public void connect() throws IOException;
+
+    // Android-changed: Add javadoc to specify Android's timeout behavior.
+    /**
+     * Sets a specified timeout value, in milliseconds, to be used
+     * when opening a communications link to the resource referenced
+     * by this URLConnection.  If the timeout expires before the
+     * connection can be established, a
+     * java.net.SocketTimeoutException is raised. A timeout of zero is
+     * interpreted as an infinite timeout.
+
+     * <p> Some non-standard implementation of this method may ignore
+     * the specified timeout. To see the connect timeout set, please
+     * call getConnectTimeout().
+     *
+     * <p><strong>Warning</strong>: If the hostname resolves to multiple IP
+     * addresses, Android's default implementation of {@link HttpURLConnection}
+     * will try each in
+     * <a href="http://www.ietf.org/rfc/rfc3484.txt">RFC 3484</a> order. If
+     * connecting to each of these addresses fails, multiple timeouts will
+     * elapse before the connect attempt throws an exception. Host names
+     * that support both IPv6 and IPv4 always have at least 2 IP addresses.
+     *
+     * @param timeout an {@code int} that specifies the connect
+     *               timeout value in milliseconds
+     * @throws IllegalArgumentException if the timeout parameter is negative
+     *
+     * @see #getConnectTimeout()
+     * @see #connect()
+     * @since 1.5
+     */
+    public void setConnectTimeout(int timeout) {
+        if (timeout < 0) {
+            throw new IllegalArgumentException("timeout can not be negative");
+        }
+        connectTimeout = timeout;
+    }
+
+    /**
+     * Returns setting for connect timeout.
+     * <p>
+     * 0 return implies that the option is disabled
+     * (i.e., timeout of infinity).
+     *
+     * @return an {@code int} that indicates the connect timeout
+     *         value in milliseconds
+     * @see #setConnectTimeout(int)
+     * @see #connect()
+     * @since 1.5
+     */
+    public int getConnectTimeout() {
+        return connectTimeout;
+    }
+
+    /**
+     * Sets the read timeout to a specified timeout, in
+     * milliseconds. A non-zero value specifies the timeout when
+     * reading from Input stream when a connection is established to a
+     * resource. If the timeout expires before there is data available
+     * for read, a java.net.SocketTimeoutException is raised. A
+     * timeout of zero is interpreted as an infinite timeout.
+     *
+     *<p> Some non-standard implementation of this method ignores the
+     * specified timeout. To see the read timeout set, please call
+     * getReadTimeout().
+     *
+     * @param timeout an {@code int} that specifies the timeout
+     * value to be used in milliseconds
+     * @throws IllegalArgumentException if the timeout parameter is negative
+     *
+     * @see #getReadTimeout()
+     * @see InputStream#read()
+     * @since 1.5
+     */
+    public void setReadTimeout(int timeout) {
+        if (timeout < 0) {
+            throw new IllegalArgumentException("timeout can not be negative");
+        }
+        readTimeout = timeout;
+    }
+
+    /**
+     * Returns setting for read timeout. 0 return implies that the
+     * option is disabled (i.e., timeout of infinity).
+     *
+     * @return an {@code int} that indicates the read timeout
+     *         value in milliseconds
+     *
+     * @see #setReadTimeout(int)
+     * @see InputStream#read()
+     * @since 1.5
+     */
+    public int getReadTimeout() {
+        return readTimeout;
+    }
+
+    /**
+     * Constructs a URL connection to the specified URL. A connection to
+     * the object referenced by the URL is not created.
+     *
+     * @param   url   the specified URL.
+     */
+    protected URLConnection(URL url) {
+        this.url = url;
+    }
+
+    /**
+     * Returns the value of this {@code URLConnection}'s {@code URL}
+     * field.
+     *
+     * @return  the value of this {@code URLConnection}'s {@code URL}
+     *          field.
+     * @see     java.net.URLConnection#url
+     */
+    public URL getURL() {
+        return url;
+    }
+
+    /**
+     * Returns the value of the {@code content-length} header field.
+     * <P>
+     * <B>Note</B>: {@link #getContentLengthLong() getContentLengthLong()}
+     * should be preferred over this method, since it returns a {@code long}
+     * instead and is therefore more portable.</P>
+     *
+     * @return  the content length of the resource that this connection's URL
+     *          references, {@code -1} if the content length is not known,
+     *          or if the content length is greater than Integer.MAX_VALUE.
+     */
+    public int getContentLength() {
+        long l = getContentLengthLong();
+        if (l > Integer.MAX_VALUE)
+            return -1;
+        return (int) l;
+    }
+
+    /**
+     * Returns the value of the {@code content-length} header field as a
+     * long.
+     *
+     * @return  the content length of the resource that this connection's URL
+     *          references, or {@code -1} if the content length is
+     *          not known.
+     * @since 7.0
+     */
+    public long getContentLengthLong() {
+        return getHeaderFieldLong("content-length", -1);
+    }
+
+    /**
+     * Returns the value of the {@code content-type} header field.
+     *
+     * @return  the content type of the resource that the URL references,
+     *          or {@code null} if not known.
+     * @see     java.net.URLConnection#getHeaderField(java.lang.String)
+     */
+    public String getContentType() {
+        return getHeaderField("content-type");
+    }
+
+    /**
+     * Returns the value of the {@code content-encoding} header field.
+     *
+     * @return  the content encoding of the resource that the URL references,
+     *          or {@code null} if not known.
+     * @see     java.net.URLConnection#getHeaderField(java.lang.String)
+     */
+    public String getContentEncoding() {
+        return getHeaderField("content-encoding");
+    }
+
+    /**
+     * Returns the value of the {@code expires} header field.
+     *
+     * @return  the expiration date of the resource that this URL references,
+     *          or 0 if not known. The value is the number of milliseconds since
+     *          January 1, 1970 GMT.
+     * @see     java.net.URLConnection#getHeaderField(java.lang.String)
+     */
+    public long getExpiration() {
+        return getHeaderFieldDate("expires", 0);
+    }
+
+    /**
+     * Returns the value of the {@code date} header field.
+     *
+     * @return  the sending date of the resource that the URL references,
+     *          or {@code 0} if not known. The value returned is the
+     *          number of milliseconds since January 1, 1970 GMT.
+     * @see     java.net.URLConnection#getHeaderField(java.lang.String)
+     */
+    public long getDate() {
+        return getHeaderFieldDate("date", 0);
+    }
+
+    /**
+     * Returns the value of the {@code last-modified} header field.
+     * The result is the number of milliseconds since January 1, 1970 GMT.
+     *
+     * @return  the date the resource referenced by this
+     *          {@code URLConnection} was last modified, or 0 if not known.
+     * @see     java.net.URLConnection#getHeaderField(java.lang.String)
+     */
+    public long getLastModified() {
+        return getHeaderFieldDate("last-modified", 0);
+    }
+
+    /**
+     * Returns the value of the named header field.
+     * <p>
+     * If called on a connection that sets the same header multiple times
+     * with possibly different values, only the last value is returned.
+     *
+     *
+     * @param   name   the name of a header field.
+     * @return  the value of the named header field, or {@code null}
+     *          if there is no such field in the header.
+     */
+    public String getHeaderField(String name) {
+        return null;
+    }
+
+    /**
+     * Returns an unmodifiable Map of the header fields.
+     * The Map keys are Strings that represent the
+     * response-header field names. Each Map value is an
+     * unmodifiable List of Strings that represents
+     * the corresponding field values.
+     *
+     * @return a Map of header fields
+     * @since 1.4
+     */
+    public Map<String,List<String>> getHeaderFields() {
+        return Collections.emptyMap();
+    }
+
+    /**
+     * Returns the value of the named field parsed as a number.
+     * <p>
+     * This form of {@code getHeaderField} exists because some
+     * connection types (e.g., {@code http-ng}) have pre-parsed
+     * headers. Classes for that connection type can override this method
+     * and short-circuit the parsing.
+     *
+     * @param   name      the name of the header field.
+     * @param   Default   the default value.
+     * @return  the value of the named field, parsed as an integer. The
+     *          {@code Default} value is returned if the field is
+     *          missing or malformed.
+     */
+    public int getHeaderFieldInt(String name, int Default) {
+        String value = getHeaderField(name);
+        try {
+            return Integer.parseInt(value);
+        } catch (Exception e) { }
+        return Default;
+    }
+
+    /**
+     * Returns the value of the named field parsed as a number.
+     * <p>
+     * This form of {@code getHeaderField} exists because some
+     * connection types (e.g., {@code http-ng}) have pre-parsed
+     * headers. Classes for that connection type can override this method
+     * and short-circuit the parsing.
+     *
+     * @param   name      the name of the header field.
+     * @param   Default   the default value.
+     * @return  the value of the named field, parsed as a long. The
+     *          {@code Default} value is returned if the field is
+     *          missing or malformed.
+     * @since 7.0
+     */
+    public long getHeaderFieldLong(String name, long Default) {
+        String value = getHeaderField(name);
+        try {
+            return Long.parseLong(value);
+        } catch (Exception e) { }
+        return Default;
+    }
+
+    /**
+     * Returns the value of the named field parsed as date.
+     * The result is the number of milliseconds since January 1, 1970 GMT
+     * represented by the named field.
+     * <p>
+     * This form of {@code getHeaderField} exists because some
+     * connection types (e.g., {@code http-ng}) have pre-parsed
+     * headers. Classes for that connection type can override this method
+     * and short-circuit the parsing.
+     *
+     * @param   name     the name of the header field.
+     * @param   Default   a default value.
+     * @return  the value of the field, parsed as a date. The value of the
+     *          {@code Default} argument is returned if the field is
+     *          missing or malformed.
+     */
+    @SuppressWarnings("deprecation")
+    public long getHeaderFieldDate(String name, long Default) {
+        String value = getHeaderField(name);
+        try {
+            return Date.parse(value);
+        } catch (Exception e) { }
+        return Default;
+    }
+
+    /**
+     * Returns the key for the {@code n}<sup>th</sup> header field.
+     * It returns {@code null} if there are fewer than {@code n+1} fields.
+     *
+     * @param   n   an index, where {@code n>=0}
+     * @return  the key for the {@code n}<sup>th</sup> header field,
+     *          or {@code null} if there are fewer than {@code n+1}
+     *          fields.
+     */
+    public String getHeaderFieldKey(int n) {
+        return null;
+    }
+
+    /**
+     * Returns the value for the {@code n}<sup>th</sup> header field.
+     * It returns {@code null} if there are fewer than
+     * {@code n+1}fields.
+     * <p>
+     * This method can be used in conjunction with the
+     * {@link #getHeaderFieldKey(int) getHeaderFieldKey} method to iterate through all
+     * the headers in the message.
+     *
+     * @param   n   an index, where {@code n>=0}
+     * @return  the value of the {@code n}<sup>th</sup> header field
+     *          or {@code null} if there are fewer than {@code n+1} fields
+     * @see     java.net.URLConnection#getHeaderFieldKey(int)
+     */
+    public String getHeaderField(int n) {
+        return null;
+    }
+
+    /**
+     * Retrieves the contents of this URL connection.
+     * <p>
+     * This method first determines the content type of the object by
+     * calling the {@code getContentType} method. If this is
+     * the first time that the application has seen that specific content
+     * type, a content handler for that content type is created:
+     * <ol>
+     * <li>If the application has set up a content handler factory instance
+     *     using the {@code setContentHandlerFactory} method, the
+     *     {@code createContentHandler} method of that instance is called
+     *     with the content type as an argument; the result is a content
+     *     handler for that content type.
+     * <li>If no content handler factory has yet been set up, or if the
+     *     factory's {@code createContentHandler} method returns
+     *     {@code null}, then the application loads the class named:
+     *     <blockquote><pre>
+     *         sun.net.www.content.&lt;<i>contentType</i>&gt;
+     *     </pre></blockquote>
+     *     where &lt;<i>contentType</i>&gt; is formed by taking the
+     *     content-type string, replacing all slash characters with a
+     *     {@code period} ('.'), and all other non-alphanumeric characters
+     *     with the underscore character '{@code _}'. The alphanumeric
+     *     characters are specifically the 26 uppercase ASCII letters
+     *     '{@code A}' through '{@code Z}', the 26 lowercase ASCII
+     *     letters '{@code a}' through '{@code z}', and the 10 ASCII
+     *     digits '{@code 0}' through '{@code 9}'. If the specified
+     *     class does not exist, or is not a subclass of
+     *     {@code ContentHandler}, then an
+     *     {@code UnknownServiceException} is thrown.
+     * </ol>
+     *
+     * @return     the object fetched. The {@code instanceof} operator
+     *               should be used to determine the specific kind of object
+     *               returned.
+     * @exception  IOException              if an I/O error occurs while
+     *               getting the content.
+     * @exception  UnknownServiceException  if the protocol does not support
+     *               the content type.
+     * @see        java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
+     * @see        java.net.URLConnection#getContentType()
+     * @see        java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
+     */
+    public Object getContent() throws IOException {
+        // Must call getInputStream before GetHeaderField gets called
+        // so that FileNotFoundException has a chance to be thrown up
+        // from here without being caught.
+        getInputStream();
+        return getContentHandler().getContent(this);
+    }
+
+    /**
+     * Retrieves the contents of this URL connection.
+     *
+     * @param classes the {@code Class} array
+     * indicating the requested types
+     * @return     the object fetched that is the first match of the type
+     *               specified in the classes array. null if none of
+     *               the requested types are supported.
+     *               The {@code instanceof} operator should be used to
+     *               determine the specific kind of object returned.
+     * @exception  IOException              if an I/O error occurs while
+     *               getting the content.
+     * @exception  UnknownServiceException  if the protocol does not support
+     *               the content type.
+     * @see        java.net.URLConnection#getContent()
+     * @see        java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
+     * @see        java.net.URLConnection#getContent(java.lang.Class[])
+     * @see        java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
+     * @since 1.3
+     */
+    public Object getContent(Class[] classes) throws IOException {
+        // Must call getInputStream before GetHeaderField gets called
+        // so that FileNotFoundException has a chance to be thrown up
+        // from here without being caught.
+        getInputStream();
+        return getContentHandler().getContent(this, classes);
+    }
+
+    /**
+     * Returns a permission object representing the permission
+     * necessary to make the connection represented by this
+     * object. This method returns null if no permission is
+     * required to make the connection. By default, this method
+     * returns {@code java.security.AllPermission}. Subclasses
+     * should override this method and return the permission
+     * that best represents the permission required to make a
+     * a connection to the URL. For example, a {@code URLConnection}
+     * representing a {@code file:} URL would return a
+     * {@code java.io.FilePermission} object.
+     *
+     * <p>The permission returned may dependent upon the state of the
+     * connection. For example, the permission before connecting may be
+     * different from that after connecting. For example, an HTTP
+     * sever, say foo.com, may redirect the connection to a different
+     * host, say bar.com. Before connecting the permission returned by
+     * the connection will represent the permission needed to connect
+     * to foo.com, while the permission returned after connecting will
+     * be to bar.com.
+     *
+     * <p>Permissions are generally used for two purposes: to protect
+     * caches of objects obtained through URLConnections, and to check
+     * the right of a recipient to learn about a particular URL. In
+     * the first case, the permission should be obtained
+     * <em>after</em> the object has been obtained. For example, in an
+     * HTTP connection, this will represent the permission to connect
+     * to the host from which the data was ultimately fetched. In the
+     * second case, the permission should be obtained and tested
+     * <em>before</em> connecting.
+     *
+     * @return the permission object representing the permission
+     * necessary to make the connection represented by this
+     * URLConnection.
+     *
+     * @exception IOException if the computation of the permission
+     * requires network or file I/O and an exception occurs while
+     * computing it.
+     */
+    public Permission getPermission() throws IOException {
+        return SecurityConstants.ALL_PERMISSION;
+    }
+
+    /**
+     * Returns an input stream that reads from this open connection.
+     *
+     * A SocketTimeoutException can be thrown when reading from the
+     * returned input stream if the read timeout expires before data
+     * is available for read.
+     *
+     * @return     an input stream that reads from this open connection.
+     * @exception  IOException              if an I/O error occurs while
+     *               creating the input stream.
+     * @exception  UnknownServiceException  if the protocol does not support
+     *               input.
+     * @see #setReadTimeout(int)
+     * @see #getReadTimeout()
+     */
+    public InputStream getInputStream() throws IOException {
+        throw new UnknownServiceException("protocol doesn't support input");
+    }
+
+    /**
+     * Returns an output stream that writes to this connection.
+     *
+     * @return     an output stream that writes to this connection.
+     * @exception  IOException              if an I/O error occurs while
+     *               creating the output stream.
+     * @exception  UnknownServiceException  if the protocol does not support
+     *               output.
+     */
+    public OutputStream getOutputStream() throws IOException {
+        throw new UnknownServiceException("protocol doesn't support output");
+    }
+
+    /**
+     * Returns a {@code String} representation of this URL connection.
+     *
+     * @return  a string representation of this {@code URLConnection}.
+     */
+    public String toString() {
+        return this.getClass().getName() + ":" + url;
+    }
+
+    /**
+     * Sets the value of the {@code doInput} field for this
+     * {@code URLConnection} to the specified value.
+     * <p>
+     * A URL connection can be used for input and/or output.  Set the DoInput
+     * flag to true if you intend to use the URL connection for input,
+     * false if not.  The default is true.
+     *
+     * @param   doinput   the new value.
+     * @throws IllegalStateException if already connected
+     * @see     java.net.URLConnection#doInput
+     * @see #getDoInput()
+     */
+    public void setDoInput(boolean doinput) {
+        if (connected)
+            throw new IllegalStateException("Already connected");
+        doInput = doinput;
+    }
+
+    /**
+     * Returns the value of this {@code URLConnection}'s
+     * {@code doInput} flag.
+     *
+     * @return  the value of this {@code URLConnection}'s
+     *          {@code doInput} flag.
+     * @see     #setDoInput(boolean)
+     */
+    public boolean getDoInput() {
+        return doInput;
+    }
+
+    /**
+     * Sets the value of the {@code doOutput} field for this
+     * {@code URLConnection} to the specified value.
+     * <p>
+     * A URL connection can be used for input and/or output.  Set the DoOutput
+     * flag to true if you intend to use the URL connection for output,
+     * false if not.  The default is false.
+     *
+     * @param   dooutput   the new value.
+     * @throws IllegalStateException if already connected
+     * @see #getDoOutput()
+     */
+    public void setDoOutput(boolean dooutput) {
+        if (connected)
+            throw new IllegalStateException("Already connected");
+        doOutput = dooutput;
+    }
+
+    /**
+     * Returns the value of this {@code URLConnection}'s
+     * {@code doOutput} flag.
+     *
+     * @return  the value of this {@code URLConnection}'s
+     *          {@code doOutput} flag.
+     * @see     #setDoOutput(boolean)
+     */
+    public boolean getDoOutput() {
+        return doOutput;
+    }
+
+    /**
+     * Set the value of the {@code allowUserInteraction} field of
+     * this {@code URLConnection}.
+     *
+     * @param   allowuserinteraction   the new value.
+     * @throws IllegalStateException if already connected
+     * @see     #getAllowUserInteraction()
+     */
+    public void setAllowUserInteraction(boolean allowuserinteraction) {
+        if (connected)
+            throw new IllegalStateException("Already connected");
+        allowUserInteraction = allowuserinteraction;
+    }
+
+    /**
+     * Returns the value of the {@code allowUserInteraction} field for
+     * this object.
+     *
+     * @return  the value of the {@code allowUserInteraction} field for
+     *          this object.
+     * @see     #setAllowUserInteraction(boolean)
+     */
+    public boolean getAllowUserInteraction() {
+        return allowUserInteraction;
+    }
+
+    /**
+     * Sets the default value of the
+     * {@code allowUserInteraction} field for all future
+     * {@code URLConnection} objects to the specified value.
+     *
+     * @param   defaultallowuserinteraction   the new value.
+     * @see     #getDefaultAllowUserInteraction()
+     */
+    public static void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction) {
+        defaultAllowUserInteraction = defaultallowuserinteraction;
+    }
+
+    /**
+     * Returns the default value of the {@code allowUserInteraction}
+     * field.
+     * <p>
+     * Ths default is "sticky", being a part of the static state of all
+     * URLConnections.  This flag applies to the next, and all following
+     * URLConnections that are created.
+     *
+     * @return  the default value of the {@code allowUserInteraction}
+     *          field.
+     * @see     #setDefaultAllowUserInteraction(boolean)
+     */
+    public static boolean getDefaultAllowUserInteraction() {
+        return defaultAllowUserInteraction;
+    }
+
+    /**
+     * Sets the value of the {@code useCaches} field of this
+     * {@code URLConnection} to the specified value.
+     * <p>
+     * Some protocols do caching of documents.  Occasionally, it is important
+     * to be able to "tunnel through" and ignore the caches (e.g., the
+     * "reload" button in a browser).  If the UseCaches flag on a connection
+     * is true, the connection is allowed to use whatever caches it can.
+     *  If false, caches are to be ignored.
+     *  The default value comes from DefaultUseCaches, which defaults to
+     * true.
+     *
+     * @param usecaches a {@code boolean} indicating whether
+     * or not to allow caching
+     * @throws IllegalStateException if already connected
+     * @see #getUseCaches()
+     */
+    public void setUseCaches(boolean usecaches) {
+        if (connected)
+            throw new IllegalStateException("Already connected");
+        useCaches = usecaches;
+    }
+
+    /**
+     * Returns the value of this {@code URLConnection}'s
+     * {@code useCaches} field.
+     *
+     * @return  the value of this {@code URLConnection}'s
+     *          {@code useCaches} field.
+     * @see #setUseCaches(boolean)
+     */
+    public boolean getUseCaches() {
+        return useCaches;
+    }
+
+    /**
+     * Sets the value of the {@code ifModifiedSince} field of
+     * this {@code URLConnection} to the specified value.
+     *
+     * @param   ifmodifiedsince   the new value.
+     * @throws IllegalStateException if already connected
+     * @see     #getIfModifiedSince()
+     */
+    public void setIfModifiedSince(long ifmodifiedsince) {
+        if (connected)
+            throw new IllegalStateException("Already connected");
+        ifModifiedSince = ifmodifiedsince;
+    }
+
+    /**
+     * Returns the value of this object's {@code ifModifiedSince} field.
+     *
+     * @return  the value of this object's {@code ifModifiedSince} field.
+     * @see #setIfModifiedSince(long)
+     */
+    public long getIfModifiedSince() {
+        return ifModifiedSince;
+    }
+
+   /**
+     * Returns the default value of a {@code URLConnection}'s
+     * {@code useCaches} flag.
+     * <p>
+     * Ths default is "sticky", being a part of the static state of all
+     * URLConnections.  This flag applies to the next, and all following
+     * URLConnections that are created.
+     *
+     * @return  the default value of a {@code URLConnection}'s
+     *          {@code useCaches} flag.
+     * @see     #setDefaultUseCaches(boolean)
+     */
+    public boolean getDefaultUseCaches() {
+        return defaultUseCaches;
+    }
+
+   /**
+     * Sets the default value of the {@code useCaches} field to the
+     * specified value.
+     *
+     * @param   defaultusecaches   the new value.
+     * @see     #getDefaultUseCaches()
+     */
+    public void setDefaultUseCaches(boolean defaultusecaches) {
+        defaultUseCaches = defaultusecaches;
+    }
+
+    /**
+     * Sets the general request property. If a property with the key already
+     * exists, overwrite its value with the new value.
+     *
+     * <p> NOTE: HTTP requires all request properties which can
+     * legally have multiple instances with the same key
+     * to use a comma-separated list syntax which enables multiple
+     * properties to be appended into a single property.
+     *
+     * @param   key     the keyword by which the request is known
+     *                  (e.g., "{@code Accept}").
+     * @param   value   the value associated with it.
+     * @throws IllegalStateException if already connected
+     * @throws NullPointerException if key is <CODE>null</CODE>
+     * @see #getRequestProperty(java.lang.String)
+     */
+    public void setRequestProperty(String key, String value) {
+        if (connected)
+            throw new IllegalStateException("Already connected");
+        if (key == null)
+            throw new NullPointerException ("key is null");
+
+        if (requests == null)
+            requests = new MessageHeader();
+
+        requests.set(key, value);
+    }
+
+    /**
+     * Adds a general request property specified by a
+     * key-value pair.  This method will not overwrite
+     * existing values associated with the same key.
+     *
+     * @param   key     the keyword by which the request is known
+     *                  (e.g., "{@code Accept}").
+     * @param   value  the value associated with it.
+     * @throws IllegalStateException if already connected
+     * @throws NullPointerException if key is null
+     * @see #getRequestProperties()
+     * @since 1.4
+     */
+    public void addRequestProperty(String key, String value) {
+        if (connected)
+            throw new IllegalStateException("Already connected");
+        if (key == null)
+            throw new NullPointerException ("key is null");
+
+        if (requests == null)
+            requests = new MessageHeader();
+
+        requests.add(key, value);
+    }
+
+
+    /**
+     * Returns the value of the named general request property for this
+     * connection.
+     *
+     * @param key the keyword by which the request is known (e.g., "Accept").
+     * @return  the value of the named general request property for this
+     *           connection. If key is null, then null is returned.
+     * @throws IllegalStateException if already connected
+     * @see #setRequestProperty(java.lang.String, java.lang.String)
+     */
+    public String getRequestProperty(String key) {
+        if (connected)
+            throw new IllegalStateException("Already connected");
+
+        if (requests == null)
+            return null;
+
+        return requests.findValue(key);
+    }
+
+    /**
+     * Returns an unmodifiable Map of general request
+     * properties for this connection. The Map keys
+     * are Strings that represent the request-header
+     * field names. Each Map value is a unmodifiable List
+     * of Strings that represents the corresponding
+     * field values.
+     *
+     * @return  a Map of the general request properties for this connection.
+     * @throws IllegalStateException if already connected
+     * @since 1.4
+     */
+    public Map<String,List<String>> getRequestProperties() {
+        if (connected)
+            throw new IllegalStateException("Already connected");
+
+        if (requests == null)
+            return Collections.emptyMap();
+
+        return requests.getHeaders(null);
+    }
+
+    /**
+     * Sets the default value of a general request property. When a
+     * {@code URLConnection} is created, it is initialized with
+     * these properties.
+     *
+     * @param   key     the keyword by which the request is known
+     *                  (e.g., "{@code Accept}").
+     * @param   value   the value associated with the key.
+     *
+     * @see java.net.URLConnection#setRequestProperty(java.lang.String,java.lang.String)
+     *
+     * @deprecated The instance specific setRequestProperty method
+     * should be used after an appropriate instance of URLConnection
+     * is obtained. Invoking this method will have no effect.
+     *
+     * @see #getDefaultRequestProperty(java.lang.String)
+     */
+    @Deprecated
+    public static void setDefaultRequestProperty(String key, String value) {
+    }
+
+    /**
+     * Returns the value of the default request property. Default request
+     * properties are set for every connection.
+     *
+     * @param key the keyword by which the request is known (e.g., "Accept").
+     * @return  the value of the default request property
+     * for the specified key.
+     *
+     * @see java.net.URLConnection#getRequestProperty(java.lang.String)
+     *
+     * @deprecated The instance specific getRequestProperty method
+     * should be used after an appropriate instance of URLConnection
+     * is obtained.
+     *
+     * @see #setDefaultRequestProperty(java.lang.String, java.lang.String)
+     */
+    @Deprecated
+    public static String getDefaultRequestProperty(String key) {
+        return null;
+    }
+
+    /**
+     * The ContentHandler factory.
+     */
+    static ContentHandlerFactory factory;
+
+    /**
+     * Sets the {@code ContentHandlerFactory} of an
+     * application. It can be called at most once by an application.
+     * <p>
+     * The {@code ContentHandlerFactory} instance is used to
+     * construct a content handler from a content type
+     * <p>
+     * If there is a security manager, this method first calls
+     * the security manager's {@code checkSetFactory} method
+     * to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param      fac   the desired factory.
+     * @exception  Error  if the factory has already been defined.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkSetFactory} method doesn't allow the operation.
+     * @see        java.net.ContentHandlerFactory
+     * @see        java.net.URLConnection#getContent()
+     * @see        SecurityManager#checkSetFactory
+     */
+    public static synchronized void setContentHandlerFactory(ContentHandlerFactory fac) {
+        if (factory != null) {
+            throw new Error("factory already defined");
+        }
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkSetFactory();
+        }
+        factory = fac;
+    }
+
+    private static Hashtable<String, ContentHandler> handlers = new Hashtable<>();
+
+    /**
+     * Gets the Content Handler appropriate for this connection.
+     */
+    synchronized ContentHandler getContentHandler()
+        throws IOException
+    {
+        String contentType = stripOffParameters(getContentType());
+        ContentHandler handler = null;
+        // BEGIN Android-changed: App Compat. Android guesses content type from name and stream.
+        if (contentType == null) {
+            if ((contentType = guessContentTypeFromName(url.getFile())) == null) {
+                contentType = guessContentTypeFromStream(getInputStream());
+            }
+        }
+
+        if (contentType == null) {
+            return UnknownContentHandler.INSTANCE;
+        }
+        // END Android-changed: App Compat. Android guesses content type from name and stream.
+        try {
+            handler = handlers.get(contentType);
+            if (handler != null)
+                return handler;
+        } catch(Exception e) {
+        }
+
+        if (factory != null)
+            handler = factory.createContentHandler(contentType);
+        if (handler == null) {
+            try {
+                handler = lookupContentHandlerClassFor(contentType);
+            } catch(Exception e) {
+                e.printStackTrace();
+                handler = UnknownContentHandler.INSTANCE;
+            }
+            handlers.put(contentType, handler);
+        }
+        return handler;
+    }
+
+    /*
+     * Media types are in the format: type/subtype*(; parameter).
+     * For looking up the content handler, we should ignore those
+     * parameters.
+     */
+    private String stripOffParameters(String contentType)
+    {
+        if (contentType == null)
+            return null;
+        int index = contentType.indexOf(';');
+
+        if (index > 0)
+            return contentType.substring(0, index);
+        else
+            return contentType;
+    }
+
+    private static final String contentClassPrefix = "sun.net.www.content";
+    private static final String contentPathProp = "java.content.handler.pkgs";
+
+    /**
+     * Looks for a content handler in a user-defineable set of places.
+     * By default it looks in sun.net.www.content, but users can define a
+     * vertical-bar delimited set of class prefixes to search through in
+     * addition by defining the java.content.handler.pkgs property.
+     * The class name must be of the form:
+     * <pre>
+     *     {package-prefix}.{major}.{minor}
+     * e.g.
+     *     YoyoDyne.experimental.text.plain
+     * </pre>
+     */
+    private ContentHandler lookupContentHandlerClassFor(String contentType)
+        throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+        String contentHandlerClassName = typeToPackageName(contentType);
+
+        String contentHandlerPkgPrefixes =getContentHandlerPkgPrefixes();
+
+        StringTokenizer packagePrefixIter =
+            new StringTokenizer(contentHandlerPkgPrefixes, "|");
+
+        while (packagePrefixIter.hasMoreTokens()) {
+            String packagePrefix = packagePrefixIter.nextToken().trim();
+
+            try {
+                String clsName = packagePrefix + "." + contentHandlerClassName;
+                Class<?> cls = null;
+                try {
+                    cls = Class.forName(clsName);
+                } catch (ClassNotFoundException e) {
+                    ClassLoader cl = ClassLoader.getSystemClassLoader();
+                    if (cl != null) {
+                        cls = cl.loadClass(clsName);
+                    }
+                }
+                if (cls != null) {
+                    ContentHandler handler =
+                        (ContentHandler)cls.newInstance();
+                    return handler;
+                }
+            } catch(Exception e) {
+            }
+        }
+
+        return UnknownContentHandler.INSTANCE;
+    }
+
+    /**
+     * Utility function to map a MIME content type into an equivalent
+     * pair of class name components.  For example: "text/html" would
+     * be returned as "text.html"
+     */
+    private String typeToPackageName(String contentType) {
+        // make sure we canonicalize the class name: all lower case
+        contentType = contentType.toLowerCase();
+        int len = contentType.length();
+        char nm[] = new char[len];
+        contentType.getChars(0, len, nm, 0);
+        for (int i = 0; i < len; i++) {
+            char c = nm[i];
+            if (c == '/') {
+                nm[i] = '.';
+            } else if (!('A' <= c && c <= 'Z' ||
+                       'a' <= c && c <= 'z' ||
+                       '0' <= c && c <= '9')) {
+                nm[i] = '_';
+            }
+        }
+        return new String(nm);
+    }
+
+
+    /**
+     * Returns a vertical bar separated list of package prefixes for potential
+     * content handlers.  Tries to get the java.content.handler.pkgs property
+     * to use as a set of package prefixes to search.  Whether or not
+     * that property has been defined, the sun.net.www.content is always
+     * the last one on the returned package list.
+     */
+    private String getContentHandlerPkgPrefixes() {
+        String packagePrefixList = AccessController.doPrivileged(
+            new sun.security.action.GetPropertyAction(contentPathProp, ""));
+
+        if (packagePrefixList != "") {
+            packagePrefixList += "|";
+        }
+
+        return packagePrefixList + contentClassPrefix;
+    }
+
+    /**
+     * Tries to determine the content type of an object, based
+     * on the specified "file" component of a URL.
+     * This is a convenience method that can be used by
+     * subclasses that override the {@code getContentType} method.
+     *
+     * @param   fname   a filename.
+     * @return  a guess as to what the content type of the object is,
+     *          based upon its file name.
+     * @see     java.net.URLConnection#getContentType()
+     */
+    public static String guessContentTypeFromName(String fname) {
+        return getFileNameMap().getContentTypeFor(fname);
+    }
+
+    /**
+     * Tries to determine the type of an input stream based on the
+     * characters at the beginning of the input stream. This method can
+     * be used by subclasses that override the
+     * {@code getContentType} method.
+     * <p>
+     * Ideally, this routine would not be needed. But many
+     * {@code http} servers return the incorrect content type; in
+     * addition, there are many nonstandard extensions. Direct inspection
+     * of the bytes to determine the content type is often more accurate
+     * than believing the content type claimed by the {@code http} server.
+     *
+     * @param      is   an input stream that supports marks.
+     * @return     a guess at the content type, or {@code null} if none
+     *             can be determined.
+     * @exception  IOException  if an I/O error occurs while reading the
+     *               input stream.
+     * @see        java.io.InputStream#mark(int)
+     * @see        java.io.InputStream#markSupported()
+     * @see        java.net.URLConnection#getContentType()
+     */
+    static public String guessContentTypeFromStream(InputStream is)
+                        throws IOException {
+        // If we can't read ahead safely, just give up on guessing
+        if (!is.markSupported())
+            return null;
+
+        is.mark(16);
+        int c1 = is.read();
+        int c2 = is.read();
+        int c3 = is.read();
+        int c4 = is.read();
+        int c5 = is.read();
+        int c6 = is.read();
+        int c7 = is.read();
+        int c8 = is.read();
+        int c9 = is.read();
+        int c10 = is.read();
+        int c11 = is.read();
+        int c12 = is.read();
+        int c13 = is.read();
+        int c14 = is.read();
+        int c15 = is.read();
+        int c16 = is.read();
+        is.reset();
+
+        if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE) {
+            return "application/java-vm";
+        }
+
+        if (c1 == 0xAC && c2 == 0xED) {
+            // next two bytes are version number, currently 0x00 0x05
+            return "application/x-java-serialized-object";
+        }
+
+        if (c1 == '<') {
+            if (c2 == '!'
+                || ((c2 == 'h' && (c3 == 't' && c4 == 'm' && c5 == 'l' ||
+                                   c3 == 'e' && c4 == 'a' && c5 == 'd') ||
+                (c2 == 'b' && c3 == 'o' && c4 == 'd' && c5 == 'y'))) ||
+                ((c2 == 'H' && (c3 == 'T' && c4 == 'M' && c5 == 'L' ||
+                                c3 == 'E' && c4 == 'A' && c5 == 'D') ||
+                (c2 == 'B' && c3 == 'O' && c4 == 'D' && c5 == 'Y')))) {
+                return "text/html";
+            }
+
+            if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l' && c6 == ' ') {
+                return "application/xml";
+            }
+        }
+
+        // big and little (identical) endian UTF-8 encodings, with BOM
+        if (c1 == 0xef &&  c2 == 0xbb &&  c3 == 0xbf) {
+            if (c4 == '<' &&  c5 == '?' &&  c6 == 'x') {
+                return "application/xml";
+            }
+        }
+
+        // big and little endian UTF-16 encodings, with byte order mark
+        if (c1 == 0xfe && c2 == 0xff) {
+            if (c3 == 0 && c4 == '<' && c5 == 0 && c6 == '?' &&
+                c7 == 0 && c8 == 'x') {
+                return "application/xml";
+            }
+        }
+
+        if (c1 == 0xff && c2 == 0xfe) {
+            if (c3 == '<' && c4 == 0 && c5 == '?' && c6 == 0 &&
+                c7 == 'x' && c8 == 0) {
+                return "application/xml";
+            }
+        }
+
+        // big and little endian UTF-32 encodings, with BOM
+        if (c1 == 0x00 &&  c2 == 0x00 &&  c3 == 0xfe &&  c4 == 0xff) {
+            if (c5  == 0 && c6  == 0 && c7  == 0 && c8  == '<' &&
+                c9  == 0 && c10 == 0 && c11 == 0 && c12 == '?' &&
+                c13 == 0 && c14 == 0 && c15 == 0 && c16 == 'x') {
+                return "application/xml";
+            }
+        }
+
+        if (c1 == 0xff &&  c2 == 0xfe &&  c3 == 0x00 &&  c4 == 0x00) {
+            if (c5  == '<' && c6  == 0 && c7  == 0 && c8  == 0 &&
+                c9  == '?' && c10 == 0 && c11 == 0 && c12 == 0 &&
+                c13 == 'x' && c14 == 0 && c15 == 0 && c16 == 0) {
+                return "application/xml";
+            }
+        }
+
+        if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') {
+            return "image/gif";
+        }
+
+        if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') {
+            return "image/x-bitmap";
+        }
+
+        if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' &&
+                        c5 == 'M' && c6 == '2') {
+            return "image/x-pixmap";
+        }
+
+        if (c1 == 137 && c2 == 80 && c3 == 78 &&
+                c4 == 71 && c5 == 13 && c6 == 10 &&
+                c7 == 26 && c8 == 10) {
+            return "image/png";
+        }
+
+        if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF) {
+            if (c4 == 0xE0 || c4 == 0xEE) {
+                return "image/jpeg";
+            }
+
+            /**
+             * File format used by digital cameras to store images.
+             * Exif Format can be read by any application supporting
+             * JPEG. Exif Spec can be found at:
+             * http://www.pima.net/standards/it10/PIMA15740/Exif_2-1.PDF
+             */
+            if ((c4 == 0xE1) &&
+                (c7 == 'E' && c8 == 'x' && c9 == 'i' && c10 =='f' &&
+                 c11 == 0)) {
+                return "image/jpeg";
+            }
+        }
+
+        if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0 &&
+            c5 == 0xA1 && c6 == 0xB1 && c7 == 0x1A && c8 == 0xE1) {
+
+            /* Above is signature of Microsoft Structured Storage.
+             * Below this, could have tests for various SS entities.
+             * For now, just test for FlashPix.
+             */
+            if (checkfpx(is)) {
+                return "image/vnd.fpx";
+            }
+        }
+
+        if (c1 == 0x2E && c2 == 0x73 && c3 == 0x6E && c4 == 0x64) {
+            return "audio/basic";  // .au format, big endian
+        }
+
+        if (c1 == 0x64 && c2 == 0x6E && c3 == 0x73 && c4 == 0x2E) {
+            return "audio/basic";  // .au format, little endian
+        }
+
+        if (c1 == 'R' && c2 == 'I' && c3 == 'F' && c4 == 'F') {
+            /* I don't know if this is official but evidence
+             * suggests that .wav files start with "RIFF" - brown
+             */
+            return "audio/x-wav";
+        }
+        return null;
+    }
+
+    /**
+     * Check for FlashPix image data in InputStream is.  Return true if
+     * the stream has FlashPix data, false otherwise.  Before calling this
+     * method, the stream should have already been checked to be sure it
+     * contains Microsoft Structured Storage data.
+     */
+    static private boolean checkfpx(InputStream is) throws IOException {
+
+        /* Test for FlashPix image data in Microsoft Structured Storage format.
+         * In general, should do this with calls to an SS implementation.
+         * Lacking that, need to dig via offsets to get to the FlashPix
+         * ClassID.  Details:
+         *
+         * Offset to Fpx ClsID from beginning of stream should be:
+         *
+         * FpxClsidOffset = rootEntryOffset + clsidOffset
+         *
+         * where: clsidOffset = 0x50.
+         *        rootEntryOffset = headerSize + sectorSize*sectDirStart
+         *                          + 128*rootEntryDirectory
+         *
+         *        where:  headerSize = 0x200 (always)
+         *                sectorSize = 2 raised to power of uSectorShift,
+         *                             which is found in the header at
+         *                             offset 0x1E.
+         *                sectDirStart = found in the header at offset 0x30.
+         *                rootEntryDirectory = in general, should search for
+         *                                     directory labelled as root.
+         *                                     We will assume value of 0 (i.e.,
+         *                                     rootEntry is in first directory)
+         */
+
+        // Mark the stream so we can reset it. 0x100 is enough for the first
+        // few reads, but the mark will have to be reset and set again once
+        // the offset to the root directory entry is computed. That offset
+        // can be very large and isn't know until the stream has been read from
+        is.mark(0x100);
+
+        // Get the byte ordering located at 0x1E. 0xFE is Intel,
+        // 0xFF is other
+        long toSkip = (long)0x1C;
+        long posn;
+
+        if ((posn = skipForward(is, toSkip)) < toSkip) {
+          is.reset();
+          return false;
+        }
+
+        int c[] = new int[16];
+        if (readBytes(c, 2, is) < 0) {
+            is.reset();
+            return false;
+        }
+
+        int byteOrder = c[0];
+
+        posn+=2;
+        int uSectorShift;
+        if (readBytes(c, 2, is) < 0) {
+            is.reset();
+            return false;
+        }
+
+        if(byteOrder == 0xFE) {
+            uSectorShift = c[0];
+            uSectorShift += c[1] << 8;
+        }
+        else {
+            uSectorShift = c[0] << 8;
+            uSectorShift += c[1];
+        }
+
+        posn += 2;
+        toSkip = (long)0x30 - posn;
+        long skipped = 0;
+        if ((skipped = skipForward(is, toSkip)) < toSkip) {
+          is.reset();
+          return false;
+        }
+        posn += skipped;
+
+        if (readBytes(c, 4, is) < 0) {
+            is.reset();
+            return false;
+        }
+
+        int sectDirStart;
+        if(byteOrder == 0xFE) {
+            sectDirStart = c[0];
+            sectDirStart += c[1] << 8;
+            sectDirStart += c[2] << 16;
+            sectDirStart += c[3] << 24;
+        } else {
+            sectDirStart =  c[0] << 24;
+            sectDirStart += c[1] << 16;
+            sectDirStart += c[2] << 8;
+            sectDirStart += c[3];
+        }
+        posn += 4;
+        is.reset(); // Reset back to the beginning
+
+        toSkip = 0x200L + (long)(1<<uSectorShift)*sectDirStart + 0x50L;
+
+        // Sanity check!
+        if (toSkip < 0) {
+            return false;
+        }
+
+        /*
+         * How far can we skip? Is there any performance problem here?
+         * This skip can be fairly long, at least 0x4c650 in at least
+         * one case. Have to assume that the skip will fit in an int.
+         * Leave room to read whole root dir
+         */
+        is.mark((int)toSkip+0x30);
+
+        if ((skipForward(is, toSkip)) < toSkip) {
+            is.reset();
+            return false;
+        }
+
+        /* should be at beginning of ClassID, which is as follows
+         * (in Intel byte order):
+         *    00 67 61 56 54 C1 CE 11 85 53 00 AA 00 A1 F9 5B
+         *
+         * This is stored from Windows as long,short,short,char[8]
+         * so for byte order changes, the order only changes for
+         * the first 8 bytes in the ClassID.
+         *
+         * Test against this, ignoring second byte (Intel) since
+         * this could change depending on part of Fpx file we have.
+         */
+
+        if (readBytes(c, 16, is) < 0) {
+            is.reset();
+            return false;
+        }
+
+        // intel byte order
+        if (byteOrder == 0xFE &&
+            c[0] == 0x00 && c[2] == 0x61 && c[3] == 0x56 &&
+            c[4] == 0x54 && c[5] == 0xC1 && c[6] == 0xCE &&
+            c[7] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&
+            c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&
+            c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {
+            is.reset();
+            return true;
+        }
+
+        // non-intel byte order
+        else if (c[3] == 0x00 && c[1] == 0x61 && c[0] == 0x56 &&
+            c[5] == 0x54 && c[4] == 0xC1 && c[7] == 0xCE &&
+            c[6] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&
+            c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&
+            c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {
+            is.reset();
+            return true;
+        }
+        is.reset();
+        return false;
+    }
+
+    /**
+     * Tries to read the specified number of bytes from the stream
+     * Returns -1, If EOF is reached before len bytes are read, returns 0
+     * otherwise
+     */
+    static private int readBytes(int c[], int len, InputStream is)
+                throws IOException {
+
+        byte buf[] = new byte[len];
+        if (is.read(buf, 0, len) < len) {
+            return -1;
+        }
+
+        // fill the passed in int array
+        for (int i = 0; i < len; i++) {
+             c[i] = buf[i] & 0xff;
+        }
+        return 0;
+    }
+
+
+    /**
+     * Skips through the specified number of bytes from the stream
+     * until either EOF is reached, or the specified
+     * number of bytes have been skipped
+     */
+    static private long skipForward(InputStream is, long toSkip)
+                throws IOException {
+
+        long eachSkip = 0;
+        long skipped = 0;
+
+        while (skipped != toSkip) {
+            eachSkip = is.skip(toSkip - skipped);
+
+            // check if EOF is reached
+            if (eachSkip <= 0) {
+                if (is.read() == -1) {
+                    return skipped ;
+                } else {
+                    skipped++;
+                }
+            }
+            skipped += eachSkip;
+        }
+        return skipped;
+    }
+
+}
+
+
+class UnknownContentHandler extends ContentHandler {
+    static final ContentHandler INSTANCE = new UnknownContentHandler();
+
+    public Object getContent(URLConnection uc) throws IOException {
+        return uc.getInputStream();
+    }
+}
diff --git a/java/net/URLDecoder.java b/java/net/URLDecoder.java
new file mode 100644
index 0000000..8b14eb8
--- /dev/null
+++ b/java/net/URLDecoder.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.*;
+
+/**
+ * Utility class for HTML form decoding. This class contains static methods
+ * for decoding a String from the <CODE>application/x-www-form-urlencoded</CODE>
+ * MIME format.
+ * <p>
+ * The conversion process is the reverse of that used by the URLEncoder class. It is assumed
+ * that all characters in the encoded string are one of the following:
+ * &quot;{@code a}&quot; through &quot;{@code z}&quot;,
+ * &quot;{@code A}&quot; through &quot;{@code Z}&quot;,
+ * &quot;{@code 0}&quot; through &quot;{@code 9}&quot;, and
+ * &quot;{@code -}&quot;, &quot;{@code _}&quot;,
+ * &quot;{@code .}&quot;, and &quot;{@code *}&quot;. The
+ * character &quot;{@code %}&quot; is allowed but is interpreted
+ * as the start of a special escaped sequence.
+ * <p>
+ * The following rules are applied in the conversion:
+ *
+ * <ul>
+ * <li>The alphanumeric characters &quot;{@code a}&quot; through
+ *     &quot;{@code z}&quot;, &quot;{@code A}&quot; through
+ *     &quot;{@code Z}&quot; and &quot;{@code 0}&quot;
+ *     through &quot;{@code 9}&quot; remain the same.
+ * <li>The special characters &quot;{@code .}&quot;,
+ *     &quot;{@code -}&quot;, &quot;{@code *}&quot;, and
+ *     &quot;{@code _}&quot; remain the same.
+ * <li>The plus sign &quot;{@code +}&quot; is converted into a
+ *     space character &quot; &nbsp; &quot; .
+ * <li>A sequence of the form "<i>{@code %xy}</i>" will be
+ *     treated as representing a byte where <i>xy</i> is the two-digit
+ *     hexadecimal representation of the 8 bits. Then, all substrings
+ *     that contain one or more of these byte sequences consecutively
+ *     will be replaced by the character(s) whose encoding would result
+ *     in those consecutive bytes.
+ *     The encoding scheme used to decode these characters may be specified,
+ *     or if unspecified, the default encoding of the platform will be used.
+ * </ul>
+ * <p>
+ * There are two possible ways in which this decoder could deal with
+ * illegal strings.  It could either leave illegal characters alone or
+ * it could throw an {@link java.lang.IllegalArgumentException}.
+ * Which approach the decoder takes is left to the
+ * implementation.
+ *
+ * @author  Mark Chamness
+ * @author  Michael McCloskey
+ * @since   1.2
+ */
+
+public class URLDecoder {
+
+    // The platform default encoding
+    static String dfltEncName = URLEncoder.dfltEncName;
+
+    /**
+     * Decodes a {@code x-www-form-urlencoded} string.
+     * The platform's default encoding is used to determine what characters
+     * are represented by any consecutive sequences of the form
+     * "<i>{@code %xy}</i>".
+     * @param s the {@code String} to decode
+     * @deprecated The resulting string may vary depending on the platform's
+     *          default encoding. Instead, use the decode(String,String) method
+     *          to specify the encoding.
+     * @return the newly decoded {@code String}
+     */
+    @Deprecated
+    public static String decode(String s) {
+
+        String str = null;
+
+        try {
+            str = decode(s, dfltEncName);
+        } catch (UnsupportedEncodingException e) {
+            // The system should always have the platform default
+        }
+
+        return str;
+    }
+
+    /**
+     * Decodes a {@code application/x-www-form-urlencoded} string using a specific
+     * encoding scheme.
+     * The supplied encoding is used to determine
+     * what characters are represented by any consecutive sequences of the
+     * form "<i>{@code %xy}</i>".
+     * <p>
+     * <em><strong>Note:</strong> The <a href=
+     * "http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars">
+     * World Wide Web Consortium Recommendation</a> states that
+     * UTF-8 should be used. Not doing so may introduce
+     * incompatibilities.</em>
+     *
+     * @param s the {@code String} to decode
+     * @param enc   The name of a supported
+     *    <a href="../lang/package-summary.html#charenc">character
+     *    encoding</a>.
+     * @return the newly decoded {@code String}
+     * @exception  UnsupportedEncodingException
+     *             If character encoding needs to be consulted, but
+     *             named character encoding is not supported
+     * @see URLEncoder#encode(java.lang.String, java.lang.String)
+     * @since 1.4
+     */
+    public static String decode(String s, String enc)
+        throws UnsupportedEncodingException{
+
+        boolean needToChange = false;
+        int numChars = s.length();
+        StringBuffer sb = new StringBuffer(numChars > 500 ? numChars / 2 : numChars);
+        int i = 0;
+
+        if (enc.length() == 0) {
+            throw new UnsupportedEncodingException ("URLDecoder: empty string enc parameter");
+        }
+
+        char c;
+        byte[] bytes = null;
+        while (i < numChars) {
+            c = s.charAt(i);
+            switch (c) {
+            case '+':
+                sb.append(' ');
+                i++;
+                needToChange = true;
+                break;
+            case '%':
+                /*
+                 * Starting with this instance of %, process all
+                 * consecutive substrings of the form %xy. Each
+                 * substring %xy will yield a byte. Convert all
+                 * consecutive  bytes obtained this way to whatever
+                 * character(s) they represent in the provided
+                 * encoding.
+                 */
+
+                try {
+
+                    // (numChars-i)/3 is an upper bound for the number
+                    // of remaining bytes
+                    if (bytes == null)
+                        bytes = new byte[(numChars-i)/3];
+                    int pos = 0;
+
+                    while ( ((i+2) < numChars) &&
+                            (c=='%')) {
+                        // BEGIN Android-changed: App compat. Forbid non-hex chars after '%'.
+                        if (!isValidHexChar(s.charAt(i+1)) || !isValidHexChar(s.charAt(i+2))) {
+                            throw new IllegalArgumentException("URLDecoder: Illegal hex characters in escape (%) pattern : "
+                                    + s.substring(i, i + 3));
+                        }
+                        // END Android-changed: App compat. Forbid non-hex chars after '%'.
+                        int v = Integer.parseInt(s.substring(i+1,i+3),16);
+                        if (v < 0)
+                            // Android-changed: Improve error message by printing the string value.
+                            throw new IllegalArgumentException("URLDecoder: Illegal hex characters in escape (%) pattern - negative value : "
+                                    + s.substring(i, i + 3));
+                        bytes[pos++] = (byte) v;
+                        i+= 3;
+                        if (i < numChars)
+                            c = s.charAt(i);
+                    }
+
+                    // A trailing, incomplete byte encoding such as
+                    // "%x" will cause an exception to be thrown
+
+                    if ((i < numChars) && (c=='%'))
+                        throw new IllegalArgumentException(
+                         "URLDecoder: Incomplete trailing escape (%) pattern");
+
+                    sb.append(new String(bytes, 0, pos, enc));
+                } catch (NumberFormatException e) {
+                    throw new IllegalArgumentException(
+                    "URLDecoder: Illegal hex characters in escape (%) pattern - "
+                    + e.getMessage());
+                }
+                needToChange = true;
+                break;
+            default:
+                sb.append(c);
+                i++;
+                break;
+            }
+        }
+
+        return (needToChange? sb.toString() : s);
+    }
+
+    // BEGIN Android-added: App compat. Forbid non-hex chars after '%'.
+    private static boolean isValidHexChar(char c) {
+        return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
+    }
+    // END Android-added: App compat. Forbid non-hex chars after '%'.
+}
diff --git a/java/net/URLEncoder.java b/java/net/URLEncoder.java
new file mode 100644
index 0000000..86377b7
--- /dev/null
+++ b/java/net/URLEncoder.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.ByteArrayOutputStream;
+import java.io.BufferedWriter;
+import java.io.OutputStreamWriter;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.io.CharArrayWriter;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException ;
+import java.util.BitSet;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import sun.security.action.GetBooleanAction;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * Utility class for HTML form encoding. This class contains static methods
+ * for converting a String to the <CODE>application/x-www-form-urlencoded</CODE> MIME
+ * format. For more information about HTML form encoding, consult the HTML
+ * <A HREF="http://www.w3.org/TR/html4/">specification</A>.
+ *
+ * <p>
+ * When encoding a String, the following rules apply:
+ *
+ * <ul>
+ * <li>The alphanumeric characters &quot;{@code a}&quot; through
+ *     &quot;{@code z}&quot;, &quot;{@code A}&quot; through
+ *     &quot;{@code Z}&quot; and &quot;{@code 0}&quot;
+ *     through &quot;{@code 9}&quot; remain the same.
+ * <li>The special characters &quot;{@code .}&quot;,
+ *     &quot;{@code -}&quot;, &quot;{@code *}&quot;, and
+ *     &quot;{@code _}&quot; remain the same.
+ * <li>The space character &quot; &nbsp; &quot; is
+ *     converted into a plus sign &quot;{@code +}&quot;.
+ * <li>All other characters are unsafe and are first converted into
+ *     one or more bytes using some encoding scheme. Then each byte is
+ *     represented by the 3-character string
+ *     &quot;<i>{@code %xy}</i>&quot;, where <i>xy</i> is the
+ *     two-digit hexadecimal representation of the byte.
+ *     The recommended encoding scheme to use is UTF-8. However,
+ *     for compatibility reasons, if an encoding is not specified,
+ *     then the default encoding of the platform is used.
+ * </ul>
+ *
+ * <p>
+ * For example using UTF-8 as the encoding scheme the string &quot;The
+ * string &#252;@foo-bar&quot; would get converted to
+ * &quot;The+string+%C3%BC%40foo-bar&quot; because in UTF-8 the character
+ * &#252; is encoded as two bytes C3 (hex) and BC (hex), and the
+ * character @ is encoded as one byte 40 (hex).
+ *
+ * @author  Herb Jellinek
+ * @since   JDK1.0
+ */
+public class URLEncoder {
+    static BitSet dontNeedEncoding;
+    static final int caseDiff = ('a' - 'A');
+    static String dfltEncName = null;
+
+    static {
+
+        /* The list of characters that are not encoded has been
+         * determined as follows:
+         *
+         * RFC 2396 states:
+         * -----
+         * Data characters that are allowed in a URI but do not have a
+         * reserved purpose are called unreserved.  These include upper
+         * and lower case letters, decimal digits, and a limited set of
+         * punctuation marks and symbols.
+         *
+         * unreserved  = alphanum | mark
+         *
+         * mark        = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
+         *
+         * Unreserved characters can be escaped without changing the
+         * semantics of the URI, but this should not be done unless the
+         * URI is being used in a context that does not allow the
+         * unescaped character to appear.
+         * -----
+         *
+         * It appears that both Netscape and Internet Explorer escape
+         * all special characters from this list with the exception
+         * of "-", "_", ".", "*". While it is not clear why they are
+         * escaping the other characters, perhaps it is safest to
+         * assume that there might be contexts in which the others
+         * are unsafe if not escaped. Therefore, we will use the same
+         * list. It is also noteworthy that this is consistent with
+         * O'Reilly's "HTML: The Definitive Guide" (page 164).
+         *
+         * As a last note, Intenet Explorer does not encode the "@"
+         * character which is clearly not unreserved according to the
+         * RFC. We are being consistent with the RFC in this matter,
+         * as is Netscape.
+         *
+         */
+
+        dontNeedEncoding = new BitSet(256);
+        int i;
+        for (i = 'a'; i <= 'z'; i++) {
+            dontNeedEncoding.set(i);
+        }
+        for (i = 'A'; i <= 'Z'; i++) {
+            dontNeedEncoding.set(i);
+        }
+        for (i = '0'; i <= '9'; i++) {
+            dontNeedEncoding.set(i);
+        }
+        dontNeedEncoding.set(' '); /* encoding a space to a + is done
+                                    * in the encode() method */
+        dontNeedEncoding.set('-');
+        dontNeedEncoding.set('_');
+        dontNeedEncoding.set('.');
+        dontNeedEncoding.set('*');
+
+        dfltEncName = AccessController.doPrivileged(
+            new GetPropertyAction("file.encoding")
+        );
+    }
+
+    /**
+     * You can't call the constructor.
+     */
+    private URLEncoder() { }
+
+    /**
+     * Translates a string into {@code x-www-form-urlencoded}
+     * format. This method uses the platform's default encoding
+     * as the encoding scheme to obtain the bytes for unsafe characters.
+     *
+     * @param   s   {@code String} to be translated.
+     * @deprecated The resulting string may vary depending on the platform's
+     *             default encoding. Instead, use the encode(String,String)
+     *             method to specify the encoding.
+     * @return  the translated {@code String}.
+     */
+    @Deprecated
+    public static String encode(String s) {
+
+        String str = null;
+
+        try {
+            str = encode(s, dfltEncName);
+        } catch (UnsupportedEncodingException e) {
+            // The system should always have the platform default
+        }
+
+        return str;
+    }
+
+    /**
+     * Translates a string into {@code application/x-www-form-urlencoded}
+     * format using a specific encoding scheme. This method uses the
+     * supplied encoding scheme to obtain the bytes for unsafe
+     * characters.
+     * <p>
+     * <em><strong>Note:</strong> The <a href=
+     * "http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars">
+     * World Wide Web Consortium Recommendation</a> states that
+     * UTF-8 should be used. Not doing so may introduce
+     * incompatibilities.</em>
+     *
+     * @param   s   {@code String} to be translated.
+     * @param   enc   The name of a supported
+     *    <a href="../lang/package-summary.html#charenc">character
+     *    encoding</a>.
+     * @return  the translated {@code String}.
+     * @exception  UnsupportedEncodingException
+     *             If the named encoding is not supported
+     * @see URLDecoder#decode(java.lang.String, java.lang.String)
+     * @since 1.4
+     */
+    public static String encode(String s, String enc)
+        throws UnsupportedEncodingException {
+
+        boolean needToChange = false;
+        StringBuffer out = new StringBuffer(s.length());
+        Charset charset;
+        CharArrayWriter charArrayWriter = new CharArrayWriter();
+
+        if (enc == null)
+            throw new NullPointerException("charsetName");
+
+        try {
+            charset = Charset.forName(enc);
+        } catch (IllegalCharsetNameException e) {
+            throw new UnsupportedEncodingException(enc);
+        } catch (UnsupportedCharsetException e) {
+            throw new UnsupportedEncodingException(enc);
+        }
+
+        for (int i = 0; i < s.length();) {
+            int c = (int) s.charAt(i);
+            //System.out.println("Examining character: " + c);
+            if (dontNeedEncoding.get(c)) {
+                if (c == ' ') {
+                    c = '+';
+                    needToChange = true;
+                }
+                //System.out.println("Storing: " + c);
+                out.append((char)c);
+                i++;
+            } else {
+                // convert to external encoding before hex conversion
+                do {
+                    charArrayWriter.write(c);
+                    /*
+                     * If this character represents the start of a Unicode
+                     * surrogate pair, then pass in two characters. It's not
+                     * clear what should be done if a bytes reserved in the
+                     * surrogate pairs range occurs outside of a legal
+                     * surrogate pair. For now, just treat it as if it were
+                     * any other character.
+                     */
+                    if (c >= 0xD800 && c <= 0xDBFF) {
+                        /*
+                          System.out.println(Integer.toHexString(c)
+                          + " is high surrogate");
+                        */
+                        if ( (i+1) < s.length()) {
+                            int d = (int) s.charAt(i+1);
+                            /*
+                              System.out.println("\tExamining "
+                              + Integer.toHexString(d));
+                            */
+                            if (d >= 0xDC00 && d <= 0xDFFF) {
+                                /*
+                                  System.out.println("\t"
+                                  + Integer.toHexString(d)
+                                  + " is low surrogate");
+                                */
+                                charArrayWriter.write(d);
+                                i++;
+                            }
+                        }
+                    }
+                    i++;
+                } while (i < s.length() && !dontNeedEncoding.get((c = (int) s.charAt(i))));
+
+                charArrayWriter.flush();
+                String str = new String(charArrayWriter.toCharArray());
+                byte[] ba = str.getBytes(charset);
+                for (int j = 0; j < ba.length; j++) {
+                    out.append('%');
+                    char ch = Character.forDigit((ba[j] >> 4) & 0xF, 16);
+                    // converting to use uppercase letter as part of
+                    // the hex value if ch is a letter.
+                    if (Character.isLetter(ch)) {
+                        ch -= caseDiff;
+                    }
+                    out.append(ch);
+                    ch = Character.forDigit(ba[j] & 0xF, 16);
+                    if (Character.isLetter(ch)) {
+                        ch -= caseDiff;
+                    }
+                    out.append(ch);
+                }
+                charArrayWriter.reset();
+                needToChange = true;
+            }
+        }
+
+        return (needToChange? out.toString() : s);
+    }
+}
diff --git a/java/net/URLStreamHandler.java b/java/net/URLStreamHandler.java
new file mode 100644
index 0000000..dffc6d5
--- /dev/null
+++ b/java/net/URLStreamHandler.java
@@ -0,0 +1,626 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.util.Objects;
+
+import sun.net.util.IPAddressUtil;
+
+/**
+ * The abstract class {@code URLStreamHandler} is the common
+ * superclass for all stream protocol handlers. A stream protocol
+ * handler knows how to make a connection for a particular protocol
+ * type, such as {@code http} or {@code https}.
+ * <p>
+ * In most cases, an instance of a {@code URLStreamHandler}
+ * subclass is not created directly by an application. Rather, the
+ * first time a protocol name is encountered when constructing a
+ * {@code URL}, the appropriate stream protocol handler is
+ * automatically loaded.
+ *
+ * @author  James Gosling
+ * @see     java.net.URL#URL(java.lang.String, java.lang.String, int, java.lang.String)
+ * @since   JDK1.0
+ */
+public abstract class URLStreamHandler {
+    /**
+     * Opens a connection to the object referenced by the
+     * {@code URL} argument.
+     * This method should be overridden by a subclass.
+     *
+     * <p>If for the handler's protocol (such as HTTP or JAR), there
+     * exists a public, specialized URLConnection subclass belonging
+     * to one of the following packages or one of their subpackages:
+     * java.lang, java.io, java.util, java.net, the connection
+     * returned will be of that subclass. For example, for HTTP an
+     * HttpURLConnection will be returned, and for JAR a
+     * JarURLConnection will be returned.
+     *
+     * @param      u   the URL that this connects to.
+     * @return     a {@code URLConnection} object for the {@code URL}.
+     * @exception  IOException  if an I/O error occurs while opening the
+     *               connection.
+     */
+    abstract protected URLConnection openConnection(URL u) throws IOException;
+
+    /**
+     * Same as openConnection(URL), except that the connection will be
+     * made through the specified proxy; Protocol handlers that do not
+     * support proxying will ignore the proxy parameter and make a
+     * normal connection.
+     *
+     * Calling this method preempts the system's default ProxySelector
+     * settings.
+     *
+     * @param      u   the URL that this connects to.
+     * @param      p   the proxy through which the connection will be made.
+     *                 If direct connection is desired, Proxy.NO_PROXY
+     *                 should be specified.
+     * @return     a {@code URLConnection} object for the {@code URL}.
+     * @exception  IOException  if an I/O error occurs while opening the
+     *               connection.
+     * @exception  IllegalArgumentException if either u or p is null,
+     *               or p has the wrong type.
+     * @exception  UnsupportedOperationException if the subclass that
+     *               implements the protocol doesn't support this method.
+     * @since      1.5
+     */
+    protected URLConnection openConnection(URL u, Proxy p) throws IOException {
+        throw new UnsupportedOperationException("Method not implemented.");
+    }
+
+    /**
+     * Parses the string representation of a {@code URL} into a
+     * {@code URL} object.
+     * <p>
+     * If there is any inherited context, then it has already been
+     * copied into the {@code URL} argument.
+     * <p>
+     * The {@code parseURL} method of {@code URLStreamHandler}
+     * parses the string representation as if it were an
+     * {@code http} specification. Most URL protocol families have a
+     * similar parsing. A stream protocol handler for a protocol that has
+     * a different syntax must override this routine.
+     *
+     * @param   u       the {@code URL} to receive the result of parsing
+     *                  the spec.
+     * @param   spec    the {@code String} representing the URL that
+     *                  must be parsed.
+     * @param   start   the character index at which to begin parsing. This is
+     *                  just past the '{@code :}' (if there is one) that
+     *                  specifies the determination of the protocol name.
+     * @param   limit   the character position to stop parsing at. This is the
+     *                  end of the string or the position of the
+     *                  "{@code #}" character, if present. All information
+     *                  after the sharp sign indicates an anchor.
+     */
+    protected void parseURL(URL u, String spec, int start, int limit) {
+        // These fields may receive context content if this was relative URL
+        String protocol = u.getProtocol();
+        String authority = u.getAuthority();
+        String userInfo = u.getUserInfo();
+        String host = u.getHost();
+        int port = u.getPort();
+        String path = u.getPath();
+        String query = u.getQuery();
+
+        // This field has already been parsed
+        String ref = u.getRef();
+
+        boolean isRelPath = false;
+        boolean queryOnly = false;
+        // BEGIN Android-changed: App compat
+        boolean querySet = false;
+        // END Android-changed: App compat
+
+// FIX: should not assume query if opaque
+        // Strip off the query part
+        if (start < limit) {
+            int queryStart = spec.indexOf('?');
+            queryOnly = queryStart == start;
+            if ((queryStart != -1) && (queryStart < limit)) {
+                query = spec.substring(queryStart+1, limit);
+                if (limit > queryStart)
+                    limit = queryStart;
+                spec = spec.substring(0, queryStart);
+                // BEGIN Android-changed: App compat
+                querySet = true;
+                // END Android-changed: App compat
+            }
+        }
+
+        int i = 0;
+        // Parse the authority part if any
+        // BEGIN Android-changed: App compat
+        // boolean isUNCName = (start <= limit - 4) &&
+        //                 (spec.charAt(start) == '/') &&
+        //                 (spec.charAt(start + 1) == '/') &&
+        //                 (spec.charAt(start + 2) == '/') &&
+        //                 (spec.charAt(start + 3) == '/');
+        boolean isUNCName = false;
+        // END Android-changed: App compat
+        if (!isUNCName && (start <= limit - 2) && (spec.charAt(start) == '/') &&
+            (spec.charAt(start + 1) == '/')) {
+            start += 2;
+            // BEGIN Android-changed: Check for all hostname termination chars. http://b/110955991
+            /*
+            i = spec.indexOf('/', start);
+            if (i < 0 || i > limit) {
+                i = spec.indexOf('?', start);
+                if (i < 0 || i > limit)
+                    i = limit;
+            }
+            */
+            LOOP: for (i = start; i < limit; i++) {
+                switch (spec.charAt(i)) {
+                    case '/':  // Start of path
+                    case '\\': // Start of path - see https://url.spec.whatwg.org/#host-state
+                    case '?':  // Start of query
+                    case '#':  // Start of fragment
+                        break LOOP;
+                }
+            }
+            // END Android-changed: Check for all hostname termination chars. http://b/110955991
+
+            host = authority = spec.substring(start, i);
+
+            int ind = authority.indexOf('@');
+            if (ind != -1) {
+                if (ind != authority.lastIndexOf('@')) {
+                    // more than one '@' in authority. This is not server based
+                    userInfo = null;
+                    host = null;
+                } else {
+                    userInfo = authority.substring(0, ind);
+                    host = authority.substring(ind+1);
+                }
+            } else {
+                userInfo = null;
+            }
+            if (host != null) {
+                // If the host is surrounded by [ and ] then its an IPv6
+                // literal address as specified in RFC2732
+                if (host.length()>0 && (host.charAt(0) == '[')) {
+                    if ((ind = host.indexOf(']')) > 2) {
+
+                        String nhost = host ;
+                        host = nhost.substring(0,ind+1);
+                        if (!IPAddressUtil.
+                            isIPv6LiteralAddress(host.substring(1, ind))) {
+                            throw new IllegalArgumentException(
+                                "Invalid host: "+ host);
+                        }
+
+                        port = -1 ;
+                        if (nhost.length() > ind+1) {
+                            if (nhost.charAt(ind+1) == ':') {
+                                ++ind ;
+                                // port can be null according to RFC2396
+                                if (nhost.length() > (ind + 1)) {
+                                    port = Integer.parseInt(nhost.substring(ind+1));
+                                }
+                            } else {
+                                throw new IllegalArgumentException(
+                                    "Invalid authority field: " + authority);
+                            }
+                        }
+                    } else {
+                        throw new IllegalArgumentException(
+                            "Invalid authority field: " + authority);
+                    }
+                } else {
+                    ind = host.indexOf(':');
+                    port = -1;
+                    if (ind >= 0) {
+                        // port can be null according to RFC2396
+                        if (host.length() > (ind + 1)) {
+                            // BEGIN Android-changed: App compat
+                            // port = Integer.parseInt(host.substring(ind + 1));
+                            char firstPortChar = host.charAt(ind+1);
+                            if (firstPortChar >= '0' && firstPortChar <= '9') {
+                                port = Integer.parseInt(host.substring(ind + 1));
+                            } else {
+                                throw new IllegalArgumentException("invalid port: " +
+                                                                   host.substring(ind + 1));
+                            }
+                            // END Android-changed: App compat
+                        }
+                        host = host.substring(0, ind);
+                    }
+                }
+            } else {
+                host = "";
+            }
+            if (port < -1)
+                throw new IllegalArgumentException("Invalid port number :" +
+                                                   port);
+            start = i;
+
+            // If the authority is defined then the path is defined by the
+            // spec only; See RFC 2396 Section 5.2.4.
+            // BEGIN Android-changed: App compat
+            // if (authority != null && authority.length() > 0)
+            //   path = "";
+            path = null;
+            if (!querySet) {
+                query = null;
+            }
+            // END Android-changed: App compat
+        }
+
+        if (host == null) {
+            host = "";
+        }
+
+        // Parse the file path if any
+        if (start < limit) {
+            // Android-changed: Check for all hostname termination chars. http://b/110955991
+            // if (spec.charAt(start) == '/') {
+            if (spec.charAt(start) == '/' || spec.charAt(start) == '\\') {
+                path = spec.substring(start, limit);
+            } else if (path != null && path.length() > 0) {
+                isRelPath = true;
+                int ind = path.lastIndexOf('/');
+                String seperator = "";
+                if (ind == -1 && authority != null)
+                    seperator = "/";
+                path = path.substring(0, ind + 1) + seperator +
+                         spec.substring(start, limit);
+
+            } else {
+                String seperator = (authority != null) ? "/" : "";
+                path = seperator + spec.substring(start, limit);
+            }
+        }
+        // BEGIN Android-changed: App compat
+        //else if (queryOnly && path != null) {
+        //    int ind = path.lastIndexOf('/');
+        //    if (ind < 0)
+        //        ind = 0;
+        //    path = path.substring(0, ind) + "/";
+        //}
+        // END Android-changed: App compat
+        if (path == null)
+            path = "";
+
+        // BEGIN Android-changed
+        //if (isRelPath) {
+        if (true) {
+        // END Android-changed
+            // Remove embedded /./
+            while ((i = path.indexOf("/./")) >= 0) {
+                path = path.substring(0, i) + path.substring(i + 2);
+            }
+            // Remove embedded /../ if possible
+            i = 0;
+            while ((i = path.indexOf("/../", i)) >= 0) {
+                // BEGIN Android-changed: App compat
+                /*
+                 * Trailing /../
+                 */
+                if (i == 0) {
+                    path = path.substring(i + 3);
+                    i = 0;
+                // END Android-changed: App compat
+                /*
+                 * A "/../" will cancel the previous segment and itself,
+                 * unless that segment is a "/../" itself
+                 * i.e. "/a/b/../c" becomes "/a/c"
+                 * but "/../../a" should stay unchanged
+                 */
+                // Android-changed: App compat
+                // if (i > 0 && (limit = path.lastIndexOf('/', i - 1)) >= 0 &&
+                } else if (i > 0 && (limit = path.lastIndexOf('/', i - 1)) >= 0 &&
+                    (path.indexOf("/../", limit) != 0)) {
+                    path = path.substring(0, limit) + path.substring(i + 3);
+                    i = 0;
+                } else {
+                    i = i + 3;
+                }
+            }
+            // Remove trailing .. if possible
+            while (path.endsWith("/..")) {
+                i = path.indexOf("/..");
+                if ((limit = path.lastIndexOf('/', i - 1)) >= 0) {
+                    path = path.substring(0, limit+1);
+                } else {
+                    break;
+                }
+            }
+            // Remove starting .
+            if (path.startsWith("./") && path.length() > 2)
+                path = path.substring(2);
+
+            // Remove trailing .
+            if (path.endsWith("/."))
+                path = path.substring(0, path.length() -1);
+
+            // Android-changed: App compat: Remove trailing ?
+            if (path.endsWith("?"))
+                path = path.substring(0, path.length() -1);
+        }
+
+        setURL(u, protocol, host, port, authority, userInfo, path, query, ref);
+    }
+
+    /**
+     * Returns the default port for a URL parsed by this handler. This method
+     * is meant to be overidden by handlers with default port numbers.
+     * @return the default port for a {@code URL} parsed by this handler.
+     * @since 1.3
+     */
+    protected int getDefaultPort() {
+        return -1;
+    }
+
+    /**
+     * Provides the default equals calculation. May be overidden by handlers
+     * for other protocols that have different requirements for equals().
+     * This method requires that none of its arguments is null. This is
+     * guaranteed by the fact that it is only called by java.net.URL class.
+     * @param u1 a URL object
+     * @param u2 a URL object
+     * @return {@code true} if the two urls are
+     * considered equal, ie. they refer to the same
+     * fragment in the same file.
+     * @since 1.3
+     */
+    protected boolean equals(URL u1, URL u2) {
+        // Android-changed: Avoid network I/O
+        return Objects.equals(u1.getRef(), u2.getRef()) &&
+               Objects.equals(u1.getQuery(), u2.getQuery()) &&
+               // sameFile compares the protocol, file, port & host components of
+               // the URLs.
+               sameFile(u1, u2);
+    }
+
+    /**
+     * Provides the default hash calculation. May be overidden by handlers for
+     * other protocols that have different requirements for hashCode
+     * calculation.
+     * @param u a URL object
+     * @return an {@code int} suitable for hash table indexing
+     * @since 1.3
+     */
+    protected int hashCode(URL u) {
+        // Android-changed: Avoid network I/O
+        // Hash on the same set of fields that we compare in equals().
+        return Objects.hash(
+                u.getRef(),
+                u.getQuery(),
+                u.getProtocol(),
+                u.getFile(),
+                u.getHost(),
+                u.getPort());
+    }
+
+    /**
+     * Compare two urls to see whether they refer to the same file,
+     * i.e., having the same protocol, host, port, and path.
+     * This method requires that none of its arguments is null. This is
+     * guaranteed by the fact that it is only called indirectly
+     * by java.net.URL class.
+     * @param u1 a URL object
+     * @param u2 a URL object
+     * @return true if u1 and u2 refer to the same file
+     * @since 1.3
+     */
+    protected boolean sameFile(URL u1, URL u2) {
+        // Compare the protocols.
+        if (!((u1.getProtocol() == u2.getProtocol()) ||
+              (u1.getProtocol() != null &&
+               u1.getProtocol().equalsIgnoreCase(u2.getProtocol()))))
+            return false;
+
+        // Compare the files.
+        if (!(u1.getFile() == u2.getFile() ||
+              (u1.getFile() != null && u1.getFile().equals(u2.getFile()))))
+            return false;
+
+        // Compare the ports.
+        int port1, port2;
+        port1 = (u1.getPort() != -1) ? u1.getPort() : u1.handler.getDefaultPort();
+        port2 = (u2.getPort() != -1) ? u2.getPort() : u2.handler.getDefaultPort();
+        if (port1 != port2)
+            return false;
+
+        // Compare the hosts.
+        if (!hostsEqual(u1, u2))
+            return false;
+
+        return true;
+    }
+
+    /**
+     * Get the IP address of our host. An empty host field or a DNS failure
+     * will result in a null return.
+     *
+     * @param u a URL object
+     * @return an {@code InetAddress} representing the host
+     * IP address.
+     * @since 1.3
+     */
+    protected synchronized InetAddress getHostAddress(URL u) {
+        if (u.hostAddress != null)
+            return u.hostAddress;
+
+        String host = u.getHost();
+        if (host == null || host.equals("")) {
+            return null;
+        } else {
+            try {
+                u.hostAddress = InetAddress.getByName(host);
+            } catch (UnknownHostException ex) {
+                return null;
+            } catch (SecurityException se) {
+                return null;
+            }
+        }
+        return u.hostAddress;
+    }
+
+    /**
+     * Compares the host components of two URLs.
+     * @param u1 the URL of the first host to compare
+     * @param u2 the URL of the second host to compare
+     * @return  {@code true} if and only if they
+     * are equal, {@code false} otherwise.
+     * @since 1.3
+     */
+    protected boolean hostsEqual(URL u1, URL u2) {
+        // Android-changed: Don't compare the InetAddresses of the hosts.
+        if (u1.getHost() != null && u2.getHost() != null)
+            return u1.getHost().equalsIgnoreCase(u2.getHost());
+         else
+            return u1.getHost() == null && u2.getHost() == null;
+    }
+
+    /**
+     * Converts a {@code URL} of a specific protocol to a
+     * {@code String}.
+     *
+     * @param   u   the URL.
+     * @return  a string representation of the {@code URL} argument.
+     */
+    protected String toExternalForm(URL u) {
+
+        // pre-compute length of StringBuffer
+        int len = u.getProtocol().length() + 1;
+        if (u.getAuthority() != null && u.getAuthority().length() > 0)
+            len += 2 + u.getAuthority().length();
+        if (u.getPath() != null) {
+            len += u.getPath().length();
+        }
+        if (u.getQuery() != null) {
+            len += 1 + u.getQuery().length();
+        }
+        if (u.getRef() != null)
+            len += 1 + u.getRef().length();
+
+        // BEGIN Android-changed: Add a toExternalForm variant that optionally escapes illegal chars
+        // TODO: The variant has been removed. We can potentially revert the change
+        StringBuilder result = new StringBuilder(len);
+        result.append(u.getProtocol());
+        result.append(":");
+        if (u.getAuthority() != null) {// ANDROID: && u.getAuthority().length() > 0) {
+            result.append("//");
+            result.append(u.getAuthority());
+        }
+        String fileAndQuery = u.getFile();
+        if (fileAndQuery != null) {
+            result.append(fileAndQuery);
+        }
+        // END Android-changed: Add a toExternalForm variant that optionally escapes illegal chars
+        if (u.getRef() != null) {
+            result.append("#");
+            result.append(u.getRef());
+        }
+        return result.toString();
+    }
+
+    // Android-changed: Removed @see tag (target is package-private):
+    // @see     java.net.URL#set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String)
+    /**
+     * Sets the fields of the {@code URL} argument to the indicated values.
+     * Only classes derived from URLStreamHandler are able
+     * to use this method to set the values of the URL fields.
+     *
+     * @param   u         the URL to modify.
+     * @param   protocol  the protocol name.
+     * @param   host      the remote host value for the URL.
+     * @param   port      the port on the remote machine.
+     * @param   authority the authority part for the URL.
+     * @param   userInfo the userInfo part of the URL.
+     * @param   path      the path component of the URL.
+     * @param   query     the query part for the URL.
+     * @param   ref       the reference.
+     * @exception       SecurityException       if the protocol handler of the URL is
+     *                                  different from this one
+     * @since 1.3
+     */
+       protected void setURL(URL u, String protocol, String host, int port,
+                             String authority, String userInfo, String path,
+                             String query, String ref) {
+        if (this != u.handler) {
+            throw new SecurityException("handler for url different from " +
+                                        "this handler");
+        }
+        // ensure that no one can reset the protocol on a given URL.
+        u.set(u.getProtocol(), host, port, authority, userInfo, path, query, ref);
+    }
+
+    /**
+     * Sets the fields of the {@code URL} argument to the indicated values.
+     * Only classes derived from URLStreamHandler are able
+     * to use this method to set the values of the URL fields.
+     *
+     * @param   u         the URL to modify.
+     * @param   protocol  the protocol name. This value is ignored since 1.2.
+     * @param   host      the remote host value for the URL.
+     * @param   port      the port on the remote machine.
+     * @param   file      the file.
+     * @param   ref       the reference.
+     * @exception       SecurityException       if the protocol handler of the URL is
+     *                                  different from this one
+     * @deprecated Use setURL(URL, String, String, int, String, String, String,
+     *             String);
+     */
+    @Deprecated
+    protected void setURL(URL u, String protocol, String host, int port,
+                          String file, String ref) {
+        /*
+         * Only old URL handlers call this, so assume that the host
+         * field might contain "user:passwd@host". Fix as necessary.
+         */
+        String authority = null;
+        String userInfo = null;
+        if (host != null && host.length() != 0) {
+            authority = (port == -1) ? host : host + ":" + port;
+            int at = host.lastIndexOf('@');
+            if (at != -1) {
+                userInfo = host.substring(0, at);
+                host = host.substring(at+1);
+            }
+        }
+
+        /*
+         * Assume file might contain query part. Fix as necessary.
+         */
+        String path = null;
+        String query = null;
+        if (file != null) {
+            int q = file.lastIndexOf('?');
+            if (q != -1) {
+                query = file.substring(q+1);
+                path = file.substring(0, q);
+            } else
+                path = file;
+        }
+        setURL(u, protocol, host, port, authority, userInfo, path, query, ref);
+    }
+}
diff --git a/java/net/URLStreamHandlerFactory.java b/java/net/URLStreamHandlerFactory.java
new file mode 100644
index 0000000..e46e028
--- /dev/null
+++ b/java/net/URLStreamHandlerFactory.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * This interface defines a factory for {@code URL} stream
+ * protocol handlers.
+ * <p>
+ * It is used by the {@code URL} class to create a
+ * {@code URLStreamHandler} for a specific protocol.
+ *
+ * @author  Arthur van Hoff
+ * @see     java.net.URL
+ * @see     java.net.URLStreamHandler
+ * @since   JDK1.0
+ */
+public interface URLStreamHandlerFactory {
+    /**
+     * Creates a new {@code URLStreamHandler} instance with the specified
+     * protocol.
+     *
+     * @param   protocol   the protocol ("{@code ftp}",
+     *                     "{@code http}", "{@code nntp}", etc.).
+     * @return  a {@code URLStreamHandler} for the specific protocol.
+     * @see     java.net.URLStreamHandler
+     */
+    URLStreamHandler createURLStreamHandler(String protocol);
+}
diff --git a/java/net/UnknownHostException.java b/java/net/UnknownHostException.java
new file mode 100644
index 0000000..21a9d14
--- /dev/null
+++ b/java/net/UnknownHostException.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * Thrown to indicate that the IP address of a host could not be determined.
+ *
+ * @author  Jonathan Payne
+ * @since   JDK1.0
+ */
+public
+class UnknownHostException extends IOException {
+    private static final long serialVersionUID = -4639126076052875403L;
+
+    /**
+     * Constructs a new {@code UnknownHostException} with the
+     * specified detail message.
+     *
+     * @param   host   the detail message.
+     */
+    public UnknownHostException(String host) {
+        super(host);
+    }
+
+    /**
+     * Constructs a new {@code UnknownHostException} with no detail
+     * message.
+     */
+    public UnknownHostException() {
+    }
+}
diff --git a/java/net/UnknownServiceException.java b/java/net/UnknownServiceException.java
new file mode 100644
index 0000000..4eea4a7
--- /dev/null
+++ b/java/net/UnknownServiceException.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * Thrown to indicate that an unknown service exception has
+ * occurred. Either the MIME type returned by a URL connection does
+ * not make sense, or the application is attempting to write to a
+ * read-only URL connection.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public class UnknownServiceException extends IOException {
+    private static final long serialVersionUID = -4169033248853639508L;
+
+    /**
+     * Constructs a new {@code UnknownServiceException} with no
+     * detail message.
+     */
+    public UnknownServiceException() {
+    }
+
+    /**
+     * Constructs a new {@code UnknownServiceException} with the
+     * specified detail message.
+     *
+     * @param   msg   the detail message.
+     */
+    public UnknownServiceException(String msg) {
+        super(msg);
+    }
+}
diff --git a/java/net/package-info.java b/java/net/package-info.java
new file mode 100644
index 0000000..fda2e4f
--- /dev/null
+++ b/java/net/package-info.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Provides the classes for implementing networking applications.
+ *
+ * <p> The java.net package can be roughly divided in two sections:</p>
+ * <ul>
+ *     <li><p><i>A Low Level API</i>, which deals with the
+ *               following abstractions:</p>
+ *     <ul>
+ *       <li><p><i>Addresses</i>, which are networking identifiers,
+ *              like IP addresses.</p></li>
+ *       <li><p><i>Sockets</i>, which are basic bidirectional data communication
+ *              mechanisms.</p></li>
+ *       <li><p><i>Interfaces</i>, which describe network interfaces. </p></li>
+ *     </ul></li>
+ *     <li> <p><i>A High Level API</i>, which deals with the following
+ *          abstractions:</p>
+ *     <ul>
+ *       <li><p><i>URIs</i>, which represent
+ *               Universal Resource Identifiers.</p></li>
+ *       <li><p><i>URLs</i>, which represent
+ *               Universal Resource Locators.</p></li>
+ *       <li><p><i>Connections</i>, which represents connections to the resource
+ *               pointed to by <i>URLs</i>.</p></li>
+ *       </ul></li>
+ * </ul>
+ * <h2>Addresses</h2>
+ * <p>Addresses are used throughout the java.net APIs as either host
+ *    identifiers, or socket endpoint identifiers.</p>
+ * <p>The {@link java.net.InetAddress} class is the abstraction representing an
+ *    IP (Internet Protocol) address.  It has two subclasses:
+ * <ul>
+ *       <li>{@link java.net.Inet4Address} for IPv4 addresses.</li>
+ *       <li>{@link java.net.Inet6Address} for IPv6 addresses.</li>
+ * </ul>
+ * <p>But, in most cases, there is no need to deal directly with the subclasses,
+ *    as the InetAddress abstraction should cover most of the needed
+ *    functionality.</p>
+ * <h3><b>About IPv6</b></h3>
+ * <p>Not all systems have support for the IPv6 protocol, and while the Java
+ *    networking stack will attempt to detect it and use it transparently when
+ *    available, it is also possible to disable its use with a system property.
+ *    In the case where IPv6 is not available, or explicitly disabled,
+ *    Inet6Address are not valid arguments for most networking operations any
+ *    more. While methods like {@link java.net.InetAddress#getByName} are
+ *    guaranteed not to return an Inet6Address when looking up host names, it
+ *    is possible, by passing literals, to create such an object. In which
+ *    case, most methods, when called with an Inet6Address will throw an
+ *    Exception.</p>
+ * <h2>Sockets</h2>
+ * <p>Sockets are means to establish a communication link between machines over
+ *    the network. The java.net package provides 4 kinds of Sockets:</p>
+ * <ul>
+ *       <li>{@link java.net.Socket} is a TCP client API, and will typically
+ *            be used to {@linkplain java.net.Socket#connect(SocketAddress)
+ *            connect} to a remote host.</li>
+ *       <li>{@link java.net.ServerSocket} is a TCP server API, and will
+ *            typically {@linkplain java.net.ServerSocket#accept accept}
+ *            connections from client sockets.</li>
+ *       <li>{@link java.net.DatagramSocket} is a UDP endpoint API and is used
+ *            to {@linkplain java.net.DatagramSocket#send send} and
+ *            {@linkplain java.net.DatagramSocket#receive receive}
+ *            {@linkplain java.net.DatagramPacket datagram packets}.</li>
+ *       <li>{@link java.net.MulticastSocket} is a subclass of
+ *            {@code DatagramSocket} used when dealing with multicast
+ *            groups.</li>
+ * </ul>
+ * <p>Sending and receiving with TCP sockets is done through InputStreams and
+ *    OutputStreams which can be obtained via the
+ *    {@link java.net.Socket#getInputStream} and
+ *    {@link java.net.Socket#getOutputStream} methods.</p>
+ * <h2>Interfaces</h2>
+ * <p>The {@link java.net.NetworkInterface} class provides APIs to browse and
+ *    query all the networking interfaces (e.g. ethernet connection or PPP
+ *    endpoint) of the local machine. It is through that class that you can
+ *    check if any of the local interfaces is configured to support IPv6.</p>
+ * <p>Note, all conforming implementations must support at least one
+ *    {@code NetworkInterface} object, which must either be connected to a
+ *    network, or be a "loopback" interface that can only communicate with
+ *    entities on the same machine.</p>
+ *
+ * <h2>High level API</h2>
+ * <p>A number of classes in the java.net package do provide for a much higher
+ *    level of abstraction and allow for easy access to resources on the
+ *    network. The classes are:
+ * <ul>
+ *       <li>{@link java.net.URI} is the class representing a
+ *            Universal Resource Identifier, as specified in RFC 2396.
+ *            As the name indicates, this is just an Identifier and doesn't
+ *            provide directly the means to access the resource.</li>
+ *       <li>{@link java.net.URL} is the class representing a
+ *            Universal Resource Locator, which is both an older concept for
+ *            URIs and a means to access the resources.</li>
+ *       <li>{@link java.net.URLConnection} is created from a URL and is the
+ *            communication link used to access the resource pointed by the
+ *            URL. This abstract class will delegate most of the work to the
+ *            underlying protocol handlers like http or https.</li>
+ *       <li>{@link java.net.HttpURLConnection} is a subclass of URLConnection
+ *            and provides some additional functionalities specific to the
+ *            HTTP protocol.</li>
+ * </ul>
+ * <p>The recommended usage is to use {@link java.net.URI} to identify
+ *    resources, then convert it into a {@link java.net.URL} when it is time to
+ *    access the resource. From that URL, you can either get the
+ *    {@link java.net.URLConnection} for fine control, or get directly the
+ *    InputStream.
+ * <p>Here is an example:</p>
+ * <pre>
+ * URI uri = new URI("http://java.sun.com/");
+ * URL url = uri.toURL();
+ * InputStream in = url.openStream();
+ * </pre>
+ * <h2>Protocol Handlers</h2>
+ * As mentioned, URL and URLConnection rely on protocol handlers which must be
+ * present, otherwise an Exception is thrown. This is the major difference with
+ * URIs which only identify resources, and therefore don't need to have access
+ * to the protocol handler. So, while it is possible to create an URI with any
+ * kind of protocol scheme (e.g. {@code myproto://myhost.mydomain/resource/}),
+ * a similar URL will try to instantiate the handler for the specified protocol;
+ * if it doesn't exist an exception will be thrown.
+ * <p>By default the protocol handlers are loaded dynamically from the default
+ *    location. It is, however, possible to add to the search path by setting
+ *    the {@code java.protocol.handler.pkgs} system property. For instance if
+ *    it is set to {@code myapp.protocols}, then the URL code will try, in the
+ *    case of http, first to load {@code myapp.protocols.http.Handler}, then,
+ *    if this fails, {@code http.Handler} from the default location.
+ * <p>Note that the Handler class <b>has to</b> be a subclass of the abstract
+ *    class {@link java.net.URLStreamHandler}.</p>
+ * <h2>Additional Specification</h2>
+ * <ul>
+ *       <li><a href="doc-files/net-properties.html">
+ *            Networking System Properties</a></li>
+ * </ul>
+ *
+ * @since JDK1.0
+ */
+package java.net;