Allow using third-party HTTP/... stacks for per-network URLs.
Also switch to double-checked locking for mNetworkBoundSocketFactory and OkHttpClient. Change-Id: Ic52776ee760036ad5623b7496156b8909dc282fa
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package android.net;
|
package android.net;
|
||||||
|
|
||||||
|
import android.net.NetworkBoundURLFactory;
|
||||||
import android.net.NetworkUtils;
|
import android.net.NetworkUtils;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
@@ -29,6 +30,8 @@ import java.net.SocketAddress;
|
|||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.net.URLStreamHandler;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import javax.net.SocketFactory;
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
import com.android.okhttp.HostResolver;
|
import com.android.okhttp.HostResolver;
|
||||||
@@ -52,8 +55,8 @@ public class Network implements Parcelable {
|
|||||||
|
|
||||||
// Objects used to perform per-network operations such as getSocketFactory
|
// Objects used to perform per-network operations such as getSocketFactory
|
||||||
// and getBoundURL, and a lock to protect access to them.
|
// and getBoundURL, and a lock to protect access to them.
|
||||||
private NetworkBoundSocketFactory mNetworkBoundSocketFactory = null;
|
private volatile NetworkBoundSocketFactory mNetworkBoundSocketFactory = null;
|
||||||
private OkHttpClient mOkHttpClient = null;
|
private volatile OkHttpClient mOkHttpClient = null;
|
||||||
private Object mLock = new Object();
|
private Object mLock = new Object();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -174,36 +177,83 @@ public class Network implements Parcelable {
|
|||||||
* {@code Network}.
|
* {@code Network}.
|
||||||
*/
|
*/
|
||||||
public SocketFactory getSocketFactory() {
|
public SocketFactory getSocketFactory() {
|
||||||
synchronized (mLock) {
|
if (mNetworkBoundSocketFactory == null) {
|
||||||
if (mNetworkBoundSocketFactory == null) {
|
synchronized (mLock) {
|
||||||
mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId);
|
if (mNetworkBoundSocketFactory == null) {
|
||||||
|
mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mNetworkBoundSocketFactory;
|
return mNetworkBoundSocketFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The default NetworkBoundURLFactory, used if setNetworkBoundURLFactory is never called. */
|
||||||
|
private static final NetworkBoundURLFactory DEFAULT_URL_FACTORY = new NetworkBoundURLFactory() {
|
||||||
|
public URL getBoundURL(final Network network, URL url) throws MalformedURLException {
|
||||||
|
if (network.mOkHttpClient == null) {
|
||||||
|
synchronized (network.mLock) {
|
||||||
|
if (network.mOkHttpClient == null) {
|
||||||
|
HostResolver hostResolver = new HostResolver() {
|
||||||
|
@Override
|
||||||
|
public InetAddress[] getAllByName(String host)
|
||||||
|
throws UnknownHostException {
|
||||||
|
return network.getAllByName(host);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
network.mOkHttpClient = new OkHttpClient()
|
||||||
|
.setSocketFactory(network.getSocketFactory())
|
||||||
|
.setHostResolver(hostResolver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String protocol = url.getProtocol();
|
||||||
|
URLStreamHandler handler = network.mOkHttpClient.createURLStreamHandler(protocol);
|
||||||
|
if (handler == null) {
|
||||||
|
// OkHttpClient only supports HTTP and HTTPS and returns a null URLStreamHandler if
|
||||||
|
// passed another protocol.
|
||||||
|
throw new MalformedURLException("Invalid URL or unrecognized protocol " + protocol);
|
||||||
|
}
|
||||||
|
return new URL(url, "", handler);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static AtomicReference<NetworkBoundURLFactory> sNetworkBoundURLFactory =
|
||||||
|
new AtomicReference <NetworkBoundURLFactory>(DEFAULT_URL_FACTORY);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@link URL} based on the given URL but bound to this {@code Network}.
|
* Returns a {@link URL} based on the given URL but bound to this {@code Network},
|
||||||
* Note that if this {@code Network} ever disconnects, this factory and any URL object it
|
* such that opening the URL will send all network traffic on this Network.
|
||||||
* produced in the past or future will cease to work.
|
*
|
||||||
|
* Note that if this {@code Network} ever disconnects, any URL object generated by this method
|
||||||
|
* in the past or future will cease to work.
|
||||||
|
*
|
||||||
|
* The returned URL may have a {@link URLStreamHandler} explicitly set, which may not be the
|
||||||
|
* handler generated by the factory set with {@link java.net.URL.setURLStreamHandlerFactory}. To
|
||||||
|
* affect the {@code URLStreamHandler}s of URLs returned by this method, call
|
||||||
|
* {@link #setNetworkBoundURLFactory}.
|
||||||
|
*
|
||||||
|
* Because the returned URLs may have an explicit {@code URLStreamHandler} set, using them as a
|
||||||
|
* context when constructing other URLs and explicitly specifying a {@code URLStreamHandler} may
|
||||||
|
* result in URLs that are no longer bound to the same {@code Network}.
|
||||||
|
*
|
||||||
|
* The default implementation only supports {@code HTTP} and {@code HTTPS} URLs.
|
||||||
*
|
*
|
||||||
* @return a {@link URL} bound to this {@code Network}.
|
* @return a {@link URL} bound to this {@code Network}.
|
||||||
*/
|
*/
|
||||||
public URL getBoundURL(URL url) throws MalformedURLException {
|
public URL getBoundURL(URL url) throws MalformedURLException {
|
||||||
synchronized (mLock) {
|
return sNetworkBoundURLFactory.get().getBoundURL(this, url);
|
||||||
if (mOkHttpClient == null) {
|
}
|
||||||
HostResolver hostResolver = new HostResolver() {
|
|
||||||
@Override
|
/**
|
||||||
public InetAddress[] getAllByName(String host) throws UnknownHostException {
|
* Sets the {@link NetworkBoundURLFactory} to be used by future {@link #getBoundURL} calls.
|
||||||
return Network.this.getAllByName(host);
|
* If {@code null}, clears any factory that was previously specified.
|
||||||
}
|
*/
|
||||||
};
|
public static void setNetworkBoundURLFactory(NetworkBoundURLFactory factory) {
|
||||||
mOkHttpClient = new OkHttpClient()
|
if (factory == null) {
|
||||||
.setSocketFactory(getSocketFactory())
|
factory = DEFAULT_URL_FACTORY;
|
||||||
.setHostResolver(hostResolver);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return new URL(url, "", mOkHttpClient.createURLStreamHandler(url.getProtocol()));
|
sNetworkBoundURLFactory.set(factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
// implement the Parcelable interface
|
// implement the Parcelable interface
|
||||||
|
|||||||
Reference in New Issue
Block a user