From 42acef37339afe6ac608c842f1637870ee9c4f6c Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 12 Aug 2009 16:08:25 -0700 Subject: Add net type to mobile for mobile-required traffic This also refactors ConnectivityService a bit towards supporting multiple simultaneous connections by making each a seem like a seperate Network with it's own stateTracker, etc. Also adds tracking of process death to clean orphaned startUsingNetworkFeature features. --- core/java/android/net/ConnectivityManager.java | 59 ++++- core/java/android/net/IConnectivityManager.aidl | 4 +- core/java/android/net/MobileDataStateTracker.java | 265 ++++++++-------------- core/java/android/net/NetworkStateTracker.java | 73 +++++- 4 files changed, 214 insertions(+), 187 deletions(-) (limited to 'core/java/android/net') diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 1429bc1..a127df0 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -18,6 +18,7 @@ package android.net; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.os.Binder; import android.os.RemoteException; /** @@ -114,15 +115,64 @@ public class ConnectivityManager public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED"; - public static final int TYPE_MOBILE = 0; - public static final int TYPE_WIFI = 1; + /** + * The Default Mobile data connection. When active, all data traffic + * will use this connection by default. Should not coexist with other + * default connections. + */ + public static final int TYPE_MOBILE = 0; + /** + * The Default WIFI data connection. When active, all data traffic + * will use this connection by default. Should not coexist with other + * default connections. + */ + public static final int TYPE_WIFI = 1; + /** + * An MMS-specific Mobile data connection. This connection may be the + * same as {@link #TYPEMOBILE} but it may be different. This is used + * by applications needing to talk to the carrier's Multimedia Messaging + * Service servers. It may coexist with default data connections. + * {@hide} + */ + public static final int TYPE_MOBILE_MMS = 2; + /** + * A SUPL-specific Mobile data connection. This connection may be the + * same as {@link #TYPEMOBILE} but it may be different. This is used + * by applications needing to talk to the carrier's Secure User Plane + * Location servers for help locating the device. It may coexist with + * default data connections. + * {@hide} + */ + public static final int TYPE_MOBILE_SUPL = 3; + /** + * A DUN-specific Mobile data connection. This connection may be the + * same as {@link #TYPEMOBILE} but it may be different. This is used + * by applicaitons performing a Dial Up Networking bridge so that + * the carrier is aware of DUN traffic. It may coexist with default data + * connections. + * {@hide} + */ + public static final int TYPE_MOBILE_DUN = 4; + /** + * A High Priority Mobile data connection. This connection is typically + * the same as {@link #TYPEMOBILE} but the routing setup is different. + * Only requesting processes will have access to the Mobile DNS servers + * and only IP's explicitly requested via {@link #requestRouteToHost} + * will route over this interface. + *{@hide} + */ + public static final int TYPE_MOBILE_HIPRI = 5; + /** {@hide} */ + public static final int MAX_RADIO_TYPE = TYPE_WIFI; + /** {@hide} */ + public static final int MAX_NETWORK_TYPE = TYPE_MOBILE_HIPRI; public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI; private IConnectivityManager mService; static public boolean isNetworkTypeValid(int networkType) { - return networkType == TYPE_WIFI || networkType == TYPE_MOBILE; + return networkType >= 0 && networkType <= MAX_NETWORK_TYPE; } public void setNetworkPreference(int preference) { @@ -195,7 +245,8 @@ public class ConnectivityManager */ public int startUsingNetworkFeature(int networkType, String feature) { try { - return mService.startUsingNetworkFeature(networkType, feature); + return mService.startUsingNetworkFeature(networkType, feature, + new Binder()); } catch (RemoteException e) { return -1; } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index de68598..9f59cce 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -17,6 +17,7 @@ package android.net; import android.net.NetworkInfo; +import android.os.IBinder; /** * Interface that answers queries about, and allows changing, the @@ -39,7 +40,8 @@ interface IConnectivityManager boolean setRadio(int networkType, boolean turnOn); - int startUsingNetworkFeature(int networkType, in String feature); + int startUsingNetworkFeature(int networkType, in String feature, + in IBinder binder); int stopUsingNetworkFeature(int networkType, in String feature); diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java index 1064fb6..6b00900 100644 --- a/core/java/android/net/MobileDataStateTracker.java +++ b/core/java/android/net/MobileDataStateTracker.java @@ -32,9 +32,6 @@ import android.telephony.TelephonyManager; import android.util.Log; import android.text.TextUtils; -import java.util.List; -import java.util.ArrayList; - /** * Track the state of mobile data connectivity. This is done by * receiving broadcast intents from the Phone process whenever @@ -45,36 +42,47 @@ import java.util.ArrayList; public class MobileDataStateTracker extends NetworkStateTracker { private static final String TAG = "MobileDataStateTracker"; - private static final boolean DBG = false; + private static final boolean DBG = true; private Phone.DataState mMobileDataState; private ITelephony mPhoneService; - private static final String[] sDnsPropNames = { - "net.rmnet0.dns1", - "net.rmnet0.dns2", - "net.eth0.dns1", - "net.eth0.dns2", - "net.eth0.dns3", - "net.eth0.dns4", - "net.gprs.dns1", - "net.gprs.dns2" - }; - private List mDnsServers; - private String mInterfaceName; - private int mDefaultGatewayAddr; - private int mLastCallingPid = -1; + + private String mApnType; + private boolean mEnabled; + private boolean mTeardownRequested; /** * Create a new MobileDataStateTracker * @param context the application context of the caller * @param target a message handler for getting callbacks about state changes + * @param netType the ConnectivityManager network type + * @param apnType the Phone apnType + * @param tag the name of this network */ - public MobileDataStateTracker(Context context, Handler target) { - super(context, target, ConnectivityManager.TYPE_MOBILE, - TelephonyManager.getDefault().getNetworkType(), "MOBILE", - TelephonyManager.getDefault().getNetworkTypeName()); + public MobileDataStateTracker(Context context, Handler target, + int netType, String apnType, String tag) { + super(context, target, netType, + TelephonyManager.getDefault().getNetworkType(), tag, + TelephonyManager.getDefault().getNetworkTypeName()); + mApnType = apnType; mPhoneService = null; - mDnsServers = new ArrayList(); + mTeardownRequested = false; + if(netType == ConnectivityManager.TYPE_MOBILE) { + mEnabled = true; + } else { + mEnabled = false; + } + + mDnsPropNames = new String[] { + "net.rmnet0.dns1", + "net.rmnet0.dns2", + "net.eth0.dns1", + "net.eth0.dns2", + "net.eth0.dns3", + "net.eth0.dns4", + "net.gprs.dns1", + "net.gprs.dns2"}; + } /** @@ -93,31 +101,70 @@ public class MobileDataStateTracker extends NetworkStateTracker { mMobileDataState = Phone.DataState.DISCONNECTED; } - private static Phone.DataState getMobileDataState(Intent intent) { + private Phone.DataState getMobileDataState(Intent intent) { String str = intent.getStringExtra(Phone.STATE_KEY); - if (str != null) - return Enum.valueOf(Phone.DataState.class, str); - else - return Phone.DataState.DISCONNECTED; + if (str != null) { + String apnTypeList = + intent.getStringExtra(Phone.DATA_APN_TYPES_KEY); + if (isApnTypeIncluded(apnTypeList)) { + return Enum.valueOf(Phone.DataState.class, str); + } + } + return Phone.DataState.DISCONNECTED; + } + + private boolean isApnTypeIncluded(String typeList) { + /* comma seperated list - split and check */ + if (typeList == null) + return false; + + String[] list = typeList.split(","); + for(int i=0; i< list.length; i++) { + if (TextUtils.equals(list[i], mApnType) || + TextUtils.equals(list[i], Phone.APN_TYPE_ALL)) { + return true; + } + } + return false; } private class MobileDataStateReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { + if (intent.getAction().equals(TelephonyIntents. + ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { Phone.DataState state = getMobileDataState(intent); - String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY); + String reason = + intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY); String apnName = intent.getStringExtra(Phone.DATA_APN_KEY); - boolean unavailable = intent.getBooleanExtra(Phone.NETWORK_UNAVAILABLE_KEY, false); - if (DBG) Log.d(TAG, "Received " + intent.getAction() + - " broadcast - state = " + state - + ", unavailable = " + unavailable - + ", reason = " + (reason == null ? "(unspecified)" : reason)); + + String apnTypeList = + intent.getStringExtra(Phone.DATA_APN_TYPES_KEY); + + boolean unavailable = intent.getBooleanExtra( + Phone.NETWORK_UNAVAILABLE_KEY, false); + if (DBG) Log.d(TAG, mApnType + " Received " + + intent.getAction() + " broadcast - state = " + + state + ", unavailable = " + unavailable + + ", reason = " + + (reason == null ? "(unspecified)" : reason)); + + if ((!isApnTypeIncluded(apnTypeList)) || mEnabled == false) { + if (DBG) Log.e(TAG, " dropped - mEnabled = "+mEnabled); + return; + } + + mNetworkInfo.setIsAvailable(!unavailable); if (mMobileDataState != state) { mMobileDataState = state; switch (state) { case DISCONNECTED: + if(mTeardownRequested) { + mEnabled = false; + mTeardownRequested = false; + } + setDetailedState(DetailedState.DISCONNECTED, reason, apnName); if (mInterfaceName != null) { NetworkUtils.resetConnections(mInterfaceName); @@ -136,12 +183,12 @@ public class MobileDataStateTracker extends NetworkStateTracker { if (mInterfaceName == null) { Log.d(TAG, "CONNECTED event did not supply interface name."); } - setupDnsProperties(); setDetailedState(DetailedState.CONNECTED, reason, apnName); break; } } } else if (intent.getAction().equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) { + mEnabled = false; String reason = intent.getStringExtra(Phone.FAILURE_REASON_KEY); String apnName = intent.getStringExtra(Phone.DATA_APN_KEY); if (DBG) Log.d(TAG, "Received " + intent.getAction() + " broadcast" + @@ -154,40 +201,6 @@ public class MobileDataStateTracker extends NetworkStateTracker { } } - /** - * Make sure that route(s) exist to the carrier DNS server(s). - */ - public void addPrivateRoutes() { - if (mInterfaceName != null) { - for (String addrString : mDnsServers) { - int addr = NetworkUtils.lookupHost(addrString); - if (addr != -1) { - NetworkUtils.addHostRoute(mInterfaceName, addr); - } - } - } - } - - public void removePrivateRoutes() { - if(mInterfaceName != null) { - NetworkUtils.removeHostRoutes(mInterfaceName); - } - } - - public void removeDefaultRoute() { - if(mInterfaceName != null) { - mDefaultGatewayAddr = NetworkUtils.getDefaultRoute(mInterfaceName); - NetworkUtils.removeDefaultRoute(mInterfaceName); - } - } - - public void restoreDefaultRoute() { - // 0 is not a valid address for a gateway - if (mInterfaceName != null && mDefaultGatewayAddr != 0) { - NetworkUtils.setDefaultRoute(mInterfaceName, mDefaultGatewayAddr); - } - } - private void getPhoneService(boolean forceRefresh) { if ((mPhoneService == null) || forceRefresh) { mPhoneService = ITelephony.Stub.asInterface(ServiceManager.getService("phone")); @@ -219,15 +232,6 @@ public class MobileDataStateTracker extends NetworkStateTracker { } /** - * Return the IP addresses of the DNS servers available for the mobile data - * network interface. - * @return a list of DNS addresses, with no holes. - */ - public String[] getNameServers() { - return getNameServerList(sDnsPropNames); - } - - /** * {@inheritDoc} * The mobile data network subtype indicates what generation network technology is in effect, * e.g., GPRS, EDGE, UMTS, etc. @@ -273,54 +277,19 @@ public class MobileDataStateTracker extends NetworkStateTracker { */ @Override public boolean teardown() { - getPhoneService(false); - /* - * If the phone process has crashed in the past, we'll get a - * RemoteException and need to re-reference the service. - */ - for (int retry = 0; retry < 2; retry++) { - if (mPhoneService == null) { - Log.w(TAG, - "Ignoring mobile data teardown request because could not acquire PhoneService"); - break; - } - - try { - return mPhoneService.disableDataConnectivity(); - } catch (RemoteException e) { - if (retry == 0) getPhoneService(true); - } - } - - Log.w(TAG, "Failed to tear down mobile data connectivity"); - return false; + mTeardownRequested = true; + return (setEnableApn(mApnType, false) != Phone.APN_REQUEST_FAILED); } /** * Re-enable mobile data connectivity after a {@link #teardown()}. */ public boolean reconnect() { - getPhoneService(false); - /* - * If the phone process has crashed in the past, we'll get a - * RemoteException and need to re-reference the service. - */ - for (int retry = 0; retry < 2; retry++) { - if (mPhoneService == null) { - Log.w(TAG, - "Ignoring mobile data connect request because could not acquire PhoneService"); - break; - } - - try { - return mPhoneService.enableDataConnectivity(); - } catch (RemoteException e) { - if (retry == 0) getPhoneService(true); - } - } - - Log.w(TAG, "Failed to set up mobile data connectivity"); - return false; + mEnabled = true; + mTeardownRequested = false; + mEnabled = (setEnableApn(mApnType, true) != + Phone.APN_REQUEST_FAILED); + return mEnabled; } /** @@ -374,14 +343,7 @@ public class MobileDataStateTracker extends NetworkStateTracker { * */ public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) { - if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { - mLastCallingPid = callingPid; - return setEnableApn(Phone.APN_TYPE_MMS, true); - } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { - return setEnableApn(Phone.APN_TYPE_SUPL, true); - } else { - return -1; - } + return -1; } /** @@ -397,13 +359,7 @@ public class MobileDataStateTracker extends NetworkStateTracker { * the value {@code -1} always indicates failure. */ public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) { - if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { - return setEnableApn(Phone.APN_TYPE_MMS, false); - } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { - return setEnableApn(Phone.APN_TYPE_SUPL, false); - } else { - return -1; - } + return -1; } /** @@ -433,43 +389,6 @@ public class MobileDataStateTracker extends NetworkStateTracker { return sb.toString(); } - private void setupDnsProperties() { - mDnsServers.clear(); - // Set up per-process DNS server list on behalf of the MMS process - int i = 1; - if (mInterfaceName != null) { - for (String propName : sDnsPropNames) { - if (propName.indexOf(mInterfaceName) != -1) { - String propVal = SystemProperties.get(propName); - if (propVal != null && propVal.length() != 0 && !propVal.equals("0.0.0.0")) { - mDnsServers.add(propVal); - if (mLastCallingPid != -1) { - SystemProperties.set("net.dns" + i + "." + mLastCallingPid, propVal); - } - ++i; - } - } - } - } - if (i == 1) { - Log.d(TAG, "DNS server addresses are not known."); - } else if (mLastCallingPid != -1) { - /* - * Bump the property that tells the name resolver library - * to reread the DNS server list from the properties. - */ - String propVal = SystemProperties.get("net.dnschange"); - if (propVal.length() != 0) { - try { - int n = Integer.parseInt(propVal); - SystemProperties.set("net.dnschange", "" + (n+1)); - } catch (NumberFormatException e) { - } - } - } - mLastCallingPid = -1; - } - /** * Internal method supporting the ENABLE_MMS feature. * @param apnType the type of APN to be enabled or disabled (e.g., mms) diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java index 37087ac..418f511 100644 --- a/core/java/android/net/NetworkStateTracker.java +++ b/core/java/android/net/NetworkStateTracker.java @@ -27,6 +27,7 @@ import android.text.TextUtils; import android.util.Config; import android.util.Log; + /** * Each subclass of this class keeps track of the state of connectivity * of a network interface. All state information for a network should @@ -40,11 +41,16 @@ public abstract class NetworkStateTracker extends Handler { protected NetworkInfo mNetworkInfo; protected Context mContext; protected Handler mTarget; + protected String mInterfaceName; + protected String[] mDnsPropNames; + private boolean mPrivateDnsRouteSet; + protected int mDefaultGatewayAddr; + private boolean mDefaultRouteSet; private boolean mTeardownRequested; - private static boolean DBG = Config.LOGV; + private static boolean DBG = Config.LOGV; private static final String TAG = "NetworkStateTracker"; - + public static final int EVENT_STATE_CHANGED = 1; public static final int EVENT_SCAN_RESULTS_AVAILABLE = 2; /** @@ -56,6 +62,7 @@ public abstract class NetworkStateTracker extends Handler { public static final int EVENT_CONFIGURATION_CHANGED = 4; public static final int EVENT_ROAMING_CHANGED = 5; public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 6; + public static final int EVENT_RESTORE_DEFAULT_NETWORK = 7; public NetworkStateTracker(Context context, Handler target, @@ -67,6 +74,7 @@ public abstract class NetworkStateTracker extends Handler { mContext = context; mTarget = target; mTeardownRequested = false; + this.mNetworkInfo = new NetworkInfo(networkType, subType, typeName, subtypeName); } @@ -75,19 +83,21 @@ public abstract class NetworkStateTracker extends Handler { } /** - * Return the list of DNS servers associated with this network. - * @return a list of the IP addresses of the DNS servers available - * for the network. - */ - public abstract String[] getNameServers(); - - /** * Return the system properties name associated with the tcp buffer sizes * for this network. */ public abstract String getTcpBufferSizesPropName(); /** + * Return the IP addresses of the DNS servers available for the mobile data + * network interface. + * @return a list of DNS addresses, with no holes. + */ + public String[] getNameServers() { + return getNameServerList(mDnsPropNames); + } + + /** * Return the IP addresses of the DNS servers available for this * network interface. * @param propertyNames the names of the system properties whose values @@ -112,6 +122,50 @@ public abstract class NetworkStateTracker extends Handler { return dnsAddresses; } + public void addPrivateDnsRoutes() { + if (DBG) Log.d(TAG, "addPrivateDnsRoutes for " + this + + "(" + mInterfaceName + ")"); + if (mInterfaceName != null && !mPrivateDnsRouteSet) { + for (String addrString : getNameServers()) { + int addr = NetworkUtils.lookupHost(addrString); + if (addr != -1) { + NetworkUtils.addHostRoute(mInterfaceName, addr); + } + } + mPrivateDnsRouteSet = true; + } + } + + public void removePrivateDnsRoutes() { + if (DBG) Log.d(TAG, "removePrivateDnsRoutes for " + this + + "(" + mInterfaceName + ")"); + // TODO - we should do this explicitly but the NetUtils api doesnt + // support this yet - must remove all. No worse than before + if (mInterfaceName != null && mPrivateDnsRouteSet) { + NetworkUtils.removeHostRoutes(mInterfaceName); + mPrivateDnsRouteSet = false; + } + } + + public void addDefaultRoute() { + if (DBG) Log.d(TAG, "addDefaultRoute for " + this + "(" + + mInterfaceName + "), GatewayAddr=" + mDefaultGatewayAddr); + if ((mInterfaceName != null) && (mDefaultGatewayAddr != 0) && + mDefaultRouteSet == false) { + NetworkUtils.setDefaultRoute(mInterfaceName, mDefaultGatewayAddr); + mDefaultRouteSet = true; + } + } + + public void removeDefaultRoute() { + if (DBG) Log.d(TAG, "removeDefaultRoute for " + this + "(" + + mInterfaceName + ")"); + if (mInterfaceName != null && mDefaultRouteSet == true) { + NetworkUtils.removeDefaultRoute(mInterfaceName); + mDefaultRouteSet = false; + } + } + /** * Reads the network specific TCP buffer sizes from SystemProperties * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system @@ -209,6 +263,7 @@ public abstract class NetworkStateTracker extends Handler { * @param extraInfo optional {@code String} providing extra information about the state change */ public void setDetailedState(NetworkInfo.DetailedState state, String reason, String extraInfo) { + if (DBG) Log.d(TAG, "setDetailed state, old ="+mNetworkInfo.getDetailedState()+" and new state="+state); if (state != mNetworkInfo.getDetailedState()) { boolean wasConnecting = (mNetworkInfo.getState() == NetworkInfo.State.CONNECTING); String lastReason = mNetworkInfo.getReason(); -- cgit v1.1