From 00cfe112b436eaafb44c0466ceacce3baf10a8f3 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Thu, 16 Sep 2010 15:54:32 -0700 Subject: [PATCH] Add LinkSocket API Restructuring ConnectivityService to handle multiple connections. Change-Id: Ia993fbb120bebb844fd0d603dc76fbc700b31fd1 --- core/java/android/net/LinkSocket.java | 265 ++++++++++++++++++ core/java/android/net/LinkSocketNotifier.java | 88 ++++++ .../src/android/net/LinkSocketTest.java | 44 +++ 3 files changed, 397 insertions(+) create mode 100644 core/java/android/net/LinkSocket.java create mode 100644 core/java/android/net/LinkSocketNotifier.java create mode 100644 core/tests/coretests/src/android/net/LinkSocketTest.java diff --git a/core/java/android/net/LinkSocket.java b/core/java/android/net/LinkSocket.java new file mode 100644 index 0000000000000..d416ed0955ac3 --- /dev/null +++ b/core/java/android/net/LinkSocket.java @@ -0,0 +1,265 @@ +/* + * 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 android.net; + +import android.net.LinkCapabilities; +import android.net.LinkProperties; +import android.net.LinkSocketNotifier; + +import android.util.Log; + +import java.io.IOException; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; +import java.util.HashSet; +import java.util.Set; + +/** @hide */ +public class LinkSocket extends Socket { + private final static String TAG = "LinkSocket"; + private final static boolean DBG = true; + + /** + * Default constructor + */ + public LinkSocket() { + if (DBG) log("LinkSocket() EX"); + } + + /** + * Creates a new unconnected socket. + * @param notifier a reference to a class that implements {@code LinkSocketNotifier} + */ + public LinkSocket(LinkSocketNotifier notifier) { + if (DBG) log("LinkSocket(notifier) EX"); + } + + /** + * Creates a new unconnected socket usign the given proxy type. + * @param notifier a reference to a class that implements {@code LinkSocketNotifier} + * @param proxy the specified proxy for this socket + * @throws IllegalArgumentException if the argument proxy is null or of an invalid type. + * @throws SecurityException if a security manager exists and it denies the permission + * to connect to the given proxy. + */ + public LinkSocket(LinkSocketNotifier notifier, Proxy proxy) { + if (DBG) log("LinkSocket(notifier, proxy) EX"); + } + + /** + * @return the {@code LinkProperties} for the socket + */ + public LinkProperties getLinkProperties() { + if (DBG) log("LinkProperties() EX"); + return new LinkProperties(); + } + + /** + * Set the {@code LinkCapabilies} needed for this socket. If the socket is already connected + * or is a duplicate socket the request is ignored and {@code false} will + * be returned. A needs map can be created via the {@code createNeedsMap} static + * method. + * @param needs the needs of the socket + * @return {@code true} if needs are successfully set, {@code false} otherwise + */ + public boolean setNeededCapabilities(LinkCapabilities needs) { + if (DBG) log("setNeeds() EX"); + return false; + } + + /** + * @return the LinkCapabilites set by setNeededCapabilities, empty if none has been set + */ + public LinkCapabilities getNeededCapabilities() { + if (DBG) log("getNeeds() EX"); + return null; + } + + /** + * @return all of the {@code LinkCapabilities} of the link used by this socket + */ + public LinkCapabilities getCapabilities() { + if (DBG) log("getCapabilities() EX"); + return null; + } + + /** + * Returns this LinkSockets set of capabilities, filtered according to + * the given {@code Set}. Capabilities in the Set but not available from + * the link will not be reported in the results. Capabilities of the link + * but not listed in the Set will also not be reported in the results. + * @param capabilities {@code Set} of capabilities requested + * @return the filtered {@code LinkCapabilities} of this LinkSocket, may be empty + */ + public LinkCapabilities getCapabilities(Set capabilities) { + if (DBG) log("getCapabilities(capabilities) EX"); + return new LinkCapabilities(); + } + + /** + * Provide the set of capabilities the application is interested in tracking + * for this LinkSocket. + * @param capabilities a {@code Set} of capabilities to track + */ + public void setTrackedCapabilities(Set capabilities) { + if (DBG) log("setTrackedCapabilities(capabilities) EX"); + } + + /** + * @return the {@code LinkCapabilities} that are tracked, empty if none has been set. + */ + public Set getTrackedCapabilities() { + if (DBG) log("getTrackedCapabilities(capabilities) EX"); + return new HashSet(); + } + + /** + * Connects this socket to the given remote host address and port specified + * by dstName and dstPort. + * @param dstName the address of the remote host to connect to + * @param dstPort the port to connect to on the remote host + * @param timeout the timeout value in milliseconds or 0 for infinite timeout + * @throws UnknownHostException if the given dstName is invalid + * @throws IOException if the socket is already connected or an error occurs + * while connecting + * @throws SocketTimeoutException if the timeout fires + */ + public void connect(String dstName, int dstPort, int timeout) + throws UnknownHostException, IOException, SocketTimeoutException { + if (DBG) log("connect(dstName, dstPort, timeout) EX"); + } + + /** + * Connects this socket to the given remote host address and port specified + * by dstName and dstPort. + * @param dstName the address of the remote host to connect to + * @param dstPort the port to connect to on the remote host + * @throws UnknownHostException if the given dstName is invalid + * @throws IOException if the socket is already connected or an error occurs + * while connecting + */ + public void connect(String dstName, int dstPort) + throws UnknownHostException, IOException { + if (DBG) log("connect(dstName, dstPort, timeout) EX"); + } + + /** + * Connects this socket to the given remote host address and port specified + * by the SocketAddress with the specified timeout. + * @deprecated Use {@code connect(String dstName, int dstPort, int timeout)} + * instead. Using this method may result in reduced functionality. + * @param remoteAddr the address and port of the remote host to connect to + * @throws IllegalArgumentException if the given SocketAddress is invalid + * @throws IOException if the socket is already connected or an error occurs + * while connecting + * @throws SocketTimeoutException if the timeout expires + */ + @Override + @Deprecated + public void connect(SocketAddress remoteAddr, int timeout) + throws IOException, SocketTimeoutException { + if (DBG) log("connect(remoteAddr, timeout) EX DEPRECATED"); + } + + /** + * Connects this socket to the given remote host address and port specified + * by the SocketAddress. + * TODO add comment on all these that the network selection happens during connect + * and may take 30 seconds + * @deprecated Use {@code connect(String dstName, int dstPort)} + * Using this method may result in reduced functionality. + * @param remoteAddr the address and port of the remote host to connect to. + * @throws IllegalArgumentException if the SocketAddress is invalid or not supported. + * @throws IOException if the socket is already connected or an error occurs + * while connecting + */ + @Override + @Deprecated + public void connect(SocketAddress remoteAddr) throws IOException { + if (DBG) log("connect(remoteAddr) EX DEPRECATED"); + } + + /** + * Connect a duplicate socket socket to the same remote host address and port + * as the original. + * @throws IOException if the socket is already connected or an error occurs + * while connecting + */ + public void connect() throws IOException { + if (DBG) log("connect() EX"); + } + + /** + * Closes the socket. It is not possible to reconnect or rebind to this + * socket thereafter which means a new socket instance has to be created. + * @throws IOException if an error occurs while closing the socket + */ + @Override + public synchronized void close() throws IOException { + if (DBG) log("close() EX"); + } + + /** + * Request that a new LinkSocket be created using a different radio + * (such as WiFi or 3G) than the current LinkSocket. If a different + * radio is available a call back will be made via {@code onBetterLinkAvail}. + * If unable to find a better radio, application will be notified via + * {@code onNewLinkUnavailable} + * @see LinkSocketNotifier#onBetterLinkAvailable(LinkSocket, LinkSocket) + * @param linkRequestReason reason for requesting a new link. + */ + public void requestNewLink(LinkRequestReason linkRequestReason) { + if (DBG) log("requestNewLink(linkRequestReason) EX"); + } + + /** + * @deprecated LinkSocket will automatically pick the optimum interface + * to bind to + * @param localAddr the specific address and port on the local machine + * to bind to + * @throws IOException always as this method is deprecated for LinkSocket + */ + @Override + @Deprecated + public void bind(SocketAddress localAddr) throws IOException { + if (DBG) log("bind(localAddr) EX throws IOException"); + throw new IOException("bind is deprecated for LinkSocket"); + } + + /** + * Reason codes an application can specify when requesting for a new link. + * TODO: need better documentation + */ + public static final class LinkRequestReason { + /** No constructor */ + private LinkRequestReason() {} + + /** This link is working properly */ + public static final int LINK_PROBLEM_NONE = 0; + /** This link has an unknown issue */ + public static final int LINK_PROBLEM_UNKNOWN = 1; + } + + /** + * Debug logging + */ + protected static void log(String s) { + Log.d(TAG, s); + } +} diff --git a/core/java/android/net/LinkSocketNotifier.java b/core/java/android/net/LinkSocketNotifier.java new file mode 100644 index 0000000000000..183c767dd763b --- /dev/null +++ b/core/java/android/net/LinkSocketNotifier.java @@ -0,0 +1,88 @@ +/* + * 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 android.net; + +import java.util.Map; + +/** + * Interface used to get feedback about a {@link android.net.LinkSocket}. Instance is optionally + * passed when a LinkSocket is constructed. Multiple LinkSockets may use the same notifier. + * @hide + */ +public interface LinkSocketNotifier { + /** + * This callback function will be called if a better link + * becomes available. + * TODO - this shouldn't be checked for all cases - what's the conditional + * flag? + * If the duplicate socket is accepted, the original will be marked invalid + * and additional use will throw exceptions. + * @param original the original LinkSocket + * @param duplicate the new LinkSocket that better meets the application + * requirements + * @return {@code true} if the application intends to use this link + * + * REM + * TODO - how agressive should we be? + * At a minimum CS tracks which LS have this turned on and tracks the requirements + * When a new link becomes available, automatically check if any of the LinkSockets + * will care. + * If found, grab a refcount on the link so it doesn't go away and send notification + * Optionally, periodically setup connection on available networks to check for better links + * Maybe pass this info into the LinkFactories so condition changes can be acted on more quickly + */ + public boolean onBetterLinkAvailable(LinkSocket original, LinkSocket duplicate); + + /** + * This callback function will be called when a LinkSocket no longer has + * an active link. + * @param socket the LinkSocket that lost its link + * + * REM + * NetworkStateTracker tells us it is disconnected + * CS checks the table for LS on that link + * CS calls each callback (need to work out p2p cross process callback) + */ + public void onLinkLost(LinkSocket socket); + + /** + * This callback function will be called when an application calls + * requestNewLink on a LinkSocket but the LinkSocket is unable to find + * a suitable new link. + * @param socket the LinkSocket for which a new link was not found + * TODO - why the diff between initial request (sync) and requestNewLink? + * + * REM + * CS process of trying to find a new link must track the LS that started it + * on failure, call callback + */ + public void onNewLinkUnavailable(LinkSocket socket); + + /** + * This callback function will be called when any of the notification-marked + * capabilities of the LinkSocket (e.g. upstream bandwidth) have changed. + * @param socket the linkSocet for which capabilities have changed + * @param changedCapabilities the set of capabilities that the application + * is interested in and have changed (with new values) + * + * REM + * Maybe pass the interesting capabilities into the Links. + * Get notified of every capability change + * check for LinkSockets on that Link that are interested in that Capability - call them + */ + public void onCapabilityChanged(LinkSocket socket, LinkCapabilities changedCapabilities); +} diff --git a/core/tests/coretests/src/android/net/LinkSocketTest.java b/core/tests/coretests/src/android/net/LinkSocketTest.java new file mode 100644 index 0000000000000..af77d634024ab --- /dev/null +++ b/core/tests/coretests/src/android/net/LinkSocketTest.java @@ -0,0 +1,44 @@ +/* + * 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 android.net; + +import android.net.LinkSocket; +import android.test.suitebuilder.annotation.SmallTest; +import junit.framework.TestCase; + +/** + * Test LinkSocket + */ +public class LinkSocketTest extends TestCase { + + @SmallTest + public void testBasic() throws Exception { + LinkSocket ls; + + ls = new LinkSocket(); + ls.close(); + } + + @SmallTest + public void testLinkCapabilities() throws Exception { + LinkCapabilities lc; + + lc = new LinkCapabilities(); + assertEquals(0, lc.size()); + assertEquals(true, lc.isEmpty()); + } +}