Enabling internal msg apis
NetworkFactory and NetworkAgent. First trying with wifi and
getting rid of WifiStateTracker.
Conflicts:
api/current.txt
services/core/java/com/android/server/ConnectivityService.java
Change-Id: I7f0ec13d7d8988b32f3c6dc71f72012f3349fe02
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 @@
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 @@
} 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 @@
}
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 @@
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 @@
} 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 @@
}
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 @@
/**
* 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 @@
* {@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 @@
* {@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 @@
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 @@
* @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 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 @@
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 @@
// 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 @@
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 @@
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 @@
* @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 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 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 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..4c4c76f1 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -56,5 +56,6 @@
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.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.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.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.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.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 @@
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 @@
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 @@
*/
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 @@
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 @@
}
}
- // 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 @@
/**
* 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 @@
@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 @@
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 @@
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 @@
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 @@
}
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 @@
}
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 @@
}
}
- /**
- * 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 @@
}
/**
- * 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 @@
/**
* 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 @@
* 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 @@
*/
handleDnsConfigurationChange(netType);
- LinkProperties curLp = mCurrentLinkProperties[netType];
LinkProperties newLp = null;
if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
@@ -2742,26 +2575,30 @@
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();
+ 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 + ", " + nt);
- 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);
- }
- }
+ 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 @@
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 @@
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 @@
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 @@
// 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 @@
}
}
+ 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 @@
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 @@
handleRegisterNetworkFactory((Messenger)msg.obj);
break;
}
+ case EVENT_REGISTER_NETWORK_AGENT: {
+ handleRegisterNetworkAgent((NetworkAgentInfo)msg.obj);
+ break;
+ }
}
}
}
@@ -5112,7 +5034,6 @@
public void registerNetworkFactory(Messenger messenger) {
enforceConnectivityInternalPermission();
-
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, messenger));
}
@@ -5123,5 +5044,335 @@
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);
- }
-}