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
This commit is contained in:
Robert Greenwalt
2014-04-18 15:25:25 -07:00
committed by Lorenzo Colitti
parent 2a9d35f655
commit e20f7a2429
6 changed files with 1139 additions and 313 deletions

View File

@@ -534,39 +534,33 @@ 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;
}
}
/**
* Returns details about the currently active default data network. When
@@ -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) {}
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
@@ -305,12 +308,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
@@ -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()) {
@@ -2746,12 +2579,16 @@ public class ConnectivityService extends IConnectivityManager.Stub {
* 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);
loge("Unexpected mtu value: " + mtu + ", " + iface);
return;
}
@@ -3053,19 +2890,56 @@ 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));
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 {
loge("Error connecting NetworkFactory");
mNetworkFactories.remove((AsyncChannel) msg.obj);
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: {
@@ -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());
}
}
}
}
}

View File

@@ -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() + ")]";
}
}