diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2014-07-29 22:51:27 +0900 |
---|---|---|
committer | Lorenzo Colitti <lorenzo@google.com> | 2014-07-31 02:17:28 +0000 |
commit | 5b37fa2ed574dbfaf2a2ef6adf5daccb9db941a8 (patch) | |
tree | 5b3e5b026dafeb883dde1880ab0c38310b3fb0b3 /core/java/android/net | |
parent | 4b54271f1bbd29957c47433155c58aa792105d6d (diff) | |
download | frameworks_base-5b37fa2ed574dbfaf2a2ef6adf5daccb9db941a8.zip frameworks_base-5b37fa2ed574dbfaf2a2ef6adf5daccb9db941a8.tar.gz frameworks_base-5b37fa2ed574dbfaf2a2ef6adf5daccb9db941a8.tar.bz2 |
Allow using third-party HTTP/... stacks for per-network URLs.
Also switch to double-checked locking for
mNetworkBoundSocketFactory and OkHttpClient.
Change-Id: Ic52776ee760036ad5623b7496156b8909dc282fa
Diffstat (limited to 'core/java/android/net')
-rw-r--r-- | core/java/android/net/Network.java | 92 | ||||
-rw-r--r-- | core/java/android/net/NetworkBoundURLFactory.java | 35 |
2 files changed, 106 insertions, 21 deletions
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index 5e3decd..7a1c988 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -16,6 +16,7 @@ package android.net; +import android.net.NetworkBoundURLFactory; import android.net.NetworkUtils; import android.os.Parcelable; import android.os.Parcel; @@ -29,6 +30,8 @@ import java.net.SocketAddress; import java.net.SocketException; import java.net.UnknownHostException; import java.net.URL; +import java.net.URLStreamHandler; +import java.util.concurrent.atomic.AtomicReference; import javax.net.SocketFactory; import com.android.okhttp.HostResolver; @@ -52,8 +55,8 @@ public class Network implements Parcelable { // Objects used to perform per-network operations such as getSocketFactory // and getBoundURL, and a lock to protect access to them. - private NetworkBoundSocketFactory mNetworkBoundSocketFactory = null; - private OkHttpClient mOkHttpClient = null; + private volatile NetworkBoundSocketFactory mNetworkBoundSocketFactory = null; + private volatile OkHttpClient mOkHttpClient = null; private Object mLock = new Object(); /** @@ -174,36 +177,83 @@ public class Network implements Parcelable { * {@code Network}. */ public SocketFactory getSocketFactory() { - synchronized (mLock) { - if (mNetworkBoundSocketFactory == null) { - mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId); + if (mNetworkBoundSocketFactory == null) { + synchronized (mLock) { + if (mNetworkBoundSocketFactory == null) { + mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId); + } } } 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}. - * Note that if this {@code Network} ever disconnects, this factory and any URL object it - * produced in the past or future will cease to work. + * Returns a {@link URL} based on the given URL but bound to this {@code Network}, + * such that opening the URL will send all network traffic on this Network. + * + * 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}. */ public URL getBoundURL(URL url) throws MalformedURLException { - synchronized (mLock) { - if (mOkHttpClient == null) { - HostResolver hostResolver = new HostResolver() { - @Override - public InetAddress[] getAllByName(String host) throws UnknownHostException { - return Network.this.getAllByName(host); - } - }; - mOkHttpClient = new OkHttpClient() - .setSocketFactory(getSocketFactory()) - .setHostResolver(hostResolver); - } + return sNetworkBoundURLFactory.get().getBoundURL(this, url); + } + + /** + * Sets the {@link NetworkBoundURLFactory} to be used by future {@link #getBoundURL} calls. + * If {@code null}, clears any factory that was previously specified. + */ + public static void setNetworkBoundURLFactory(NetworkBoundURLFactory factory) { + if (factory == null) { + factory = DEFAULT_URL_FACTORY; } - return new URL(url, "", mOkHttpClient.createURLStreamHandler(url.getProtocol())); + sNetworkBoundURLFactory.set(factory); } // implement the Parcelable interface diff --git a/core/java/android/net/NetworkBoundURLFactory.java b/core/java/android/net/NetworkBoundURLFactory.java new file mode 100644 index 0000000..356100e --- /dev/null +++ b/core/java/android/net/NetworkBoundURLFactory.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014 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 android.net; + +import java.net.MalformedURLException; +import java.net.URL; + +/** + * An interface that describes a factory for network-specific {@link URL} objects. + */ +public interface NetworkBoundURLFactory { + /** + * Returns a {@link URL} based on the given URL but bound to the specified {@code Network}, + * such that opening the URL will send all network traffic on the specified Network. + * + * @return a {@link URL} bound to this {@code Network}. + * @throws MalformedURLException if the URL was not valid, or this factory cannot handle the + * specified URL (e.g., if it does not support the protocol of the URL). + */ + public URL getBoundURL(Network network, URL url) throws MalformedURLException; +} |