diff options
12 files changed, 1211 insertions, 699 deletions
diff --git a/cmds/svc/src/com/android/commands/svc/DataCommand.java b/cmds/svc/src/com/android/commands/svc/DataCommand.java index 72cb86d..406e33b 100644 --- a/cmds/svc/src/com/android/commands/svc/DataCommand.java +++ b/cmds/svc/src/com/android/commands/svc/DataCommand.java @@ -36,9 +36,7 @@ public class DataCommand extends Svc.Command { return shortHelp() + "\n" + "\n" + "usage: svc data [enable|disable]\n" - + " Turn mobile data on or off.\n\n" - + " svc data prefer\n" - + " Set mobile as the preferred data network\n"; + + " Turn mobile data on or off.\n\n"; } public void run(String[] args) { @@ -51,15 +49,6 @@ public class DataCommand extends Svc.Command { } else if ("disable".equals(args[1])) { flag = false; validCommand = true; - } else if ("prefer".equals(args[1])) { - IConnectivityManager connMgr = - IConnectivityManager.Stub.asInterface(ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); - try { - connMgr.setNetworkPreference(ConnectivityManager.TYPE_MOBILE); - } catch (RemoteException e) { - System.err.println("Failed to set preferred network: " + e); - } - return; } if (validCommand) { ITelephony phoneMgr @@ -78,4 +67,4 @@ public class DataCommand extends Svc.Command { } System.err.println(longHelp()); } -}
\ No newline at end of file +} diff --git a/cmds/svc/src/com/android/commands/svc/WifiCommand.java b/cmds/svc/src/com/android/commands/svc/WifiCommand.java index d29e8b2..39f0e35 100644 --- a/cmds/svc/src/com/android/commands/svc/WifiCommand.java +++ b/cmds/svc/src/com/android/commands/svc/WifiCommand.java @@ -36,9 +36,7 @@ public class WifiCommand extends Svc.Command { return shortHelp() + "\n" + "\n" + "usage: svc wifi [enable|disable]\n" - + " Turn Wi-Fi on or off.\n\n" - + " svc wifi prefer\n" - + " Set Wi-Fi as the preferred data network\n"; + + " Turn Wi-Fi on or off.\n\n"; } public void run(String[] args) { @@ -51,15 +49,6 @@ public class WifiCommand extends Svc.Command { } else if ("disable".equals(args[1])) { flag = false; validCommand = true; - } else if ("prefer".equals(args[1])) { - IConnectivityManager connMgr = - IConnectivityManager.Stub.asInterface(ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); - try { - connMgr.setNetworkPreference(ConnectivityManager.TYPE_WIFI); - } catch (RemoteException e) { - System.err.println("Failed to set preferred network: " + e); - } - return; } if (validCommand) { IWifiManager wifiMgr @@ -75,4 +64,4 @@ public class WifiCommand extends Svc.Command { } System.err.println(longHelp()); } -}
\ No newline at end of file +} diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 2406cba..1ee4ec0 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -534,38 +534,32 @@ public class ConnectivityManager { /** * Specifies the preferred network type. When the device has more * than one type available the preferred network type will be used. - * Note that this made sense when we only had 2 network types, - * but with more and more default networks we need an array to list - * their ordering. This will be deprecated soon. * * @param preference the network type to prefer over all others. It is * unspecified what happens to the old preferred network in the * overall ordering. + * @Deprecated Functionality has been removed as it no longer makes sense, + * with many more than two networks - we'd need an array to express + * preference. Instead we use dynamic network properties of + * the networks to describe their precedence. */ public void setNetworkPreference(int preference) { - try { - mService.setNetworkPreference(preference); - } catch (RemoteException e) { - } } /** * Retrieves the current preferred network type. - * Note that this made sense when we only had 2 network types, - * but with more and more default networks we need an array to list - * their ordering. This will be deprecated soon. * * @return an integer representing the preferred network type * * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. + * @Deprecated Functionality has been removed as it no longer makes sense, + * with many more than two networks - we'd need an array to express + * preference. Instead we use dynamic network properties of + * the networks to describe their precedence. */ public int getNetworkPreference() { - try { - return mService.getNetworkPreference(); - } catch (RemoteException e) { - return -1; - } + return -1; } /** @@ -723,13 +717,14 @@ public class ConnectivityManager { * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}. * {@hide} */ - public boolean setRadios(boolean turnOn) { - try { - return mService.setRadios(turnOn); - } catch (RemoteException e) { - return false; - } - } +// TODO - check for any callers and remove +// public boolean setRadios(boolean turnOn) { +// try { +// return mService.setRadios(turnOn); +// } catch (RemoteException e) { +// return false; +// } +// } /** * Tells a given networkType to set its radio power state as directed. @@ -743,13 +738,14 @@ public class ConnectivityManager { * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}. * {@hide} */ - public boolean setRadio(int networkType, boolean turnOn) { - try { - return mService.setRadio(networkType, turnOn); - } catch (RemoteException e) { - return false; - } - } +// TODO - check for any callers and remove +// public boolean setRadio(int networkType, boolean turnOn) { +// try { +// return mService.setRadio(networkType, turnOn); +// } catch (RemoteException e) { +// return false; +// } +// } /** * Tells the underlying networking system that the caller wants to @@ -1594,4 +1590,81 @@ public class ConnectivityManager { mService.registerNetworkFactory(messenger); } catch (RemoteException e) { } } + + /** {@hide} */ + public void registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, + NetworkCapabilities nc, int score) { + try { + mService.registerNetworkAgent(messenger, ni, lp, nc, score); + } catch (RemoteException e) { } + } + + /** Interface for NetworkRequest callbacks {@hide} */ + public static class NetworkCallbacks { + public static final int PRECHECK = 1; + public static final int AVAILABLE = 2; + public static final int LOSING = 3; + public static final int LOST = 4; + public static final int UNAVAIL = 5; + public static final int CAP_CHANGED = 6; + public static final int PROP_CHANGED = 7; + public static final int CANCELED = 8; + + /** + * @hide + * Called whenever the framework connects to a network that it may use to + * satisfy this request + */ + public void onPreCheck(NetworkRequest networkRequest, Network network) {} + + /** + * Called when the framework connects and has validated the new network. + */ + public void onAvailable(NetworkRequest networkRequest, Network network) {} + + /** + * Called when the framework is losing the network. Often paired with an + * onAvailable call with the new replacement network for graceful handover. + * This may not be called if we have a hard loss (loss without warning). + * This may be followed by either an onLost call or an onAvailable call for this + * network depending on if we lose or regain it. + */ + public void onLosing(NetworkRequest networkRequest, Network network, int maxSecToLive) {} + + /** + * Called when the framework has a hard loss of the network or when the + * graceful failure ends. Note applications should only request this callback + * if the application is willing to track the Available and Lost callbacks + * together, else the application may think it has no network when it + * really does (A Avail, B Avail, A Lost.. still have B). + */ + public void onLost(NetworkRequest networkRequest, Network network) {} + + /** + * Called if no network is found in the given timeout time. If no timeout is given, + * this will not be called. + */ + public void onUnavailable(NetworkRequest networkRequest) {} + + /** + * Called when the network the framework connected to for this request + * changes capabilities but still satisfies the stated need. + */ + public void onCapabilitiesChanged(NetworkRequest networkRequest, Network network, + NetworkCapabilities networkCapabilities) {} + + /** + * Called when the network the framework connected to for this request + * changes properties. + */ + public void onPropertiesChanged(NetworkRequest networkRequest, Network network, + LinkProperties linkProperties) {} + + /** + * Called when a CancelRequest call concludes and the registered callbacks will + * no longer be used. + */ + public void onCanceled(NetworkRequest networkRequest) {} + } + } diff --git a/core/java/android/net/ConnectivityServiceProtocol.java b/core/java/android/net/ConnectivityServiceProtocol.java index 34ba645..c670166 100644 --- a/core/java/android/net/ConnectivityServiceProtocol.java +++ b/core/java/android/net/ConnectivityServiceProtocol.java @@ -23,15 +23,41 @@ import static com.android.internal.util.Protocol.BASE_CONNECTIVITY_SERVICE; * @hide */ public class ConnectivityServiceProtocol { - private ConnectivityServiceProtocol() {} private static final int BASE = BASE_CONNECTIVITY_SERVICE; + private ConnectivityServiceProtocol() {} + + /** + * This is a contract between ConnectivityService and various bearers. + * A NetworkFactory is an abstract entity that creates NetworkAgent objects. + * The bearers register with ConnectivityService using + * ConnectivityManager.registerNetworkFactory, where they pass in a Messenger + * to be used to deliver the following Messages. + */ public static class NetworkFactoryProtocol { private NetworkFactoryProtocol() {} /** - * Pass a network request to the transport + * Pass a network request to the bearer. If the bearer believes it can + * satisfy the request it should connect to the network and create a + * NetworkAgent. Once the NetworkAgent is fully functional it will + * register itself with ConnectivityService using registerNetworkAgent. + * If the bearer cannot immediately satisfy the request (no network, + * user disabled the radio, lower-scored network) it should remember + * any NetworkRequests it may be able to satisfy in the future. It may + * disregard any that it will never be able to service, for example + * those requiring a different bearer. * msg.obj = NetworkRequest + * msg.arg1 = score - the score of the any network currently satisfying this + * request. If this bearer knows in advance it cannot + * exceed this score it should not try to connect, holding the request + * for the future. + * Note that subsequent events may give a different (lower + * or higher) score for this request, transmitted to each + * NetworkFactory through additional CMD_REQUEST_NETWORK msgs + * with the same NetworkRequest but an updated score. + * Also, network conditions may change for this bearer + * allowing for a better score in the future. */ public static final int CMD_REQUEST_NETWORK = BASE; @@ -42,7 +68,42 @@ public class ConnectivityServiceProtocol { public static final int CMD_CANCEL_REQUEST = BASE + 1; } - public static class NetworkAgentProtocol { - private NetworkAgentProtocol() {} + /** + * TODO - move to NetworkMonitor and document + */ + public static class NetworkMonitorProtocol { + private NetworkMonitorProtocol() {} + /** + * Inform NetworkMonitor that their network is connected. + * Initiates Network Validation. + */ + public static final int CMD_NETWORK_CONNECTED = BASE + 200; + + /** + * Inform ConnectivityService that the network is validated. + * obj = NetworkAgent + */ + public static final int EVENT_NETWORK_VALIDATED = BASE + 201; + + /** + * Inform NetworkMonitor to linger a network. The Monitor should + * start a timer and/or start watching for zero live connections while + * moving towards LINGER_COMPLETE. After the Linger period expires + * (or other events mark the end of the linger state) the LINGER_COMPLETE + * event should be sent to ConnectivityService and ConnectivityService + * will shut down the network, telling the corresponding NetworkAgent + * to disconnect. If a CMD_NETWORK_CONNECTED happens before the LINGER completes + * it indicates further desire to keep the network alive and so + * the LINGER is aborted. + * TODO - figure out who manages/does this simple state machine + */ + public static final int CMD_NETWORK_LINGER = BASE + 202; + + /** + * Inform ConnectivityService that the network LINGER period has + * expired. + * obj = NetworkAgent + */ + public static final int EVENT_NETWORK_LINGER_COMPLETE = BASE + 203; } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index b69797e..0d2e14d 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -18,6 +18,7 @@ package android.net; import android.net.LinkQualityInfo; import android.net.LinkProperties; +import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkQuotaInfo; import android.net.NetworkState; @@ -41,10 +42,6 @@ interface IConnectivityManager // Keep this in sync with framework/native/services/connectivitymanager/ConnectivityManager.h void markSocketAsUser(in ParcelFileDescriptor socket, int uid); - void setNetworkPreference(int pref); - - int getNetworkPreference(); - NetworkInfo getActiveNetworkInfo(); NetworkInfo getActiveNetworkInfoForUid(int uid); NetworkInfo getNetworkInfo(int networkType); @@ -62,10 +59,6 @@ interface IConnectivityManager NetworkQuotaInfo getActiveNetworkQuotaInfo(); boolean isActiveNetworkMetered(); - boolean setRadios(boolean onOff); - - boolean setRadio(int networkType, boolean turnOn); - int startUsingNetworkFeature(int networkType, in String feature, in IBinder binder); @@ -147,9 +140,12 @@ interface IConnectivityManager LinkQualityInfo[] getAllLinkQualityInfo(); - void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, in String url); + void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, + in String url); void setAirplaneMode(boolean enable); void registerNetworkFactory(in Messenger messenger); + + void registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, in NetworkCapabilities nc, int score); } diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java new file mode 100644 index 0000000..4b85398 --- /dev/null +++ b/core/java/android/net/NetworkAgent.java @@ -0,0 +1,397 @@ +/* + * 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 android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.Messenger; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; +import android.util.SparseArray; + +import com.android.internal.util.AsyncChannel; +import com.android.internal.util.Protocol; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * A Utility class for handling NetworkRequests. + * + * Created by bearer-specific code to handle tracking requests, scores, + * network data and handle communicating with ConnectivityService. Two + * abstract methods: connect and disconnect are used to act on the + * underlying bearer code. Connect is called when we have a NetworkRequest + * and our score is better than the current handling network's score, while + * disconnect is used when ConnectivityService requests a disconnect. + * + * A bearer may have more than one NetworkAgent if it can simultaneously + * support separate networks (IMS / Internet / MMS Apns on cellular, or + * perhaps connections with different SSID or P2P for Wi-Fi). The bearer + * code should pass its NetworkAgents the NetworkRequests each NetworkAgent + * can handle, demultiplexing for different network types. The bearer code + * can also filter out requests it can never handle. + * + * Each NetworkAgent needs to be given a score and NetworkCapabilities for + * their potential network. While disconnected, the NetworkAgent will check + * each time its score changes or a NetworkRequest changes to see if + * the NetworkAgent can provide a higher scored network for a NetworkRequest + * that the NetworkAgent's NetworkCapabilties can satisfy. This condition will + * trigger a connect request via connect(). After connection, connection data + * should be given to the NetworkAgent by the bearer, including LinkProperties + * NetworkCapabilties and NetworkInfo. After that the NetworkAgent will register + * with ConnectivityService and forward the data on. + * @hide + */ +public abstract class NetworkAgent extends Handler { + private final SparseArray<NetworkRequestAndScore> mNetworkRequests = new SparseArray<>(); + private boolean mConnectionRequested = false; + + private AsyncChannel mAsyncChannel; + private final String LOG_TAG; + private static final boolean DBG = true; + // TODO - this class shouldn't cache data or it runs the risk of getting out of sync + // Make the API require each of these when any is updated so we have the data we need, + // without caching. + private LinkProperties mLinkProperties; + private NetworkInfo mNetworkInfo; + private NetworkCapabilities mNetworkCapabilities; + private int mNetworkScore; + private boolean mRegistered = false; + private final Context mContext; + private AtomicBoolean mHasRequests = new AtomicBoolean(false); + + // TODO - add a name member for logging purposes. + + protected final Object mLockObj = new Object(); + + + private static final int BASE = Protocol.BASE_NETWORK_AGENT; + + /** + * Sent by self to queue up a new/modified request. + * obj = NetworkRequestAndScore + */ + private static final int CMD_ADD_REQUEST = BASE + 1; + + /** + * Sent by self to queue up the removal of a request. + * obj = NetworkRequest + */ + private static final int CMD_REMOVE_REQUEST = BASE + 2; + + /** + * Sent by ConnectivityService to the NetworkAgent to inform it of + * suspected connectivity problems on its network. The NetworkAgent + * should take steps to verify and correct connectivity. + */ + public static final int CMD_SUSPECT_BAD = BASE + 3; + + /** + * Sent by the NetworkAgent (note the EVENT vs CMD prefix) to + * ConnectivityService to pass the current NetworkInfo (connection state). + * Sent when the NetworkInfo changes, mainly due to change of state. + * obj = NetworkInfo + */ + public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 4; + + /** + * Sent by the NetworkAgent to ConnectivityService to pass the current + * NetworkCapabilties. + * obj = NetworkCapabilities + */ + public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 5; + + /** + * Sent by the NetworkAgent to ConnectivityService to pass the current + * NetworkProperties. + * obj = NetworkProperties + */ + public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 6; + + /** + * Sent by the NetworkAgent to ConnectivityService to pass the current + * network score. + * arg1 = network score int + */ + public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 7; + + public NetworkAgent(Looper looper, Context context, String logTag) { + super(looper); + LOG_TAG = logTag; + mContext = context; + } + + /** + * When conditions are right, register with ConnectivityService. + * Connditions include having a well defined network and a request + * that justifies it. The NetworkAgent will remain registered until + * disconnected. + * TODO - this should have all data passed in rather than caching + */ + private void registerSelf() { + synchronized(mLockObj) { + if (!mRegistered && mConnectionRequested && + mNetworkInfo != null && mNetworkInfo.isConnected() && + mNetworkCapabilities != null && + mLinkProperties != null && + mNetworkScore != 0) { + if (DBG) log("Registering NetworkAgent"); + mRegistered = true; + ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( + Context.CONNECTIVITY_SERVICE); + cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(mNetworkInfo), + new LinkProperties(mLinkProperties), + new NetworkCapabilities(mNetworkCapabilities), mNetworkScore); + } else if (DBG && !mRegistered) { + String err = "Not registering due to "; + if (mConnectionRequested == false) err += "no Connect requested "; + if (mNetworkInfo == null) err += "null NetworkInfo "; + if (mNetworkInfo != null && mNetworkInfo.isConnected() == false) { + err += "NetworkInfo disconnected "; + } + if (mLinkProperties == null) err += "null LinkProperties "; + if (mNetworkCapabilities == null) err += "null NetworkCapabilities "; + if (mNetworkScore == 0) err += "null NetworkScore"; + log(err); + } + } + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { + synchronized (mLockObj) { + if (mAsyncChannel != null) { + log("Received new connection while already connected!"); + } else { + if (DBG) log("NetworkAgent fully connected"); + mAsyncChannel = new AsyncChannel(); + mAsyncChannel.connected(null, this, msg.replyTo); + mAsyncChannel.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, + AsyncChannel.STATUS_SUCCESSFUL); + } + } + break; + } + case AsyncChannel.CMD_CHANNEL_DISCONNECT: { + if (DBG) log("CMD_CHANNEL_DISCONNECT"); + if (mAsyncChannel != null) mAsyncChannel.disconnect(); + break; + } + case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { + if (DBG) log("NetworkAgent channel lost"); + disconnect(); + clear(); + break; + } + case CMD_SUSPECT_BAD: { + log("Unhandled Message " + msg); + break; + } + case CMD_ADD_REQUEST: { + handleAddRequest(msg); + break; + } + case CMD_REMOVE_REQUEST: { + handleRemoveRequest(msg); + break; + } + } + } + + private void clear() { + synchronized(mLockObj) { + mNetworkRequests.clear(); + mHasRequests.set(false); + mConnectionRequested = false; + mAsyncChannel = null; + mRegistered = false; + } + } + + private static class NetworkRequestAndScore { + NetworkRequest req; + int score; + + NetworkRequestAndScore(NetworkRequest networkRequest, int score) { + req = networkRequest; + this.score = score; + } + } + + private void handleAddRequest(Message msg) { + NetworkRequestAndScore n = (NetworkRequestAndScore)msg.obj; + // replaces old request, updating score + mNetworkRequests.put(n.req.requestId, n); + mHasRequests.set(true); + evalScores(); + } + + private void handleRemoveRequest(Message msg) { + NetworkRequest networkRequest = (NetworkRequest)msg.obj; + + if (mNetworkRequests.get(networkRequest.requestId) != null) { + mNetworkRequests.remove(networkRequest.requestId); + if (mNetworkRequests.size() == 0) mHasRequests.set(false); + evalScores(); + } + } + + /** + * called to go through our list of requests and see if we're + * good enough to try connecting. + * + * Only does connects - we disconnect when requested via + * CMD_CHANNEL_DISCONNECTED, generated by either a loss of connection + * between modules (bearer or ConnectivityService dies) or more commonly + * when the NetworkInfo reports to ConnectivityService it is disconnected. + */ + private void evalScores() { + if (mConnectionRequested) { + // already trying + return; + } + for (int i=0; i < mNetworkRequests.size(); i++) { + int score = mNetworkRequests.valueAt(i).score; + if (score < mNetworkScore) { + // have a request that has a lower scored network servicing it + // (or no network) than we could provide, so lets connect! + mConnectionRequested = true; + connect(); + return; + } + } + } + + public void addNetworkRequest(NetworkRequest networkRequest, int score) { + if (DBG) log("adding NetworkRequest " + networkRequest + " with score " + score); + sendMessage(obtainMessage(CMD_ADD_REQUEST, + new NetworkRequestAndScore(networkRequest, score))); + } + + public void removeNetworkRequest(NetworkRequest networkRequest) { + if (DBG) log("removing NetworkRequest " + networkRequest); + sendMessage(obtainMessage(CMD_REMOVE_REQUEST, networkRequest)); + } + + /** + * Called by the bearer code when it has new LinkProperties data. + * If we're a registered NetworkAgent, this new data will get forwarded on, + * otherwise we store a copy in anticipation of registering. This call + * may also prompt registration if it causes the NetworkAgent to meet + * the conditions (fully configured, connected, satisfys a request and + * has sufficient score). + */ + public void sendLinkProperties(LinkProperties linkProperties) { + linkProperties = new LinkProperties(linkProperties); + synchronized(mLockObj) { + mLinkProperties = linkProperties; + if (mAsyncChannel != null) { + mAsyncChannel.sendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, linkProperties); + } else { + registerSelf(); + } + } + } + + /** + * Called by the bearer code when it has new NetworkInfo data. + * If we're a registered NetworkAgent, this new data will get forwarded on, + * otherwise we store a copy in anticipation of registering. This call + * may also prompt registration if it causes the NetworkAgent to meet + * the conditions (fully configured, connected, satisfys a request and + * has sufficient score). + */ + public void sendNetworkInfo(NetworkInfo networkInfo) { + networkInfo = new NetworkInfo(networkInfo); + synchronized(mLockObj) { + mNetworkInfo = networkInfo; + if (mAsyncChannel != null) { + mAsyncChannel.sendMessage(EVENT_NETWORK_INFO_CHANGED, networkInfo); + } else { + registerSelf(); + } + } + } + + /** + * Called by the bearer code when it has new NetworkCapabilities data. + * If we're a registered NetworkAgent, this new data will get forwarded on, + * otherwise we store a copy in anticipation of registering. This call + * may also prompt registration if it causes the NetworkAgent to meet + * the conditions (fully configured, connected, satisfys a request and + * has sufficient score). + * Note that if these capabilities make the network non-useful, + * ConnectivityServce will tear this network down. + */ + public void sendNetworkCapabilities(NetworkCapabilities networkCapabilities) { + networkCapabilities = new NetworkCapabilities(networkCapabilities); + synchronized(mLockObj) { + mNetworkCapabilities = networkCapabilities; + if (mAsyncChannel != null) { + mAsyncChannel.sendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, networkCapabilities); + } else { + registerSelf(); + } + } + } + + public NetworkCapabilities getNetworkCapabilities() { + synchronized(mLockObj) { + return new NetworkCapabilities(mNetworkCapabilities); + } + } + + /** + * Called by the bearer code when it has a new score for this network. + * If we're a registered NetworkAgent, this new data will get forwarded on, + * otherwise we store a copy. + */ + public synchronized void sendNetworkScore(int score) { + synchronized(mLockObj) { + mNetworkScore = score; + evalScores(); + if (mAsyncChannel != null) { + mAsyncChannel.sendMessage(EVENT_NETWORK_SCORE_CHANGED, mNetworkScore); + } else { + registerSelf(); + } + } + } + + public boolean hasRequests() { + return mHasRequests.get(); + } + + public boolean isConnectionRequested() { + synchronized(mLockObj) { + return mConnectionRequested; + } + } + + + abstract protected void connect(); + abstract protected void disconnect(); + + protected void log(String s) { + Log.d(LOG_TAG, "NetworkAgent: " + s); + } +} diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 7e3a06d..b3ae3f5 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -25,23 +25,55 @@ import java.util.concurrent.atomic.AtomicInteger; * @hide */ public class NetworkRequest implements Parcelable { + /** + * The NetworkCapabilities that define this request + */ public final NetworkCapabilities networkCapabilities; + + /** + * Identifies the request. NetworkRequests should only be constructed by + * the Framework and given out to applications as tokens to be used to identify + * the request. + * TODO - make sure this input is checked whenever a NR is passed in a public API + */ public final int requestId; - public final boolean legacy; - private static final AtomicInteger sRequestId = new AtomicInteger(); + /** + * Set for legacy requests and the default. + * Causes CONNECTIVITY_ACTION broadcasts to be sent. + * @hide + */ + public final boolean needsBroadcasts; + + private static final AtomicInteger sNextRequestId = new AtomicInteger(1); + + /** + * @hide + */ public NetworkRequest(NetworkCapabilities nc) { - this(nc, false, sRequestId.incrementAndGet()); + this(nc, false, sNextRequestId.getAndIncrement()); } - public NetworkRequest(NetworkCapabilities nc, boolean legacy) { - this(nc, legacy, sRequestId.incrementAndGet()); + /** + * @hide + */ + public NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts) { + this(nc, needsBroadcasts, sNextRequestId.getAndIncrement()); } - private NetworkRequest(NetworkCapabilities nc, boolean legacy, int rId) { + /** + * @hide + */ + private NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts, int rId) { requestId = rId; networkCapabilities = nc; - this.legacy = legacy; + this.needsBroadcasts = needsBroadcasts; + } + + public NetworkRequest(NetworkRequest that) { + networkCapabilities = new NetworkCapabilities(that.networkCapabilities); + requestId = that.requestId; + needsBroadcasts = that.needsBroadcasts; } // implement the Parcelable interface @@ -50,16 +82,17 @@ public class NetworkRequest implements Parcelable { } public void writeToParcel(Parcel dest, int flags) { dest.writeParcelable(networkCapabilities, flags); - dest.writeInt(legacy ? 1 : 0); + dest.writeInt(needsBroadcasts ? 1 : 0); dest.writeInt(requestId); } public static final Creator<NetworkRequest> CREATOR = new Creator<NetworkRequest>() { public NetworkRequest createFromParcel(Parcel in) { NetworkCapabilities nc = (NetworkCapabilities)in.readParcelable(null); - boolean legacy = (in.readInt() == 1); + boolean needsBroadcasts = (in.readInt() == 1); int requestId = in.readInt(); - return new NetworkRequest(nc, legacy, requestId); + NetworkRequest result = new NetworkRequest(nc, needsBroadcasts, requestId); + return result; } public NetworkRequest[] newArray(int size) { return new NetworkRequest[size]; @@ -67,14 +100,14 @@ public class NetworkRequest implements Parcelable { }; public String toString() { - return "NetworkRequest [ id=" + requestId + ", legacy=" + legacy + ", " + - networkCapabilities.toString() + " ]"; + return "NetworkRequest [ id=" + requestId + ", needsBroadcasts=" + needsBroadcasts + + ", " + networkCapabilities.toString() + " ]"; } public boolean equals(Object obj) { if (obj instanceof NetworkRequest == false) return false; NetworkRequest that = (NetworkRequest)obj; - return (that.legacy == this.legacy && + return (that.needsBroadcasts == this.needsBroadcasts && that.requestId == this.requestId && ((that.networkCapabilities == null && this.networkCapabilities == null) || (that.networkCapabilities != null && @@ -82,6 +115,7 @@ public class NetworkRequest implements Parcelable { } public int hashCode() { - return requestId + (legacy ? 1013 : 2026) + (networkCapabilities.hashCode() * 1051); + return requestId + (needsBroadcasts ? 1013 : 2026) + + (networkCapabilities.hashCode() * 1051); } } diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java index 0937ec3..4c4c76f 100644 --- a/core/java/com/android/internal/util/Protocol.java +++ b/core/java/com/android/internal/util/Protocol.java @@ -56,5 +56,6 @@ public class Protocol { public static final int BASE_NSD_MANAGER = 0x00060000; public static final int BASE_NETWORK_STATE_TRACKER = 0x00070000; public static final int BASE_CONNECTIVITY_SERVICE = 0x00080000; + public static final int BASE_NETWORK_AGENT = 0x00081000; //TODO: define all used protocols } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 1cb873e..cdb82e7 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -20,6 +20,7 @@ import static android.Manifest.permission.MANAGE_NETWORK_POLICY; import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; +import static android.net.ConnectivityManager.NetworkCallbacks; import static android.net.ConnectivityManager.TYPE_BLUETOOTH; import static android.net.ConnectivityManager.TYPE_DUMMY; import static android.net.ConnectivityManager.TYPE_ETHERNET; @@ -30,6 +31,7 @@ import static android.net.ConnectivityManager.TYPE_PROXY; import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.ConnectivityManager.isNetworkTypeValid; import static android.net.ConnectivityServiceProtocol.NetworkFactoryProtocol; +import static android.net.ConnectivityServiceProtocol.NetworkMonitorProtocol; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; @@ -67,6 +69,7 @@ import android.net.LinkProperties.CompareResult; import android.net.LinkQualityInfo; import android.net.MobileDataStateTracker; import android.net.Network; +import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.net.NetworkConfig; import android.net.NetworkInfo; @@ -82,7 +85,6 @@ import android.net.ProxyInfo; import android.net.RouteInfo; import android.net.SamplingDataTracker; import android.net.Uri; -import android.net.wifi.WifiStateTracker; import android.net.wimax.WimaxManagerConstants; import android.os.AsyncTask; import android.os.Binder; @@ -128,6 +130,7 @@ import com.android.internal.util.XmlUtils; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.Nat464Xlat; +import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.PacManager; import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; @@ -179,7 +182,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final String TAG = "ConnectivityService"; private static final boolean DBG = true; - private static final boolean VDBG = false; + private static final boolean VDBG = true; // STOPSHIP private static final boolean LOGD_RULES = false; @@ -306,12 +309,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED = 2; /** - * used internally to change our network preference setting - * arg1 = networkType to prefer - */ - private static final int EVENT_SET_NETWORK_PREFERENCE = 3; - - /** * used internally to synchronize inet condition reports * arg1 = networkType * arg2 = condition (0 bad, 100 good) @@ -382,10 +379,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int EVENT_REGISTER_NETWORK_FACTORY = 17; + /** + * used internally when registering NetworkAgents + * obj = Messenger + */ + private static final int EVENT_REGISTER_NETWORK_AGENT = 18; + /** Handler used for internal events. */ - private InternalHandler mHandler; + final private InternalHandler mHandler; /** Handler used for incoming {@link NetworkStateTracker} events. */ - private NetworkStateTrackerHandler mTrackerHandler; + final private NetworkStateTrackerHandler mTrackerHandler; // list of DeathRecipients used to make sure features are turned off when // a process dies @@ -474,8 +477,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); - NetworkRequest netRequest = new NetworkRequest(netCap); - mNetworkRequests.append(netRequest.requestId, netRequest); + mDefaultRequest = new NetworkRequest(netCap, true); + mNetworkRequests.append(mDefaultRequest.requestId, mDefaultRequest); HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread"); handlerThread.start(); @@ -624,21 +627,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - // Update mNetworkPreference according to user mannually first then overlay config.xml - mNetworkPreference = getPersistedNetworkPreference(); - if (mNetworkPreference == -1) { - for (int n : mPriorityList) { - if (mNetConfigs[n].isDefault() && ConnectivityManager.isNetworkTypeValid(n)) { - mNetworkPreference = n; - break; - } - } - if (mNetworkPreference == -1) { - throw new IllegalStateException( - "You should set at least one default Network in config.xml!"); - } - } - mNetRequestersPids = (List<Integer> [])new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1]; for (int i : mPriorityList) { @@ -738,6 +726,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { /** * Factory that creates {@link NetworkStateTracker} instances using given * {@link NetworkConfig}. + * + * TODO - this is obsolete and will be deleted. It's replaced by the + * registerNetworkFactory call and protocol. + * @Deprecated in favor of registerNetworkFactory dynamic bindings */ public interface NetworkFactory { public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config); @@ -755,10 +747,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config) { switch (config.radio) { - case TYPE_WIFI: - return new WifiStateTracker(targetNetworkType, config.name); - case TYPE_MOBILE: - return new MobileDataStateTracker(targetNetworkType, config.name); case TYPE_DUMMY: return new DummyDataStateTracker(targetNetworkType, config.name); case TYPE_BLUETOOTH: @@ -859,41 +847,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { return wimaxStateTracker; } - /** - * Sets the preferred network. - * @param preference the new preference - */ - public void setNetworkPreference(int preference) { - enforceChangePermission(); - - mHandler.sendMessage( - mHandler.obtainMessage(EVENT_SET_NETWORK_PREFERENCE, preference, 0)); - } - - public int getNetworkPreference() { - enforceAccessPermission(); - int preference; - synchronized(this) { - preference = mNetworkPreference; - } - return preference; - } - - private void handleSetNetworkPreference(int preference) { - if (ConnectivityManager.isNetworkTypeValid(preference) && - mNetConfigs[preference] != null && - mNetConfigs[preference].isDefault()) { - if (mNetworkPreference != preference) { - final ContentResolver cr = mContext.getContentResolver(); - Settings.Global.putInt(cr, Settings.Global.NETWORK_PREFERENCE, preference); - synchronized(this) { - mNetworkPreference = preference; - } - enforcePreference(); - } - } - } - private int getConnectivityChangeDelay() { final ContentResolver cr = mContext.getContentResolver(); @@ -905,41 +858,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { defaultDelay); } - private int getPersistedNetworkPreference() { - final ContentResolver cr = mContext.getContentResolver(); - - final int networkPrefSetting = Settings.Global - .getInt(cr, Settings.Global.NETWORK_PREFERENCE, -1); - - return networkPrefSetting; - } - - /** - * Make the state of network connectivity conform to the preference settings - * In this method, we only tear down a non-preferred network. Establishing - * a connection to the preferred network is taken care of when we handle - * the disconnect event from the non-preferred network - * (see {@link #handleDisconnect(NetworkInfo)}). - */ - private void enforcePreference() { - if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected()) - return; - - if (!mNetTrackers[mNetworkPreference].isAvailable()) - return; - - for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) { - if (t != mNetworkPreference && mNetTrackers[t] != null && - mNetTrackers[t].getNetworkInfo().isConnected()) { - if (DBG) { - log("tearing down " + mNetTrackers[t].getNetworkInfo() + - " in enforcePreference"); - } - teardown(mNetTrackers[t]); - } - } - } - private boolean teardown(NetworkStateTracker netTracker) { if (netTracker.teardown()) { netTracker.setTeardownRequested(true); @@ -1192,24 +1110,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { return false; } - public boolean setRadios(boolean turnOn) { - boolean result = true; - enforceChangePermission(); - for (NetworkStateTracker t : mNetTrackers) { - if (t != null) result = t.setRadio(turnOn) && result; - } - return result; - } - - public boolean setRadio(int netType, boolean turnOn) { - enforceChangePermission(); - if (!ConnectivityManager.isNetworkTypeValid(netType)) { - return false; - } - NetworkStateTracker tracker = mNetTrackers[netType]; - return tracker != null && tracker.setRadio(turnOn); - } - private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() { @Override public void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos) { @@ -1929,18 +1829,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } private void handleSetMobileData(boolean enabled) { - if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) { - if (VDBG) { - log(mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled); - } - mNetTrackers[ConnectivityManager.TYPE_MOBILE].setUserDataEnable(enabled); - } - if (mNetTrackers[ConnectivityManager.TYPE_WIMAX] != null) { - if (VDBG) { - log(mNetTrackers[ConnectivityManager.TYPE_WIMAX].toString() + enabled); - } - mNetTrackers[ConnectivityManager.TYPE_WIMAX].setUserDataEnable(enabled); - } + // TODO - handle this - probably generalize passing in a transport type and send to the + // factories? } @Override @@ -1953,12 +1843,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { } private void handleSetPolicyDataEnable(int networkType, boolean enabled) { - if (isNetworkTypeValid(networkType)) { - final NetworkStateTracker tracker = mNetTrackers[networkType]; - if (tracker != null) { - tracker.setPolicyDataEnable(enabled); - } - } + // TODO - handle this passing to factories +// if (isNetworkTypeValid(networkType)) { +// final NetworkStateTracker tracker = mNetTrackers[networkType]; +// if (tracker != null) { +// tracker.setPolicyDataEnable(enabled); +// } +// } } private void enforceAccessPermission() { @@ -2226,67 +2117,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - /** - * Called when an attempt to fail over to another network has failed. - * @param info the {@link NetworkInfo} for the failed network - */ - private void handleConnectionFailure(NetworkInfo info) { - mNetTrackers[info.getType()].setTeardownRequested(false); - - String reason = info.getReason(); - String extraInfo = info.getExtraInfo(); - - String reasonText; - if (reason == null) { - reasonText = "."; - } else { - reasonText = " (" + reason + ")."; - } - loge("Attempt to connect to " + info.getTypeName() + " failed" + reasonText); - - Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); - intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info)); - intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType()); - if (getActiveNetworkInfo() == null) { - intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); - } - if (reason != null) { - intent.putExtra(ConnectivityManager.EXTRA_REASON, reason); - } - if (extraInfo != null) { - intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo); - } - if (info.isFailover()) { - intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); - info.setFailover(false); - } - - if (mNetConfigs[info.getType()].isDefault()) { - tryFailover(info.getType()); - if (mActiveDefaultNetwork != -1) { - NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); - intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); - } else { - mDefaultInetConditionPublished = 0; - intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); - } - } - - intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); - - final Intent immediateIntent = new Intent(intent); - immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE); - sendStickyBroadcast(immediateIntent); - sendStickyBroadcast(intent); - /* - * If the failover network is already connected, then immediately send - * out a followup broadcast indicating successful failover - */ - if (mActiveDefaultNetwork != -1) { - sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo()); - } - } - private void sendStickyBroadcast(Intent intent) { synchronized(this) { if (!mSystemReady) { @@ -2478,33 +2308,35 @@ public class ConnectivityService extends IConnectivityManager.Stub { } /** - * Setup data activity tracking for the given network interface. + * Setup data activity tracking for the given network. * * Every {@code setupDataActivityTracking} should be paired with a * {@link #removeDataActivityTracking} for cleanup. */ - private void setupDataActivityTracking(int type) { - final NetworkStateTracker thisNet = mNetTrackers[type]; - final String iface = thisNet.getLinkProperties().getInterfaceName(); + private void setupDataActivityTracking(NetworkAgentInfo networkAgent) { + final String iface = networkAgent.linkProperties.getInterfaceName(); final int timeout; + int type = ConnectivityManager.TYPE_NONE; - if (ConnectivityManager.isNetworkTypeMobile(type)) { + if (networkAgent.networkCapabilities.hasTransport( + NetworkCapabilities.TRANSPORT_CELLULAR)) { timeout = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE, 5); - // Canonicalize mobile network type type = ConnectivityManager.TYPE_MOBILE; - } else if (ConnectivityManager.TYPE_WIFI == type) { + } else if (networkAgent.networkCapabilities.hasTransport( + NetworkCapabilities.TRANSPORT_WIFI)) { timeout = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI, 0); + type = ConnectivityManager.TYPE_WIFI; } else { // do not track any other networks timeout = 0; } - if (timeout > 0 && iface != null) { + if (timeout > 0 && iface != null && type != ConnectivityManager.TYPE_NONE) { try { mNetd.addIdleTimer(iface, timeout, type); } catch (Exception e) { @@ -2517,12 +2349,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { /** * Remove data activity tracking when network disconnects. */ - private void removeDataActivityTracking(int type) { - final NetworkStateTracker net = mNetTrackers[type]; - final String iface = net.getLinkProperties().getInterfaceName(); + private void removeDataActivityTracking(NetworkAgentInfo networkAgent) { + final String iface = networkAgent.linkProperties.getInterfaceName(); + final NetworkCapabilities caps = networkAgent.networkCapabilities; - if (iface != null && (ConnectivityManager.isNetworkTypeMobile(type) || - ConnectivityManager.TYPE_WIFI == type)) { + if (iface != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) || + caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) { try { // the call fails silently if no idletimer setup for this interface mNetd.removeIdleTimer(iface); @@ -2537,8 +2369,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { * concerned with making sure that the list of DNS servers is set up * according to which networks are connected, and ensuring that the * right routing table entries exist. + * + * TODO - delete when we're sure all this functionallity is captured. */ - private void handleConnectivityChange(int netType, boolean doReset) { + private void handleConnectivityChange(int netType, LinkProperties curLp, boolean doReset) { int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0; boolean exempt = ConnectivityManager.isNetworkTypeExempt(netType); if (VDBG) { @@ -2552,7 +2386,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ handleDnsConfigurationChange(netType); - LinkProperties curLp = mCurrentLinkProperties[netType]; LinkProperties newLp = null; if (mNetTrackers[netType].getNetworkInfo().isConnected()) { @@ -2742,26 +2575,30 @@ public class ConnectivityService extends IConnectivityManager.Stub { return routesChanged; } - /** + /** * Reads the network specific MTU size from reources. * and set it on it's iface. */ - private void updateMtuSizeSettings(NetworkStateTracker nt) { - final String iface = nt.getLinkProperties().getInterfaceName(); - final int mtu = nt.getLinkProperties().getMtu(); - - if (mtu < 68 || mtu > 10000) { - loge("Unexpected mtu value: " + mtu + ", " + nt); - return; - } - - try { - if (VDBG) log("Setting MTU size: " + iface + ", " + mtu); - mNetd.setMtu(iface, mtu); - } catch (Exception e) { - Slog.e(TAG, "exception in setMtu()" + e); - } - } + private void updateMtu(LinkProperties newLp, LinkProperties oldLp) { + final String iface = newLp.getInterfaceName(); + final int mtu = newLp.getMtu(); + if (oldLp != null && newLp.isIdenticalMtu(oldLp)) { + if (VDBG) log("identical MTU - not setting"); + return; + } + + if (mtu < 68 || mtu > 10000) { + loge("Unexpected mtu value: " + mtu + ", " + iface); + return; + } + + try { + if (VDBG) log("Setting MTU size: " + iface + ", " + mtu); + mNetd.setMtu(iface, mtu); + } catch (Exception e) { + Slog.e(TAG, "exception in setMtu()" + e); + } + } /** * Reads the network specific TCP buffer sizes from SystemProperties @@ -3053,21 +2890,58 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkInfo info; switch (msg.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { - AsyncChannel ac = (AsyncChannel) msg.obj; - if (mNetworkFactories.contains(ac)) { - if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { - if (VDBG) log("NetworkFactory connected"); - for (int i = 0; i < mNetworkRequests.size(); i++) { - ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, - mNetworkRequests.valueAt(i)); - } - } else { - loge("Error connecting NetworkFactory"); - mNetworkFactories.remove((AsyncChannel) msg.obj); - } + handleAsyncChannelHalfConnect(msg); + break; + } + case AsyncChannel.CMD_CHANNEL_DISCONNECT: { + NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); + if (nai != null) nai.asyncChannel.disconnect(); + break; + } + case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { + handleAsyncChannelDisconnected(msg); + break; + } + case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: { + NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); + if (nai == null) { + loge("EVENT_NETWORK_CAPABILITIES_CHANGED from unknown NetworkAgent"); + } else { + updateCapabilities(nai, (NetworkCapabilities)msg.obj); } break; } + case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: { + NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); + if (nai == null) { + loge("NetworkAgent not found for EVENT_NETWORK_PROPERTIES_CHANGED"); + } else { + LinkProperties oldLp = nai.linkProperties; + nai.linkProperties = (LinkProperties)msg.obj; + updateLinkProperties(nai, oldLp); + } + break; + } + case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: { + NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); + if (nai == null) { + loge("EVENT_NETWORK_INFO_CHANGED from unknown NetworkAgent"); + break; + } + info = (NetworkInfo) msg.obj; + updateNetworkInfo(nai, info); + break; + } + case NetworkMonitorProtocol.EVENT_NETWORK_VALIDATED: { + NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj; + handleConnectionValidated(nai); + break; + } + case NetworkMonitorProtocol.EVENT_NETWORK_LINGER_COMPLETE: { + NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj; + handleLingerComplete(nai); + break; + } case NetworkStateTracker.EVENT_STATE_CHANGED: { info = (NetworkInfo) msg.obj; NetworkInfo.State state = info.getState(); @@ -3100,10 +2974,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { EventLogTags.writeConnectivityStateChanged( info.getType(), info.getSubtype(), info.getDetailedState().ordinal()); - if (info.getDetailedState() == - NetworkInfo.DetailedState.FAILED) { - handleConnectionFailure(info); - } else if (info.isConnectedToProvisioningNetwork()) { + if (info.isConnectedToProvisioningNetwork()) { /** * TODO: Create ConnectivityManager.TYPE_MOBILE_PROVISIONING * for now its an in between network, its a network that @@ -3128,18 +2999,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetTrackers[info.getType()].getNetwork().netId); } } else if (state == NetworkInfo.State.DISCONNECTED) { - handleDisconnect(info); } else if (state == NetworkInfo.State.SUSPENDED) { - // TODO: need to think this over. - // the logic here is, handle SUSPENDED the same as - // DISCONNECTED. The only difference being we are - // broadcasting an intent with NetworkInfo that's - // suspended. This allows the applications an - // opportunity to handle DISCONNECTED and SUSPENDED - // differently, or not. - handleDisconnect(info); } else if (state == NetworkInfo.State.CONNECTED) { - handleConnect(info); + // handleConnect(info); } if (mLockdownTracker != null) { mLockdownTracker.onNetworkInfoChanged(info); @@ -3151,7 +3013,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { // TODO: Temporary allowing network configuration // change not resetting sockets. // @see bug/4455071 - handleConnectivityChange(info.getType(), false); + handleConnectivityChange(info.getType(), mCurrentLinkProperties[info.getType()], + false); break; } case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: { @@ -3164,6 +3027,66 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + private void handleAsyncChannelHalfConnect(Message msg) { + AsyncChannel ac = (AsyncChannel) msg.obj; + if (mNetworkFactories.contains(ac)) { + if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { + if (VDBG) log("NetworkFactory connected"); + // A network factory has connected. Send it all current NetworkRequests. + for (int i = 0; i < mNetworkRequests.size(); i++) { + NetworkRequest request = mNetworkRequests.valueAt(i); + NetworkAgentInfo nai = mNetworkForRequestId.get(request.requestId); + ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, + (nai != null ? nai.currentScore : 0), 0, request); + } + } else { + loge("Error connecting NetworkFactory"); + mNetworkFactories.remove(ac); + } + } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) { + if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { + if (VDBG) log("NetworkAgent connected"); + // A network agent has requested a connection. Establish the connection. + mNetworkAgentInfos.get(msg.replyTo).asyncChannel. + sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); + } else { + loge("Error connecting NetworkAgent"); + mNetworkAgentInfos.remove(msg.replyTo); + } + } + } + private void handleAsyncChannelDisconnected(Message msg) { + NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); + if (nai != null) { + if (DBG) log(nai.name() + " got DISCONNECTED"); + // A network agent has disconnected. + // Tell netd to clean up the configuration for this network + // (routing rules, DNS, etc). + try { + mNetd.removeNetwork(nai.network.netId); + } catch (Exception e) { + loge("Exception removing network: " + e); + } + notifyNetworkCallbacks(nai, NetworkCallbacks.LOST); + mNetworkAgentInfos.remove(nai); + // Since we've lost the network, go through all the requests that + // it was satisfying and see if any other factory can satisfy them. + for (int i = 0; i < nai.networkRequests.size(); i++) { + NetworkRequest request = nai.networkRequests.valueAt(i); + NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId); + if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) { + mNetworkForRequestId.remove(request.requestId); + // TODO Check if any other live network will work + sendUpdatedScoreToFactories(request, 0); + } + } + if (nai.networkRequests.get(mDefaultRequest.requestId) != null) { + removeDataActivityTracking(nai); + } + } + } + + private class InternalHandler extends Handler { public InternalHandler(Looper looper) { super(looper); @@ -3204,11 +3127,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { handleInetConditionHoldEnd(netType, sequence); break; } - case EVENT_SET_NETWORK_PREFERENCE: { - int preference = msg.arg1; - handleSetNetworkPreference(preference); - break; - } case EVENT_SET_MOBILE_DATA: { boolean enabled = (msg.arg1 == ENABLED); handleSetMobileData(enabled); @@ -3266,6 +3184,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { handleRegisterNetworkFactory((Messenger)msg.obj); break; } + case EVENT_REGISTER_NETWORK_AGENT: { + handleRegisterNetworkAgent((NetworkAgentInfo)msg.obj); + break; + } } } } @@ -5112,7 +5034,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { public void registerNetworkFactory(Messenger messenger) { enforceConnectivityInternalPermission(); - mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, messenger)); } @@ -5123,5 +5044,335 @@ public class ConnectivityService extends IConnectivityManager.Stub { ac.connect(mContext, mTrackerHandler, messenger); } + // NetworkRequest by requestId private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<NetworkRequest>(); + + /** + * NetworkAgentInfo supporting a request by requestId. + * These have already been vetted (their Capabilities satisfy the request) + * and the are the highest scored network available. + * the are keyed off the Requests requestId. + */ + private final SparseArray<NetworkAgentInfo> mNetworkForRequestId = + new SparseArray<NetworkAgentInfo>(); + + // NetworkAgentInfo keyed off its connecting messenger + // TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays + private final HashMap<Messenger, NetworkAgentInfo> mNetworkAgentInfos = + new HashMap<Messenger, NetworkAgentInfo>(); + + private final NetworkRequest mDefaultRequest; + + public void registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, + LinkProperties linkProperties, NetworkCapabilities networkCapabilities, + int currentScore) { + enforceConnectivityInternalPermission(); + + NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), nextNetId(), + new NetworkInfo(networkInfo), new LinkProperties(linkProperties), + new NetworkCapabilities(networkCapabilities), currentScore); + + mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai)); + } + + private void handleRegisterNetworkAgent(NetworkAgentInfo na) { + if (VDBG) log("Got NetworkAgent Messenger"); + mNetworkAgentInfos.put(na.messenger, na); + na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger); + NetworkInfo networkInfo = na.networkInfo; + na.networkInfo = null; + updateNetworkInfo(na, networkInfo); + } + + private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties oldLp) { + LinkProperties newLp = networkAgent.linkProperties; + int netId = networkAgent.network.netId; + + updateMtu(newLp, oldLp); + // TODO - figure out what to do for clat +// for (LinkProperties lp : newLp.getStackedLinks()) { +// updateMtu(lp, null); +// } + updateRoutes(newLp, oldLp, netId); + updateDnses(newLp, oldLp, netId); + } + private void updateRoutes(LinkProperties newLp, LinkProperties oldLp, int netId) { + CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>(); + if (oldLp != null) { + routeDiff = oldLp.compareAllRoutes(newLp); + } else if (newLp != null) { + routeDiff.added = newLp.getAllRoutes(); + } + + // add routes before removing old in case it helps with continuous connectivity + + // do this twice, adding non-nexthop routes first, then routes they are dependent on + for (RouteInfo route : routeDiff.added) { + if (route.hasGateway()) continue; + try { + mNetd.addRoute(netId, route); + } catch (Exception e) { + loge("Exception in addRoute for non-gateway: " + e); + } + } + for (RouteInfo route : routeDiff.added) { + if (route.hasGateway() == false) continue; + try { + mNetd.addRoute(netId, route); + } catch (Exception e) { + loge("Exception in addRoute for gateway: " + e); + } + } + + for (RouteInfo route : routeDiff.removed) { + try { + mNetd.removeRoute(netId, route); + } catch (Exception e) { + loge("Exception in removeRoute: " + e); + } + } + } + private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId) { + if (oldLp == null || (newLp.isIdenticalDnses(oldLp) == false)) { + Collection<InetAddress> dnses = newLp.getDnses(); + if (dnses.size() == 0 && mDefaultDns != null) { + dnses = new ArrayList(); + dnses.add(mDefaultDns); + if (DBG) { + loge("no dns provided for netId " + netId + ", so using defaults"); + } + } + try { + mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses), + newLp.getDomains()); + } catch (Exception e) { + loge("Exception in setDnsServersForNetwork: " + e); + } + // TODO - setprop "net.dnsX" + } + } + + private void updateCapabilities(NetworkAgentInfo networkAgent, + NetworkCapabilities networkCapabilities) { + // TODO - what else here? Verify still satisfies everybody? + // Check if satisfies somebody new? call callbacks? + networkAgent.networkCapabilities = networkCapabilities; + } + + private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) { + if (VDBG) log("sending new Min Network Score(" + score + "): " + networkRequest.toString()); + for (AsyncChannel ac : mNetworkFactories) { + ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, networkRequest); + } + } + + private void callCallbackForRequest(NetworkRequest networkRequest, + NetworkAgentInfo networkAgent, int notificationType) { + // TODO + } + + private void handleLingerComplete(NetworkAgentInfo oldNetwork) { + if (oldNetwork == null) { + loge("Unknown NetworkAgentInfo in handleLingerComplete"); + return; + } + if (DBG) log("handleLingerComplete for " + oldNetwork.name()); + if (DBG) { + if (oldNetwork.networkRequests.size() != 0) { + loge("Dead network still had " + oldNetwork.networkRequests.size() + " requests"); + } + } + oldNetwork.asyncChannel.disconnect(); + } + + private void handleConnectionValidated(NetworkAgentInfo newNetwork) { + if (newNetwork == null) { + loge("Unknown NetworkAgentInfo in handleConnectionValidated"); + return; + } + boolean keep = false; + boolean isNewDefault = false; + if (DBG) log("handleConnectionValidated for "+newNetwork.name()); + // check if any NetworkRequest wants this NetworkAgent + // first check if it satisfies the NetworkCapabilities + for (int i = 0; i < mNetworkRequests.size(); i++) { + NetworkRequest nr = mNetworkRequests.valueAt(i); + if (nr.networkCapabilities.satisfiedByNetworkCapabilities( + newNetwork.networkCapabilities)) { + // next check if it's better than any current network we're using for + // this request + NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nr.requestId); + if (VDBG) { + log("currentScore = " + + (currentNetwork != null ? currentNetwork.currentScore : 0) + + ", newScore = " + newNetwork.currentScore); + } + if (currentNetwork == null || + currentNetwork.currentScore < newNetwork.currentScore) { + if (currentNetwork != null) { + currentNetwork.networkRequests.remove(nr.requestId); + currentNetwork.networkListens.add(nr); + if (currentNetwork.networkRequests.size() == 0) { + // TODO tell current Network to go to linger state + + // fake the linger state: + Message message = Message.obtain(); + message.obj = currentNetwork; + message.what = NetworkMonitorProtocol.EVENT_NETWORK_LINGER_COMPLETE; + mTrackerHandler.sendMessage(message); + + notifyNetworkCallbacks(currentNetwork, NetworkCallbacks.LOSING); + } + } + mNetworkForRequestId.put(nr.requestId, newNetwork); + newNetwork.networkRequests.put(nr.requestId, nr); + keep = true; + // TODO - this could get expensive if we have alot of requests for this + // network. Think about if there is a way to reduce this. Push + // netid->request mapping to each factory? + sendUpdatedScoreToFactories(nr, newNetwork.currentScore); + if (mDefaultRequest.requestId == nr.requestId) { + isNewDefault = true; + } + } + } + } + if (keep) { + if (isNewDefault) { + if (VDBG) log("Switching to new default network: " + newNetwork); + setupDataActivityTracking(newNetwork); + try { + mNetd.setDefaultNetId(newNetwork.network.netId); + } catch (Exception e) { + loge("Exception setting default network :" + e); + } + if (newNetwork.equals(mNetworkForRequestId.get(mDefaultRequest.requestId))) { + handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy()); + } + synchronized (ConnectivityService.this) { + // have a new default network, release the transition wakelock in + // a second if it's held. The second pause is to allow apps + // to reconnect over the new network + if (mNetTransitionWakeLock.isHeld()) { + mHandler.sendMessageDelayed(mHandler.obtainMessage( + EVENT_CLEAR_NET_TRANSITION_WAKELOCK, + mNetTransitionWakeLockSerialNumber, 0), + 1000); + } + } + + // this will cause us to come up initially as unconnected and switching + // to connected after our normal pause unless somebody reports us as + // really disconnected + mDefaultInetConditionPublished = 0; + mDefaultConnectionSequence++; + mInetConditionChangeInFlight = false; + // TODO - read the tcp buffer size config string from somewhere + // updateNetworkSettings(); + } + // notify battery stats service about this network +// try { + // TODO + //BatteryStatsService.getService().noteNetworkInterfaceType(iface, netType); +// } catch (RemoteException e) { } + notifyNetworkCallbacks(newNetwork, NetworkCallbacks.AVAILABLE); + } else { + if (VDBG) log("Validated network turns out to be unwanted. Tear it down."); + newNetwork.asyncChannel.disconnect(); + } + } + + + private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) { + NetworkInfo.State state = newInfo.getState(); + NetworkInfo oldInfo = networkAgent.networkInfo; + networkAgent.networkInfo = newInfo; + + if (oldInfo != null && oldInfo.getState() == state) { + if (VDBG) log("ignoring duplicate network state non-change"); + return; + } + if (DBG) { + log(networkAgent.name() + " EVENT_NETWORK_INFO_CHANGED, going from " + + (oldInfo == null ? "null" : oldInfo.getState()) + + " to " + state); + } + if (state == NetworkInfo.State.CONNECTED) { + // TODO - check if we want it (optimization) + try { + mNetd.createNetwork(networkAgent.network.netId, + networkAgent.linkProperties.getInterfaceName()); + } catch (Exception e) { + loge("Error creating Network " + networkAgent.network.netId); + } + updateLinkProperties(networkAgent, null); + notifyNetworkCallbacks(networkAgent, NetworkCallbacks.PRECHECK); + // TODO - kick the network monitor + + // Fake things by sending self a NETWORK_VALIDATED msg + Message message = Message.obtain(); + message.obj = networkAgent; + message.what = NetworkMonitorProtocol.EVENT_NETWORK_VALIDATED; + mTrackerHandler.sendMessage(message); + } else if (state == NetworkInfo.State.DISCONNECTED || + state == NetworkInfo.State.SUSPENDED) { + networkAgent.asyncChannel.disconnect(); + } + } + + protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType) { + if (VDBG) log("notifyType " + notifyType + " for " + networkAgent.name()); + boolean needsBroadcasts = false; + for (int i = 0; i < networkAgent.networkRequests.size(); i++) { + NetworkRequest request = networkAgent.networkRequests.valueAt(i); + if (request == null) continue; + if (request.needsBroadcasts) needsBroadcasts = true; + callCallbackForRequest(request, networkAgent, notifyType); + } + for (NetworkRequest request : networkAgent.networkListens) { + if (request.needsBroadcasts) needsBroadcasts = true; + callCallbackForRequest(request, networkAgent, notifyType); + } + if (needsBroadcasts) { + if (notifyType == NetworkCallbacks.AVAILABLE) { + sendConnectedBroadcastDelayed(networkAgent.networkInfo, + getConnectivityChangeDelay()); + } else if (notifyType == NetworkCallbacks.LOST) { + NetworkInfo info = new NetworkInfo(networkAgent.networkInfo); + Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType()); + if (info.isFailover()) { + intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); + networkAgent.networkInfo.setFailover(false); + } + if (info.getReason() != null) { + intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); + } + if (info.getExtraInfo() != null) { + intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo()); + } + NetworkAgentInfo newDefaultAgent = null; + if (networkAgent.networkRequests.get(mDefaultRequest.requestId) != null) { + newDefaultAgent = mNetworkForRequestId.get(mDefaultRequest.requestId); + if (newDefaultAgent != null) { + intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, + newDefaultAgent.networkInfo); + } else { + intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); + } + } + intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, + mDefaultInetConditionPublished); + final Intent immediateIntent = new Intent(intent); + immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE); + sendStickyBroadcast(immediateIntent); + sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay()); + if (newDefaultAgent != null) { + sendConnectedBroadcastDelayed(newDefaultAgent.networkInfo, + getConnectivityChangeDelay()); + } + } + } + } } diff --git a/services/core/java/com/android/server/connectivity/NetworkAgent.java b/services/core/java/com/android/server/connectivity/NetworkAgent.java deleted file mode 100644 index a0af06d..0000000 --- a/services/core/java/com/android/server/connectivity/NetworkAgent.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 com.android.server.connectivity; - -import android.net.Network; -import android.net.NetworkInfo; -import android.net.NetworkRequest; - -import com.android.internal.util.AsyncChannel; - -import java.util.ArrayList; - -/** - * {@hide} - */ -public class NetworkAgent { - public NetworkInfo networkInfo; - public Network network; - public final ArrayList<NetworkRequest> networkRequests = new ArrayList<NetworkRequest>(); - public final ArrayList<NetworkRequest> networkListens = new ArrayList<NetworkRequest>(); - public final AsyncChannel asyncChannel; - - public NetworkAgent(AsyncChannel ac) { - asyncChannel = ac; - } -} diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java new file mode 100644 index 0000000..4747487 --- /dev/null +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -0,0 +1,75 @@ +/* + * 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 com.android.server.connectivity; + +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkInfo; +import android.net.NetworkRequest; +import android.os.Messenger; +import android.util.SparseArray; + +import com.android.internal.util.AsyncChannel; + +import java.util.ArrayList; + +/** + * A bag class used by ConnectivityService for holding a collection of most recent + * information published by a particular NetworkAgent as well as the + * AsyncChannel/messenger for reaching that NetworkAgent and lists of NetworkRequests + * interested in using it. + */ +public class NetworkAgentInfo { + public NetworkInfo networkInfo; + public final Network network; + public LinkProperties linkProperties; + public NetworkCapabilities networkCapabilities; + public int currentScore; + + // The list of NetworkRequests being satisfied by this Network. + public final SparseArray<NetworkRequest> networkRequests = new SparseArray<NetworkRequest>(); + + // The list of NetworkListens listening for changes on this Network. + public final ArrayList<NetworkRequest> networkListens = new ArrayList<NetworkRequest>(); + public final Messenger messenger; + public final AsyncChannel asyncChannel; + + public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, int netId, NetworkInfo info, + LinkProperties lp, NetworkCapabilities nc, int score) { + this.messenger = messenger; + asyncChannel = ac; + network = new Network(netId); + networkInfo = info; + linkProperties = lp; + networkCapabilities = nc; + currentScore = score; + + } + + public String toString() { + return "NetworkAgentInfo{ ni{" + networkInfo + "} network{" + + network + "} lp{" + + linkProperties + "} nc{" + + networkCapabilities + "} Score{" + currentScore + "} }"; + } + + public String name() { + return "NetworkAgentInfo [" + networkInfo.getTypeName() + " (" + + networkInfo.getSubtypeName() + ")]"; + } +} diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java deleted file mode 100644 index 40e6649..0000000 --- a/wifi/java/android/net/wifi/WifiStateTracker.java +++ /dev/null @@ -1,314 +0,0 @@ -/* - * 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.wifi; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.BaseNetworkStateTracker; -import android.net.NetworkCapabilities; -import android.net.LinkQualityInfo; -import android.net.LinkProperties; -import android.net.NetworkInfo; -import android.net.NetworkInfo.DetailedState; -import android.net.SamplingDataTracker; -import android.net.WifiLinkQualityInfo; -import android.os.Handler; -import android.os.Message; -import android.os.Messenger; -import android.util.Slog; - -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * Track the state of wifi for connectivity service. - * - * @hide - */ -public class WifiStateTracker extends BaseNetworkStateTracker { - - private static final String NETWORKTYPE = "WIFI"; - private static final String TAG = "WifiStateTracker"; - - private static final boolean LOGV = true; - - private AtomicBoolean mTeardownRequested = new AtomicBoolean(false); - private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false); - private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false); - - private NetworkInfo.State mLastState = NetworkInfo.State.UNKNOWN; - - private WifiInfo mWifiInfo; - - /* For sending events to connectivity service handler */ - private Handler mCsHandler; - private BroadcastReceiver mWifiStateReceiver; - private WifiManager mWifiManager; - - private SamplingDataTracker mSamplingDataTracker = new SamplingDataTracker(); - - public WifiStateTracker(int netType, String networkName) { - mNetworkInfo = new NetworkInfo(netType, 0, networkName, ""); - mLinkProperties = new LinkProperties(); - mNetworkCapabilities = new NetworkCapabilities(); - - mNetworkInfo.setIsAvailable(false); - setTeardownRequested(false); - } - - - public void setTeardownRequested(boolean isRequested) { - mTeardownRequested.set(isRequested); - } - - public boolean isTeardownRequested() { - return mTeardownRequested.get(); - } - - /** - * Begin monitoring wifi connectivity - */ - public void startMonitoring(Context context, Handler target) { - mCsHandler = target; - mContext = context; - - mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); - IntentFilter filter = new IntentFilter(); - filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - filter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION); - - mWifiStateReceiver = new WifiStateReceiver(); - mContext.registerReceiver(mWifiStateReceiver, filter); - } - - /** - * Disable connectivity to a network - * TODO: do away with return value after making MobileDataStateTracker async - */ - public boolean teardown() { - mTeardownRequested.set(true); - mWifiManager.stopWifi(); - return true; - } - - /** - * Re-enable connectivity to a network after a {@link #teardown()}. - */ - public boolean reconnect() { - mTeardownRequested.set(false); - mWifiManager.startWifi(); - return true; - } - - @Override - public void captivePortalCheckCompleted(boolean isCaptivePortal) { - // not implemented - } - - /** - * Turn the wireless radio off for a network. - * @param turnOn {@code true} to turn the radio on, {@code false} - */ - public boolean setRadio(boolean turnOn) { - mWifiManager.setWifiEnabled(turnOn); - return true; - } - - /** - * Wi-Fi is considered available as long as we have a connection to the - * supplicant daemon and there is at least one enabled network. If a teardown - * was explicitly requested, then Wi-Fi can be restarted with a reconnect - * request, so it is considered available. If the driver has been stopped - * for any reason other than a teardown request, Wi-Fi is considered - * unavailable. - * @return {@code true} if Wi-Fi connections are possible - */ - public boolean isAvailable() { - return mNetworkInfo.isAvailable(); - } - - @Override - public void setUserDataEnable(boolean enabled) { - Slog.w(TAG, "ignoring setUserDataEnable(" + enabled + ")"); - } - - @Override - public void setPolicyDataEnable(boolean enabled) { - // ignored - } - - /** - * Check if private DNS route is set for the network - */ - public boolean isPrivateDnsRouteSet() { - return mPrivateDnsRouteSet.get(); - } - - /** - * Set a flag indicating private DNS route is set - */ - public void privateDnsRouteSet(boolean enabled) { - mPrivateDnsRouteSet.set(enabled); - } - - /** - * Fetch NetworkInfo for the network - */ - @Override - public NetworkInfo getNetworkInfo() { - return new NetworkInfo(mNetworkInfo); - } - - /** - * Fetch LinkProperties for the network - */ - @Override - public LinkProperties getLinkProperties() { - return new LinkProperties(mLinkProperties); - } - - /** - * Return link info - * @return an object of type WifiLinkQualityInfo - */ - @Override - public LinkQualityInfo getLinkQualityInfo() { - if (mNetworkInfo == null) { - // no data available yet; just return - return null; - } - - WifiLinkQualityInfo li = new WifiLinkQualityInfo(); - li.setNetworkType(mNetworkInfo.getType()); - - synchronized(mSamplingDataTracker.mSamplingDataLock) { - mSamplingDataTracker.setCommonLinkQualityInfoFields(li); - li.setTxGood(mSamplingDataTracker.getSampledTxPacketCount()); - li.setTxBad(mSamplingDataTracker.getSampledTxPacketErrorCount()); - } - - // li.setTheoreticalRxBandwidth(??); - // li.setTheoreticalTxBandwidth(??); - - if (mWifiInfo != null) { - li.setBssid(mWifiInfo.getBSSID()); - - int rssi = mWifiInfo.getRssi(); - li.setRssi(rssi); - - li.setNormalizedSignalStrength(mWifiManager.calculateSignalLevel(rssi, - LinkQualityInfo.NORMALIZED_SIGNAL_STRENGTH_RANGE)); - } - - return li; - } - - /** - * Check if default route is set - */ - public boolean isDefaultRouteSet() { - return mDefaultRouteSet.get(); - } - - /** - * Set a flag indicating default route is set for the network - */ - public void defaultRouteSet(boolean enabled) { - mDefaultRouteSet.set(enabled); - } - - /** - * Return the system properties name associated with the tcp buffer sizes - * for this network. - */ - public String getTcpBufferSizesPropName() { - return "net.tcp.buffersize.wifi"; - } - - private class WifiStateReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - - if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { - mNetworkInfo = (NetworkInfo) intent.getParcelableExtra( - WifiManager.EXTRA_NETWORK_INFO); - - mLinkProperties = intent.getParcelableExtra( - WifiManager.EXTRA_LINK_PROPERTIES); - if (mLinkProperties == null) { - mLinkProperties = new LinkProperties(); - } - mNetworkCapabilities = intent.getParcelableExtra( - WifiManager.EXTRA_NETWORK_CAPABILITIES); - if (mNetworkCapabilities == null) { - mNetworkCapabilities = new NetworkCapabilities(); - } - - mWifiInfo = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO); - // don't want to send redundant state messages - // but send portal check detailed state notice - NetworkInfo.State state = mNetworkInfo.getState(); - if (mLastState == state && - mNetworkInfo.getDetailedState() != DetailedState.CAPTIVE_PORTAL_CHECK) { - return; - } else { - mLastState = state; - /* lets not sample traffic data across state changes */ - mSamplingDataTracker.resetSamplingData(); - } - - Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, - new NetworkInfo(mNetworkInfo)); - msg.sendToTarget(); - } else if (intent.getAction().equals(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION)) { - mLinkProperties = intent.getParcelableExtra(WifiManager.EXTRA_LINK_PROPERTIES); - Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo); - msg.sendToTarget(); - } - } - } - - public void setDependencyMet(boolean met) { - // not supported on this network - } - - @Override - public void addStackedLink(LinkProperties link) { - mLinkProperties.addStackedLink(link); - } - - @Override - public void removeStackedLink(LinkProperties link) { - mLinkProperties.removeStackedLink(link); - } - - @Override - public void supplyMessenger(Messenger messenger) { - // not supported on this network - } - - @Override - public void startSampling(SamplingDataTracker.SamplingSnapshot s) { - mSamplingDataTracker.startSampling(s); - } - - @Override - public void stopSampling(SamplingDataTracker.SamplingSnapshot s) { - mSamplingDataTracker.stopSampling(s); - } -} |