summaryrefslogtreecommitdiffstats
path: root/core/java/android/net
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2014-07-29 22:51:27 +0900
committerLorenzo Colitti <lorenzo@google.com>2014-07-31 02:17:28 +0000
commit5b37fa2ed574dbfaf2a2ef6adf5daccb9db941a8 (patch)
tree5b3e5b026dafeb883dde1880ab0c38310b3fb0b3 /core/java/android/net
parent4b54271f1bbd29957c47433155c58aa792105d6d (diff)
downloadframeworks_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.java92
-rw-r--r--core/java/android/net/NetworkBoundURLFactory.java35
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;
+}