summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/net/ConnectivityManager.java59
-rw-r--r--core/java/android/net/IConnectivityManager.aidl4
-rw-r--r--core/java/android/net/MobileDataStateTracker.java265
-rw-r--r--core/java/android/net/NetworkStateTracker.java73
-rw-r--r--core/res/res/values/config.xml19
-rw-r--r--services/java/com/android/server/ConnectivityService.java843
-rw-r--r--services/java/com/android/server/TelephonyRegistry.java17
-rw-r--r--telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java7
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl2
-rw-r--r--telephony/java/com/android/internal/telephony/Phone.java9
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/ApnSetting.java5
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java191
12 files changed, 972 insertions, 522 deletions
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<String> 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<String>();
+ 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 {
* </ul>
*/
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();
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f655b27..92c776c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -38,4 +38,23 @@
<!-- Flag indicating whether Last Name comes before First Name.
This becomes true in Japan, for example.-->
<bool name="config_lastname_comes_before_firstname">false</bool>
+
+ <!-- This string array should be overridden by the device to present a list of network attributes. This is used by the connectivity manager to decide which networks can coexist based on the hardward -->
+ <!-- An Array of "[type-name],[associated radio-name],[priority] -->
+ <string-array translatable="false" name="networkAttributes">
+ <item>"default,wifi,0"</item>
+ <item>"default,mobile,0"</item>
+ <item>"mms,mobile,1"</item>
+ <item>"supl,mobile,1"</item>
+ <item>"dun,mobile,1"</item>
+ <item>"hipri,mobile,2"</item>
+ </string-array>
+
+ <!-- This string array should be overridden by the device to present a list of radio attributes. This is used by the connectivity manager to decide which networks can coexist based on the hardware -->
+ <!-- An Array of "[radio-name],[priority] -->
+ <!-- [# simultaneous connection types]" -->
+ <string-array translatable="false" name="radioAttributes">
+ <item>"wifi,1,1"</item>
+ <item>"mobile,0,1"</item>
+ </string-array>
</resources>
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 62b839d..1c60058 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -30,48 +30,130 @@ import android.net.NetworkStateTracker;
import android.net.wifi.WifiStateTracker;
import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
+import com.android.internal.telephony.Phone;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
/**
* @hide
*/
public class ConnectivityService extends IConnectivityManager.Stub {
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
private static final String TAG = "ConnectivityService";
// Event log tags (must be in sync with event-log-tags)
private static final int EVENTLOG_CONNECTIVITY_STATE_CHANGED = 50020;
+ // how long to wait before switching back to a radio's default network
+ private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
+ // system property that can override the above value
+ private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
+ "android.telephony.apn-restore";
+
/**
* Sometimes we want to refer to the individual network state
* trackers separately, and sometimes we just want to treat them
* abstractly.
*/
private NetworkStateTracker mNetTrackers[];
- private WifiStateTracker mWifiStateTracker;
- private MobileDataStateTracker mMobileDataStateTracker;
+
+ /**
+ * A per Net list of the PID's that requested access to the net
+ * used both as a refcount and for per-PID DNS selection
+ */
+ private List mNetRequestersPids[];
+
private WifiWatchdogService mWifiWatchdogService;
+ // priority order of the nettrackers
+ // (excluding dynamically set mNetworkPreference)
+ // TODO - move mNetworkTypePreference into this
+ private int[] mPriorityList;
+
private Context mContext;
private int mNetworkPreference;
- private NetworkStateTracker mActiveNetwork;
+ private int mActiveDefaultNetwork = -1;
private int mNumDnsEntries;
- private static int sDnsChangeCounter;
private boolean mTestMode;
private static ConnectivityService sServiceInstance;
+ private Handler mHandler;
+
+ // list of DeathRecipients used to make sure features are turned off when
+ // a process dies
+ private List mFeatureUsers;
+
+ private class NetworkAttributes {
+ /**
+ * Class for holding settings read from resources.
+ */
+ public String mName;
+ public int mType;
+ public int mRadio;
+ public int mPriority;
+ public NetworkAttributes(String init) {
+ String fragments[] = init.split(",");
+ mName = fragments[0].toLowerCase();
+ if (fragments[1].toLowerCase().equals("wifi")) {
+ mRadio = ConnectivityManager.TYPE_WIFI;
+ } else {
+ mRadio = ConnectivityManager.TYPE_MOBILE;
+ }
+ if (mName.equals("default")) {
+ mType = mRadio;
+ } else if (mName.equals("mms")) {
+ mType = ConnectivityManager.TYPE_MOBILE_MMS;
+ } else if (mName.equals("supl")) {
+ mType = ConnectivityManager.TYPE_MOBILE_SUPL;
+ } else if (mName.equals("dun")) {
+ mType = ConnectivityManager.TYPE_MOBILE_DUN;
+ } else if (mName.equals("hipri")) {
+ mType = ConnectivityManager.TYPE_MOBILE_HIPRI;
+ }
+ mPriority = Integer.parseInt(fragments[2]);
+ }
+ public boolean isDefault() {
+ return (mType == mRadio);
+ }
+ }
+ NetworkAttributes[] mNetAttributes;
+
+ private class RadioAttributes {
+ public String mName;
+ public int mPriority;
+ public int mSimultaneity;
+ public int mType;
+ public RadioAttributes(String init) {
+ String fragments[] = init.split(",");
+ mName = fragments[0].toLowerCase();
+ mPriority = Integer.parseInt(fragments[1]);
+ mSimultaneity = Integer.parseInt(fragments[2]);
+ if (mName.equals("wifi")) {
+ mType = ConnectivityManager.TYPE_WIFI;
+ } else {
+ mType = ConnectivityManager.TYPE_MOBILE;
+ }
+ }
+ }
+ RadioAttributes[] mRadioAttributes;
+
private static class ConnectivityThread extends Thread {
private Context mContext;
@@ -118,11 +200,54 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private ConnectivityService(Context context) {
if (DBG) Log.v(TAG, "ConnectivityService starting up");
mContext = context;
- mNetTrackers = new NetworkStateTracker[2];
- Handler handler = new MyHandler();
+ mNetTrackers = new NetworkStateTracker[
+ ConnectivityManager.MAX_NETWORK_TYPE+1];
+ mHandler = new MyHandler();
mNetworkPreference = getPersistedNetworkPreference();
+ // Load device network attributes from resources
+ mNetAttributes = new NetworkAttributes[
+ ConnectivityManager.MAX_NETWORK_TYPE+1];
+ mRadioAttributes = new RadioAttributes[
+ ConnectivityManager.MAX_RADIO_TYPE+1];
+ String[] naStrings = context.getResources().getStringArray(
+ com.android.internal.R.array.networkAttributes);
+ // TODO - what if the setting has gaps/unknown types?
+ for (String a : naStrings) {
+ NetworkAttributes n = new NetworkAttributes(a);
+ mNetAttributes[n.mType] = n;
+ }
+ String[] raStrings = context.getResources().getStringArray(
+ com.android.internal.R.array.radioAttributes);
+ for (String a : raStrings) {
+ RadioAttributes r = new RadioAttributes(a);
+ mRadioAttributes[r.mType] = r;
+ }
+
+ // high priority first
+ mPriorityList = new int[naStrings.length];
+ {
+ int priority = 0; //lowest
+ int nextPos = naStrings.length-1;
+ while (nextPos>-1) {
+ for (int i = 0; i < mNetAttributes.length; i++) {
+ if(mNetAttributes[i].mPriority == priority) {
+ mPriorityList[nextPos--] = i;
+ }
+ }
+ priority++;
+ }
+ }
+
+ mNetRequestersPids =
+ new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
+ for (int i=0; i<=ConnectivityManager.MAX_NETWORK_TYPE; i++) {
+ mNetRequestersPids[i] = new ArrayList();
+ }
+
+ mFeatureUsers = new ArrayList();
+
/*
* Create the network state trackers for Wi-Fi and mobile
* data. Maybe this could be done with a factory class,
@@ -131,15 +256,36 @@ public class ConnectivityService extends IConnectivityManager.Stub {
* to change very often.
*/
if (DBG) Log.v(TAG, "Starting Wifi Service.");
- mWifiStateTracker = new WifiStateTracker(context, handler);
- WifiService wifiService = new WifiService(context, mWifiStateTracker);
+ WifiStateTracker wst = new WifiStateTracker(context, mHandler);
+ WifiService wifiService = new WifiService(context, wst);
ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
- mNetTrackers[ConnectivityManager.TYPE_WIFI] = mWifiStateTracker;
+ mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
+
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE] =
+ new MobileDataStateTracker(context, mHandler,
+ ConnectivityManager.TYPE_MOBILE, Phone.APN_TYPE_DEFAULT,
+ "MOBILE");
+
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE_MMS] =
+ new MobileDataStateTracker(context, mHandler,
+ ConnectivityManager.TYPE_MOBILE_MMS, Phone.APN_TYPE_MMS,
+ "MOBILE_MMS");
- mMobileDataStateTracker = new MobileDataStateTracker(context, handler);
- mNetTrackers[ConnectivityManager.TYPE_MOBILE] = mMobileDataStateTracker;
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE_SUPL] =
+ new MobileDataStateTracker(context, mHandler,
+ ConnectivityManager.TYPE_MOBILE_SUPL, Phone.APN_TYPE_SUPL,
+ "MOBILE_SUPL");
+
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] =
+ new MobileDataStateTracker(context, mHandler,
+ ConnectivityManager.TYPE_MOBILE_DUN, Phone.APN_TYPE_DUN,
+ "MOBILE_DUN");
+
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI] =
+ new MobileDataStateTracker(context, mHandler,
+ ConnectivityManager.TYPE_MOBILE_HIPRI, Phone.APN_TYPE_HIPRI,
+ "MOBILE_HIPRI");
- mActiveNetwork = null;
mNumDnsEntries = 0;
mTestMode = SystemProperties.get("cm.test.mode").equals("true")
@@ -149,8 +295,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
t.startMonitoring();
// Constructing this starts it too
- mWifiWatchdogService = new WifiWatchdogService(context,
- mWifiStateTracker);
+ mWifiWatchdogService = new WifiWatchdogService(context, wst);
}
/**
@@ -159,7 +304,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
*/
public synchronized void setNetworkPreference(int preference) {
enforceChangePermission();
- if (ConnectivityManager.isNetworkTypeValid(preference)) {
+ if (ConnectivityManager.isNetworkTypeValid(preference) &&
+ mNetAttributes[preference].isDefault()) {
if (mNetworkPreference != preference) {
persistNetworkPreference(preference);
mNetworkPreference = preference;
@@ -199,23 +345,16 @@ public class ConnectivityService extends IConnectivityManager.Stub {
* (see {@link #handleDisconnect(NetworkInfo)}).
*/
private void enforcePreference() {
- if (mActiveNetwork == null)
+ if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected())
return;
- for (NetworkStateTracker t : mNetTrackers) {
- if (t == mActiveNetwork) {
- int netType = t.getNetworkInfo().getType();
- int otherNetType = ((netType == ConnectivityManager.TYPE_WIFI) ?
- ConnectivityManager.TYPE_MOBILE :
- ConnectivityManager.TYPE_WIFI);
-
- if (t.getNetworkInfo().getType() != mNetworkPreference) {
- NetworkStateTracker otherTracker =
- mNetTrackers[otherNetType];
- if (otherTracker.isAvailable()) {
- teardown(t);
- }
- }
+ if (!mNetTrackers[mNetworkPreference].isAvailable())
+ return;
+
+ for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) {
+ if (t != mNetworkPreference &&
+ mNetTrackers[t].getNetworkInfo().isConnected()) {
+ teardown(mNetTrackers[t]);
}
}
}
@@ -238,9 +377,16 @@ public class ConnectivityService extends IConnectivityManager.Stub {
*/
public NetworkInfo getActiveNetworkInfo() {
enforceAccessPermission();
- for (NetworkStateTracker t : mNetTrackers) {
+ for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
+ if (!mNetAttributes[type].isDefault()) {
+ continue;
+ }
+ NetworkStateTracker t = mNetTrackers[type];
NetworkInfo info = t.getNetworkInfo();
if (info.isConnected()) {
+ if (DBG && type != mActiveDefaultNetwork) Log.e(TAG,
+ "connected default network is not " +
+ "mActiveDefaultNetwork!");
return info;
}
}
@@ -285,30 +431,189 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return tracker != null && tracker.setRadio(turnOn);
}
- public int startUsingNetworkFeature(int networkType, String feature) {
+ private class FeatureUser implements IBinder.DeathRecipient {
+ int mNetworkType;
+ String mFeature;
+ IBinder mBinder;
+ int mPid;
+ int mUid;
+
+ FeatureUser(int type, String feature, IBinder binder) {
+ super();
+ mNetworkType = type;
+ mFeature = feature;
+ mBinder = binder;
+ mPid = getCallingPid();
+ mUid = getCallingUid();
+ try {
+ mBinder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ binderDied();
+ }
+ }
+
+ void unlinkDeathRecipient() {
+ mBinder.unlinkToDeath(this, 0);
+ }
+
+ public void binderDied() {
+ Log.d(TAG, "ConnectivityService FeatureUser binderDied(" +
+ mNetworkType + ", " + mFeature + ", " + mBinder);
+ stopUsingNetworkFeature(mNetworkType, mFeature, mPid, mUid);
+ }
+
+ }
+
+ public int startUsingNetworkFeature(int networkType, String feature,
+ IBinder binder) {
+ if (DBG) {
+ Log.d(TAG, "startUsingNetworkFeature for net " + networkType +
+ ": " + feature);
+ }
enforceChangePermission();
if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
- return -1;
+ return Phone.APN_REQUEST_FAILED;
}
- NetworkStateTracker tracker = mNetTrackers[networkType];
- if (tracker != null) {
- return tracker.startUsingNetworkFeature(feature, getCallingPid(),
- getCallingUid());
+
+ synchronized (mFeatureUsers) {
+ mFeatureUsers.add(new FeatureUser(networkType, feature, binder));
+ }
+
+ // TODO - move this into the MobileDataStateTracker
+ int usedNetworkType = networkType;
+ if(networkType == ConnectivityManager.TYPE_MOBILE) {
+ if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
+ }
+ }
+ NetworkStateTracker network = mNetTrackers[usedNetworkType];
+ if (network != null) {
+ if (usedNetworkType != networkType) {
+ Integer currentPid = new Integer(getCallingPid());
+
+ NetworkStateTracker radio = mNetTrackers[networkType];
+ NetworkInfo ni = network.getNetworkInfo();
+
+ if (ni.isAvailable() == false) {
+ if (DBG) Log.d(TAG, "special network not available");
+ return Phone.APN_TYPE_NOT_AVAILABLE;
+ }
+
+ if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
+ // this gets used for per-pid dns when connected
+ mNetRequestersPids[usedNetworkType].add(currentPid);
+ }
+
+ if (ni.isConnectedOrConnecting() == true) {
+ if (ni.isConnected() == true) {
+ // add the pid-specific dns
+ handleDnsConfigurationChange();
+ if (DBG) Log.d(TAG, "special network already active");
+ return Phone.APN_ALREADY_ACTIVE;
+ }
+ if (DBG) Log.d(TAG, "special network already connecting");
+ return Phone.APN_REQUEST_STARTED;
+ }
+
+ // check if the radio in play can make another contact
+ // assume if cannot for now
+
+ // since we have to drop the default on this radio, setup
+ // an automatic event to switch back
+ if(mHandler.hasMessages(NetworkStateTracker.
+ EVENT_RESTORE_DEFAULT_NETWORK, radio) ||
+ radio.getNetworkInfo().isConnectedOrConnecting()) {
+ mHandler.removeMessages(NetworkStateTracker.
+ EVENT_RESTORE_DEFAULT_NETWORK,
+ radio);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(
+ NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK,
+ radio), getRestoreDefaultNetworkDelay());
+ }
+ if (DBG) Log.d(TAG, "reconnecting to special network");
+ network.reconnect();
+ return Phone.APN_REQUEST_STARTED;
+ } else {
+ return network.startUsingNetworkFeature(feature,
+ getCallingPid(), getCallingUid());
+ }
}
- return -1;
+ return Phone.APN_TYPE_NOT_AVAILABLE;
}
public int stopUsingNetworkFeature(int networkType, String feature) {
+ return stopUsingNetworkFeature(networkType, feature, getCallingPid(),
+ getCallingUid());
+ }
+
+ private int stopUsingNetworkFeature(int networkType, String feature,
+ int pid, int uid) {
+ if (DBG) {
+ Log.d(TAG, "stopUsingNetworkFeature for net " + networkType +
+ ": " + feature);
+ }
enforceChangePermission();
if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
return -1;
}
- NetworkStateTracker tracker = mNetTrackers[networkType];
- if (tracker != null) {
- return tracker.stopUsingNetworkFeature(feature, getCallingPid(),
- getCallingUid());
+
+ synchronized (mFeatureUsers) {
+ for (int i=0; i < mFeatureUsers.size(); i++) {
+ FeatureUser u = (FeatureUser)mFeatureUsers.get(i);
+ if (uid == u.mUid && pid == u.mPid &&
+ networkType == u.mNetworkType &&
+ TextUtils.equals(feature, u.mFeature)) {
+ u.unlinkDeathRecipient();
+ mFeatureUsers.remove(i);
+ break;
+ }
+ }
+ }
+
+ // TODO - move to MobileDataStateTracker
+ int usedNetworkType = networkType;
+ if (networkType == ConnectivityManager.TYPE_MOBILE) {
+ if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
+ }
+ }
+ NetworkStateTracker tracker = mNetTrackers[usedNetworkType];
+ if(usedNetworkType != networkType) {
+ Integer currentPid = new Integer(pid);
+ if (mNetRequestersPids[usedNetworkType].remove(currentPid)) {
+ reassessPidDns(pid, true);
+ }
+ if (mNetRequestersPids[usedNetworkType].size() != 0) {
+ if (DBG) Log.d(TAG, "not tearing down special network - " +
+ "others still using it");
+ return 1;
+ }
+
+ tracker.teardown();
+ NetworkStateTracker radio = mNetTrackers[networkType];
+ // Check if we want to revert to the default
+ if (mHandler.hasMessages(NetworkStateTracker.
+ EVENT_RESTORE_DEFAULT_NETWORK, radio)) {
+ mHandler.removeMessages(NetworkStateTracker.
+ EVENT_RESTORE_DEFAULT_NETWORK, radio);
+ radio.reconnect();
+ }
+ return 1;
+ } else {
+ return tracker.stopUsingNetworkFeature(feature, pid, uid);
}
- return -1;
}
/**
@@ -337,7 +642,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (getNumConnectedNetworks() > 1) {
return tracker.requestRouteToHost(hostAddress);
} else {
- return tracker.getNetworkInfo().getType() == networkType;
+ return (mNetAttributes[networkType].isDefault() &&
+ tracker.getNetworkInfo().isConnected());
}
}
@@ -402,45 +708,26 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private void handleDisconnect(NetworkInfo info) {
if (DBG) Log.v(TAG, "Handle DISCONNECT for " + info.getTypeName());
+ int prevNetType = info.getType();
- mNetTrackers[info.getType()].setTeardownRequested(false);
+ mNetTrackers[prevNetType].setTeardownRequested(false);
/*
* If the disconnected network is not the active one, then don't report
* this as a loss of connectivity. What probably happened is that we're
* getting the disconnect for a network that we explicitly disabled
* in accordance with network preference policies.
*/
- if (mActiveNetwork == null ||
- info.getType() != mActiveNetwork.getNetworkInfo().getType())
- return;
-
- NetworkStateTracker newNet;
- if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
- newNet = mWifiStateTracker;
- } else /* info().getType() == TYPE_WIFI */ {
- newNet = mMobileDataStateTracker;
- }
-
- /**
- * See if the other network is available to fail over to.
- * If is not available, we enable it anyway, so that it
- * will be able to connect when it does become available,
- * but we report a total loss of connectivity rather than
- * report that we are attempting to fail over.
- */
- NetworkInfo switchTo = null;
- if (newNet.isAvailable()) {
- mActiveNetwork = newNet;
- switchTo = newNet.getNetworkInfo();
- switchTo.setFailover(true);
- if (!switchTo.isConnectedOrConnecting()) {
- newNet.reconnect();
+ if (!mNetAttributes[prevNetType].isDefault()) {
+ List pids = mNetRequestersPids[prevNetType];
+ for (int i = 0; i<pids.size(); i++) {
+ Integer pid = (Integer)pids.get(i);
+ // will remove them because the net's no longer connected
+ // need to do this now as only now do we know the pids and
+ // can properly null things that are no longer referenced.
+ reassessPidDns(pid.intValue(), false);
}
- } else {
- newNet.reconnect();
}
- boolean otherNetworkConnected = false;
Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
if (info.isFailover()) {
@@ -454,33 +741,92 @@ public class ConnectivityService extends IConnectivityManager.Stub {
intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
info.getExtraInfo());
}
- if (switchTo != null) {
- otherNetworkConnected = switchTo.isConnected();
- if (DBG) {
- if (otherNetworkConnected) {
- Log.v(TAG, "Switching to already connected " +
- switchTo.getTypeName());
+
+ /*
+ * If this is a default network, check if other defaults are available
+ * or active
+ */
+ NetworkStateTracker newNet = null;
+ if (mNetAttributes[prevNetType].isDefault()) {
+ if (DBG) Log.d(TAG, "disconnecting a default network");
+ if (mActiveDefaultNetwork == prevNetType) {
+ mActiveDefaultNetwork = -1;
+ }
+
+ int newType = -1;
+ int newPriority = -1;
+ for (int checkType=0; checkType <=
+ ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
+ if (checkType == prevNetType) {
+ continue;
+ }
+ if (mNetAttributes[checkType].isDefault()) {
+ /* TODO - if we have multiple nets we could use
+ * we may want to put more thought into which we choose
+ */
+ if (checkType == mNetworkPreference) {
+ newType = checkType;
+ break;
+ }
+ if (mRadioAttributes[mNetAttributes[checkType].mRadio].
+ mPriority > newPriority) {
+ newType = checkType;
+ newPriority = mRadioAttributes[mNetAttributes[newType].
+ mRadio].mPriority;
+ }
+ }
+ }
+
+ if (newType != -1) {
+ newNet = mNetTrackers[newType];
+ /**
+ * See if the other network is available to fail over to.
+ * If is not available, we enable it anyway, so that it
+ * will be able to connect when it does become available,
+ * but we report a total loss of connectivity rather than
+ * report that we are attempting to fail over.
+ */
+ if (newNet.isAvailable()) {
+ NetworkInfo switchTo = newNet.getNetworkInfo();
+ switchTo.setFailover(true);
+ if (!switchTo.isConnectedOrConnecting()) {
+ newNet.reconnect();
+ }
+ if (DBG) {
+ if (switchTo.isConnected()) {
+ Log.v(TAG, "Switching to already connected " +
+ switchTo.getTypeName());
+ } else {
+ Log.v(TAG, "Attempting to switch to " +
+ switchTo.getTypeName());
+ }
+ }
+ intent.putExtra(ConnectivityManager.
+ EXTRA_OTHER_NETWORK_INFO, switchTo);
} else {
- Log.v(TAG, "Attempting to switch to " +
- switchTo.getTypeName());
+ newNet.reconnect();
}
+ } else {
+ intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY,
+ true);
}
- intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO,
- switchTo);
- } else {
- intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
}
+
+ // do this before we broadcast the change
+ handleConnectivityChange();
+
if (DBG) Log.v(TAG, "Sending DISCONNECT bcast for " +
info.getTypeName() +
- (switchTo == null ? "" : " other=" + switchTo.getTypeName()));
+ (newNet == null || !newNet.isAvailable() ? "" : " other=" +
+ newNet.getNetworkInfo().getTypeName()));
mContext.sendStickyBroadcast(intent);
/*
* If the failover network is already connected, then immediately send
* out a followup broadcast indicating successful failover
*/
- if (switchTo != null && otherNetworkConnected)
- sendConnectedBroadcast(switchTo);
+ if (newNet != null && newNet.getNetworkInfo().isConnected())
+ sendConnectedBroadcast(newNet.getNetworkInfo());
}
private void sendConnectedBroadcast(NetworkInfo info) {
@@ -506,93 +852,85 @@ public class ConnectivityService extends IConnectivityManager.Stub {
*/
private void handleConnectionFailure(NetworkInfo info) {
mNetTrackers[info.getType()].setTeardownRequested(false);
- if (getActiveNetworkInfo() == null) {
- String reason = info.getReason();
- String extraInfo = info.getExtraInfo();
- if (DBG) {
- String reasonText;
- if (reason == null) {
- reasonText = ".";
- } else {
- reasonText = " (" + reason + ").";
- }
- Log.v(TAG, "Attempt to connect to " + info.getTypeName() +
- " failed" + reasonText);
+ String reason = info.getReason();
+ String extraInfo = info.getExtraInfo();
+
+ if (DBG) {
+ String reasonText;
+ if (reason == null) {
+ reasonText = ".";
+ } else {
+ reasonText = " (" + reason + ").";
}
+ Log.v(TAG, "Attempt to connect to " + info.getTypeName() +
+ " failed" + reasonText);
+ }
- Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
- intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
+ Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
+ intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
+ 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);
- }
- mContext.sendStickyBroadcast(intent);
}
+ 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);
+ }
+ mContext.sendStickyBroadcast(intent);
}
private void handleConnect(NetworkInfo info) {
- if (DBG) Log.v(TAG, "Handle CONNECT for " + info.getTypeName());
+ if (DBG) Log.d(TAG, "Handle CONNECT for " + info.getTypeName());
+
+ int type = info.getType();
// snapshot isFailover, because sendConnectedBroadcast() resets it
boolean isFailover = info.isFailover();
- NetworkStateTracker thisNet = mNetTrackers[info.getType()];
- NetworkStateTracker deadnet = null;
- NetworkStateTracker otherNet;
- if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
- otherNet = mWifiStateTracker;
- } else /* info().getType() == TYPE_WIFI */ {
- otherNet = mMobileDataStateTracker;
- }
- /*
- * Check policy to see whether we are connected to a non-preferred
- * network that now needs to be torn down.
- */
- NetworkInfo wifiInfo = mWifiStateTracker.getNetworkInfo();
- NetworkInfo mobileInfo = mMobileDataStateTracker.getNetworkInfo();
- if (wifiInfo.isConnected() && mobileInfo.isConnected()) {
- if (mNetworkPreference == ConnectivityManager.TYPE_WIFI)
- deadnet = mMobileDataStateTracker;
- else
- deadnet = mWifiStateTracker;
- }
-
- boolean toredown = false;
- thisNet.setTeardownRequested(false);
- if (!mTestMode && deadnet != null) {
- if (DBG) Log.v(TAG, "Policy requires " +
- deadnet.getNetworkInfo().getTypeName() + " teardown");
- toredown = teardown(deadnet);
- if (DBG && !toredown) {
- Log.d(TAG, "Network declined teardown request");
- }
- }
-
- /*
- * Note that if toredown is true, deadnet cannot be null, so there is
- * no danger of a null pointer exception here..
- */
- if (!toredown || deadnet.getNetworkInfo().getType() != info.getType()) {
- mActiveNetwork = thisNet;
- if (DBG) Log.v(TAG, "Sending CONNECT bcast for " +
- info.getTypeName());
- thisNet.updateNetworkSettings();
- sendConnectedBroadcast(info);
- if (isFailover) {
- otherNet.releaseWakeLock();
+ NetworkStateTracker thisNet = mNetTrackers[type];
+
+ // if this is a default net and other default is running
+ // kill the one not preferred
+ if (mNetAttributes[type].isDefault()) {
+ if (DBG) Log.d(TAG, "connecting to a default network");
+ if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
+ if ((type != mNetworkPreference &&
+ mNetAttributes[mActiveDefaultNetwork].mPriority >
+ mNetAttributes[type].mPriority) ||
+ mNetworkPreference == mActiveDefaultNetwork) {
+ // don't accept this one
+ if (DBG) Log.v(TAG, "Not broadcasting CONNECT_ACTION " +
+ "to torn down network " + info.getTypeName());
+ teardown(thisNet);
+ return;
+ } else {
+ // tear down the other
+ NetworkStateTracker otherNet =
+ mNetTrackers[mActiveDefaultNetwork];
+ if (DBG) Log.v(TAG, "Policy requires " +
+ otherNet.getNetworkInfo().getTypeName() +
+ " teardown");
+ if (!teardown(otherNet)) {
+ Log.e(TAG, "Network declined teardown request");
+ return;
+ }
+ if (isFailover) {
+ otherNet.releaseWakeLock();
+ }
+ }
}
- } else {
- if (DBG) Log.v(TAG, "Not broadcasting CONNECT_ACTION to torn " +
- "down network " + info.getTypeName());
+ mActiveDefaultNetwork = type;
}
+ thisNet.setTeardownRequested(false);
+ if (DBG) Log.d(TAG, "Sending CONNECT bcast for " + info.getTypeName());
+ thisNet.updateNetworkSettings();
+ handleConnectivityChange();
+ sendConnectedBroadcast(info);
}
private void handleScanResultsAvailable(NetworkInfo info) {
@@ -626,60 +964,148 @@ public class ConnectivityService extends IConnectivityManager.Stub {
* table entries exist.
*/
private void handleConnectivityChange() {
+ if (DBG) Log.d(TAG, "handleConnectivityChange");
/*
+ * If a non-default network is enabled, add the host routes that
+ * will allow it's DNS servers to be accessed. Only
* If both mobile and wifi are enabled, add the host routes that
* will allow MMS traffic to pass on the mobile network. But
* remove the default route for the mobile network, so that there
* will be only one default route, to ensure that all traffic
* except MMS will travel via Wi-Fi.
*/
- int numConnectedNets = handleConfigurationChange();
- if (numConnectedNets > 1) {
- mMobileDataStateTracker.addPrivateRoutes();
- mMobileDataStateTracker.removeDefaultRoute();
- } else if (mMobileDataStateTracker.getNetworkInfo().isConnected()) {
- mMobileDataStateTracker.removePrivateRoutes();
- mMobileDataStateTracker.restoreDefaultRoute();
+ handleDnsConfigurationChange();
+
+ for (int netType : mPriorityList) {
+ if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
+ if (mNetAttributes[netType].isDefault()) {
+ mNetTrackers[netType].addDefaultRoute();
+ } else {
+ mNetTrackers[netType].addPrivateDnsRoutes();
+ }
+ } else {
+ if (mNetAttributes[netType].isDefault()) {
+ mNetTrackers[netType].removeDefaultRoute();
+ } else {
+ mNetTrackers[netType].removePrivateDnsRoutes();
+ }
+ }
}
}
- private int handleConfigurationChange() {
+ /**
+ * Adjust the per-process dns entries (net.dns<x>.<pid>) based
+ * on the highest priority active net which this process requested.
+ * If there aren't any, clear it out
+ */
+ private void reassessPidDns(int myPid, boolean doBump)
+ {
+ if (DBG) Log.d(TAG, "reassessPidDns for pid " + myPid);
+ for(int i : mPriorityList) {
+ if (mNetAttributes[i].isDefault()) {
+ continue;
+ }
+ NetworkStateTracker nt = mNetTrackers[i];
+ if (nt.getNetworkInfo().isConnected() &&
+ !nt.isTeardownRequested()) {
+ List pids = mNetRequestersPids[i];
+ for (int j=0; j<pids.size(); j++) {
+ Integer pid = (Integer)pids.get(j);
+ if (pid.intValue() == myPid) {
+ String[] dnsList = nt.getNameServers();
+ writePidDns(dnsList, myPid);
+ if (doBump) {
+ bumpDns();
+ }
+ return;
+ }
+ }
+ }
+ }
+ // nothing found - delete
+ for (int i = 1; ; i++) {
+ String prop = "net.dns" + i + "." + myPid;
+ if (SystemProperties.get(prop).length() == 0) {
+ if (doBump) {
+ bumpDns();
+ }
+ return;
+ }
+ SystemProperties.set(prop, "");
+ }
+ }
+
+ private void writePidDns(String[] dnsList, int pid) {
+ int j = 1;
+ for (String dns : dnsList) {
+ if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
+ SystemProperties.set("net.dns" + j++ + "." + pid, dns);
+ }
+ }
+ }
+
+ private void bumpDns() {
/*
- * Set DNS properties. Always put Wi-Fi entries at the front of
- * the list if it is active.
+ * Bump the property that tells the name resolver library to reread
+ * the DNS server list from the properties.
*/
- int index = 1;
- String lastDns = "";
- int numConnectedNets = 0;
- int incrValue = ConnectivityManager.TYPE_MOBILE -
- ConnectivityManager.TYPE_WIFI;
- int stopValue = ConnectivityManager.TYPE_MOBILE + incrValue;
+ String propVal = SystemProperties.get("net.dnschange");
+ int n = 0;
+ if (propVal.length() != 0) {
+ try {
+ n = Integer.parseInt(propVal);
+ } catch (NumberFormatException e) {}
+ }
+ SystemProperties.set("net.dnschange", "" + (n+1));
+ }
- for (int netType = ConnectivityManager.TYPE_WIFI; netType != stopValue;
- netType += incrValue) {
+ private void handleDnsConfigurationChange() {
+ if (DBG) Log.d(TAG, "handleDnsConfig Change");
+ // add default net's dns entries
+ for (int x = mPriorityList.length-1; x>= 0; x--) {
+ int netType = mPriorityList[x];
NetworkStateTracker nt = mNetTrackers[netType];
- if (nt.getNetworkInfo().isConnected() &&
+ if (DBG) Log.d(TAG, " checking " + nt);
+ if (nt != null && nt.getNetworkInfo().isConnected() &&
!nt.isTeardownRequested()) {
- ++numConnectedNets;
+ if (DBG) Log.d(TAG, " connected");
String[] dnsList = nt.getNameServers();
- for (int i = 0; i < dnsList.length && dnsList[i] != null; i++) {
- // skip duplicate entries
- if (!dnsList[i].equals(lastDns)) {
- SystemProperties.set("net.dns" + index++, dnsList[i]);
- lastDns = dnsList[i];
+ if (mNetAttributes[netType].isDefault()) {
+ int j = 1;
+ for (String dns : dnsList) {
+ if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
+ SystemProperties.set("net.dns" + j++, dns);
+ }
+ }
+ for (int k=j ; k<mNumDnsEntries; k++) {
+ SystemProperties.set("net.dns" + j, "");
+ }
+ mNumDnsEntries = j;
+ } else {
+ // set per-pid dns for attached secondary nets
+ List pids = mNetRequestersPids[netType];
+ for (int y=0; y< pids.size(); y++) {
+ Integer pid = (Integer)pids.get(y);
+ writePidDns(dnsList, pid.intValue());
}
}
}
}
- // Null out any DNS properties that are no longer used
- for (int i = index; i <= mNumDnsEntries; i++) {
- SystemProperties.set("net.dns" + i, "");
+
+ bumpDns();
+ }
+
+ private int getRestoreDefaultNetworkDelay() {
+ String restoreDefaultNetworkDelayStr = SystemProperties.get(
+ NETWORK_RESTORE_DELAY_PROP_NAME);
+ if(restoreDefaultNetworkDelayStr != null &&
+ restoreDefaultNetworkDelayStr.length() != 0) {
+ try {
+ return Integer.valueOf(restoreDefaultNetworkDelayStr);
+ } catch (NumberFormatException e) {
+ }
}
- mNumDnsEntries = index - 1;
- // Notify the name resolver library of the change
- SystemProperties.set("net.dnschange",
- String.valueOf(sDnsChangeCounter++));
- return numConnectedNets;
+ return RESTORE_DEFAULT_NETWORK_DELAY;
}
@Override
@@ -692,20 +1118,19 @@ public class ConnectivityService extends IConnectivityManager.Stub {
Binder.getCallingUid());
return;
}
- if (mActiveNetwork == null) {
- pw.println("No active network");
- } else {
- pw.println("Active network: " +
- mActiveNetwork.getNetworkInfo().getTypeName());
- }
pw.println();
for (NetworkStateTracker nst : mNetTrackers) {
+ if (nst.getNetworkInfo().isConnected()) {
+ pw.println("Active network: " + nst.getNetworkInfo().
+ getTypeName());
+ }
pw.println(nst.getNetworkInfo());
pw.println(nst);
pw.println();
}
}
+ // must be stateless - things change under us.
private class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
@@ -713,7 +1138,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
switch (msg.what) {
case NetworkStateTracker.EVENT_STATE_CHANGED:
info = (NetworkInfo) msg.obj;
- if (DBG) Log.v(TAG, "ConnectivityChange for " +
+ if (DBG) Log.d(TAG, "ConnectivityChange for " +
info.getTypeName() + ": " +
info.getState() + "/" + info.getDetailedState());
@@ -748,7 +1173,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
} else if (info.getState() == NetworkInfo.State.CONNECTED) {
handleConnect(info);
}
- handleConnectivityChange();
break;
case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE:
@@ -761,7 +1185,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
(Notification) msg.obj);
case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
- handleConfigurationChange();
+ handleDnsConfigurationChange();
break;
case NetworkStateTracker.EVENT_ROAMING_CHANGED:
@@ -771,6 +1195,15 @@ public class ConnectivityService extends IConnectivityManager.Stub {
case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED:
// fill me in
break;
+ case NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK:
+ for (NetworkStateTracker net : mNetTrackers) {
+ NetworkInfo i = net.getNetworkInfo();
+ if (i.isConnected() &&
+ !mNetAttributes[i.getType()].isDefault()) {
+ teardown(net);
+ }
+ }
+ break;
}
}
}
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 9f2856c..7379b5d 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -88,6 +88,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
private String mDataConnectionApn = "";
+ private String[] mDataConnectionApnTypes = null;
+
private String mDataConnectionInterfaceName = "";
private Bundle mCellLocation = new Bundle();
@@ -337,7 +339,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
- String reason, String apn, String interfaceName) {
+ String reason, String apn, String[] apnTypes, String interfaceName) {
if (!checkNotifyPermission("notifyDataConnection()" )) {
return;
}
@@ -346,6 +348,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
mDataConnectionPossible = isDataConnectivityPossible;
mDataConnectionReason = reason;
mDataConnectionApn = apn;
+ mDataConnectionApnTypes = apnTypes;
mDataConnectionInterfaceName = interfaceName;
for (int i = mRecords.size() - 1; i >= 0; i--) {
Record r = mRecords.get(i);
@@ -359,7 +362,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
- interfaceName);
+ apnTypes, interfaceName);
}
public void notifyDataConnectionFailed(String reason) {
@@ -517,8 +520,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
mContext.sendBroadcast(intent, android.Manifest.permission.READ_PHONE_STATE);
}
- private void broadcastDataConnectionStateChanged(int state, boolean isDataConnectivityPossible,
- String reason, String apn, String interfaceName) {
+ private void broadcastDataConnectionStateChanged(int state,
+ boolean isDataConnectivityPossible,
+ String reason, String apn, String[] apnTypes, String interfaceName) {
// Note: not reporting to the battery stats service here, because the
// status bar takes care of that after taking into account all of the
// required info.
@@ -531,6 +535,11 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
intent.putExtra(Phone.STATE_CHANGE_REASON_KEY, reason);
}
intent.putExtra(Phone.DATA_APN_KEY, apn);
+ String types = apnTypes[0];
+ for (int i = 1; i < apnTypes.length; i++) {
+ types = types+","+apnTypes[i];
+ }
+ intent.putExtra(Phone.DATA_APN_TYPES_KEY, types);
intent.putExtra(Phone.DATA_IFACE_NAME_KEY, interfaceName);
mContext.sendStickyBroadcast(intent);
}
diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index d6151c6..00d7c72 100644
--- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -94,8 +94,11 @@ public class DefaultPhoneNotifier implements PhoneNotifier {
public void notifyDataConnection(Phone sender, String reason) {
try {
- mRegistry.notifyDataConnection(convertDataState(sender.getDataConnectionState()),
- sender.isDataConnectivityPossible(), reason, sender.getActiveApn(),
+ mRegistry.notifyDataConnection(
+ convertDataState(sender.getDataConnectionState()),
+ sender.isDataConnectivityPossible(), reason,
+ sender.getActiveApn(),
+ sender.getActiveApnTypes(),
sender.getInterfaceName(null));
} catch (RemoteException ex) {
// system process is dead
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 865c6ca..6b42e6b 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -32,7 +32,7 @@ interface ITelephonyRegistry {
void notifyCallForwardingChanged(boolean cfi);
void notifyDataActivity(int state);
void notifyDataConnection(int state, boolean isDataConnectivityPossible,
- String reason, String apn, String interfaceName);
+ String reason, String apn, in String[] apnTypes, String interfaceName);
void notifyDataConnectionFailed(String reason);
void notifyCellLocation(in Bundle cellLocation);
}
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 86ea12b..622b47d 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -99,8 +99,9 @@ public interface Phone {
static final String PHONE_NAME_KEY = "phoneName";
static final String FAILURE_REASON_KEY = "reason";
static final String STATE_CHANGE_REASON_KEY = "reason";
- static final String DATA_APN_TYPE_KEY = "apnType";
+ static final String DATA_APN_TYPES_KEY = "apnType";
static final String DATA_APN_KEY = "apn";
+
static final String DATA_IFACE_NAME_KEY = "iface";
static final String NETWORK_UNAVAILABLE_KEY = "networkUnvailable";
static final String PHONE_IN_ECM_STATE = "phoneinECMState";
@@ -120,10 +121,16 @@ public interface Phone {
static final String APN_TYPE_MMS = "mms";
/** APN type for SUPL assisted GPS */
static final String APN_TYPE_SUPL = "supl";
+ /** APN type for DUN traffic */
+ static final String APN_TYPE_DUN = "dun";
+ /** APN type for HiPri traffic */
+ static final String APN_TYPE_HIPRI = "hipri";
// "Features" accessible through the connectivity manager
static final String FEATURE_ENABLE_MMS = "enableMMS";
static final String FEATURE_ENABLE_SUPL = "enableSUPL";
+ static final String FEATURE_ENABLE_DUN = "enableDUN";
+ static final String FEATURE_ENABLE_HIPRI = "enableHIPRI";
/**
* Return codes for <code>enableApnType()</code>
diff --git a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java
index 3ca39de..dc6f92d 100644
--- a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java
+++ b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java
@@ -72,7 +72,10 @@ public class ApnSetting {
boolean canHandleType(String type) {
for (String t : types) {
- if (t.equals(type) || t.equals(Phone.APN_TYPE_ALL)) {
+ // DEFAULT handles all, and HIPRI is handled by DEFAULT
+ if (t.equals(type) || t.equals(Phone.APN_TYPE_ALL) ||
+ (t.equals(Phone.APN_TYPE_DEFAULT) &&
+ type.equals(Phone.APN_TYPE_HIPRI))) {
return true;
}
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 8b3529f..bf60bfe 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -135,12 +135,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
/** Currently active PdpConnection */
private PdpConnection mActivePdp;
+ private static int APN_INVALID_ID = -1;
private static int APN_DEFAULT_ID = 0;
private static int APN_MMS_ID = 1;
private static int APN_SUPL_ID = 2;
- private static int APN_NUM_TYPES = 3;
+ private static int APN_DUN_ID = 3;
+ private static int APN_HIPRI_ID = 4;
+ private static int APN_NUM_TYPES = 5;
private boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
+ private int enabledCount = 0;
/** Is packet service restricted by network */
private boolean mIsPsRestricted = false;
@@ -213,7 +217,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
GsmDataConnectionTracker(GSMPhone p) {
super(p);
mGsmPhone = p;
-
p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null);
p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
p.mSIMRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
@@ -252,6 +255,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
// and 2) whether the RIL will setup the baseband to auto-PS attach.
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
dataEnabled[APN_DEFAULT_ID] = !sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false);
+ if (dataEnabled[APN_DEFAULT_ID]) {
+ enabledCount++;
+ }
noAutoAttach = !dataEnabled[APN_DEFAULT_ID];
if (!mRetryMgr.configure(SystemProperties.get("ro.gsm.data_retry_config"))) {
@@ -332,6 +338,22 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
return result;
}
+ protected int apnTypeToId(String type) {
+ if (TextUtils.equals(type, Phone.APN_TYPE_DEFAULT)) {
+ return APN_DEFAULT_ID;
+ } else if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
+ return APN_MMS_ID;
+ } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) {
+ return APN_SUPL_ID;
+ } else if (TextUtils.equals(type, Phone.APN_TYPE_DUN)) {
+ return APN_DUN_ID;
+ } else if (TextUtils.equals(type, Phone.APN_TYPE_HIPRI)) {
+ return APN_HIPRI_ID;
+ } else {
+ return APN_INVALID_ID;
+ }
+ }
+
/**
* Ensure that we are connected to an APN of the specified type.
* @param type the APN type (currently the only valid values
@@ -343,25 +365,15 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
* the APN has been established.
*/
protected int enableApnType(String type) {
- if (!TextUtils.equals(type, Phone.APN_TYPE_MMS) &&
- !TextUtils.equals(type, Phone.APN_TYPE_SUPL)) {
+ int id = apnTypeToId(type);
+ if (id == APN_INVALID_ID) {
return Phone.APN_REQUEST_FAILED;
}
// If already active, return
- Log.d(LOG_TAG, "enableApnType("+type+")");
+ if(DBG) Log.d(LOG_TAG, "enableApnType("+type+"), isApnTypeActive = "
+ + isApnTypeActive(type) + " and state = " + state);
if (isApnTypeActive(type)) {
- setEnabled(type, true);
- removeMessages(EVENT_RESTORE_DEFAULT_APN);
- /**
- * We're being asked to enable a non-default APN that's already in use.
- * This means we should restart the timer that will automatically
- * switch back to the default APN and disable the non-default APN
- * when it expires.
- */
- sendMessageDelayed(
- obtainMessage(EVENT_RESTORE_DEFAULT_APN),
- getRestoreDefaultApnDelay());
if (state == State.INITING) return Phone.APN_REQUEST_STARTED;
else if (state == State.CONNECTED) return Phone.APN_ALREADY_ACTIVE;
}
@@ -370,7 +382,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
return Phone.APN_TYPE_NOT_AVAILABLE;
}
- setEnabled(type, true);
+ setEnabled(id, true);
mRequestedApnType = type;
sendMessage(obtainMessage(EVENT_ENABLE_NEW_APN));
return Phone.APN_REQUEST_STARTED;
@@ -385,31 +397,21 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
* @return
*/
protected int disableApnType(String type) {
- Log.d(LOG_TAG, "disableApnType("+type+")");
- if ((TextUtils.equals(type, Phone.APN_TYPE_MMS) ||
- TextUtils.equals(type, Phone.APN_TYPE_SUPL))
- && isEnabled(type)) {
- removeMessages(EVENT_RESTORE_DEFAULT_APN);
- setEnabled(type, false);
+ if (DBG) Log.d(LOG_TAG, "disableApnType("+type+")");
+ int id = apnTypeToId(type);
+ if (id == APN_INVALID_ID) {
+ return Phone.APN_REQUEST_FAILED;
+ }
+ if (isEnabled(id)) {
+ setEnabled(id, false);
if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
mRequestedApnType = Phone.APN_TYPE_DEFAULT;
if (dataEnabled[APN_DEFAULT_ID]) {
return Phone.APN_ALREADY_ACTIVE;
} else {
- Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
- msg.arg1 = 1; // tearDown is true;
- msg.obj = Phone.REASON_DATA_DISABLED;
- sendMessage(msg);
return Phone.APN_REQUEST_STARTED;
}
} else {
- /*
- * Note that if default data is disabled, the following
- * has the effect of disabling the MMS APN, and then
- * ignoring the request to enable the default APN.
- * The net result is that data is completely disabled.
- */
- sendMessage(obtainMessage(EVENT_RESTORE_DEFAULT_APN));
return Phone.APN_REQUEST_STARTED;
}
} else {
@@ -455,30 +457,30 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
return false;
}
- private boolean isEnabled(String apnType) {
- if (TextUtils.equals(apnType, Phone.APN_TYPE_DEFAULT)) {
- return dataEnabled[APN_DEFAULT_ID];
- } else if (TextUtils.equals(apnType, Phone.APN_TYPE_MMS)) {
- return dataEnabled[APN_MMS_ID];
- } else if (TextUtils.equals(apnType, Phone.APN_TYPE_SUPL)) {
- return dataEnabled[APN_SUPL_ID];
- } else {
- return false;
+ private boolean isEnabled(int id) {
+ if (id != APN_INVALID_ID) {
+ return dataEnabled[id];
}
+ return false;
}
- private void setEnabled(String apnType, boolean enable) {
- Log.d(LOG_TAG, "setEnabled(" + apnType + ", " + enable + ')');
- if (TextUtils.equals(apnType, Phone.APN_TYPE_DEFAULT)) {
- dataEnabled[APN_DEFAULT_ID] = enable;
- } else if (TextUtils.equals(apnType, Phone.APN_TYPE_MMS)) {
- dataEnabled[APN_MMS_ID] = enable;
- } else if (TextUtils.equals(apnType, Phone.APN_TYPE_SUPL)) {
- dataEnabled[APN_SUPL_ID] = enable;
+ private void setEnabled(int id, boolean enable) {
+ if (DBG) Log.d(LOG_TAG, "setEnabled(" + id + ", " + enable + ')');
+ if (dataEnabled[id] != enable) {
+ dataEnabled[id] = enable;
+
+ if (enable) {
+ enabledCount++;
+ } else {
+ enabledCount--;
+ }
+
+ if (enabledCount == 0) {
+ setPrivateDataEnabled(false);
+ } else if (enabledCount == 1) {
+ setPrivateDataEnabled(true);
+ }
}
- Log.d(LOG_TAG, "dataEnabled[DEFAULT_APN]=" + dataEnabled[APN_DEFAULT_ID] +
- " dataEnabled[MMS_APN]=" + dataEnabled[APN_MMS_ID] +
- " dataEnabled[SUPL_APN]=" + dataEnabled[APN_SUPL_ID]);
}
/**
@@ -493,30 +495,20 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
* @return {@code true} if the operation succeeded
*/
public boolean setDataEnabled(boolean enable) {
- boolean isEnabled = isEnabled(Phone.APN_TYPE_DEFAULT);
- Log.d(LOG_TAG, "setDataEnabled("+enable+") isEnabled=" + isEnabled);
- if (!isEnabled && enable) {
- setEnabled(Phone.APN_TYPE_DEFAULT, true);
- // trySetupData() will be a no-op if we are currently
- // connected to the MMS APN
+ if (DBG) Log.d(LOG_TAG, "setDataEnabled("+enable+")");
+ setEnabled(APN_DEFAULT_ID, enable);
+ return true;
+ }
+
+ private void setPrivateDataEnabled(boolean enable) {
+ if (DBG) Log.d(LOG_TAG, "setPrivateDataEnabled("+enable+")");
+ if (enable) {
sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
- return true;
- } else if (!enable) {
- setEnabled(Phone.APN_TYPE_DEFAULT, false);
- // Don't tear down if there is an active APN and it handles MMS or SUPL.
- // TODO: This isn't very general.
- if ((isApnTypeActive(Phone.APN_TYPE_MMS) && isEnabled(Phone.APN_TYPE_MMS)) ||
- (isApnTypeActive(Phone.APN_TYPE_SUPL) && isEnabled(Phone.APN_TYPE_SUPL))) {
- return false;
- }
+ } else {
Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
msg.arg1 = 1; // tearDown is true
msg.obj = Phone.REASON_DATA_DISABLED;
sendMessage(msg);
- return true;
- } else {
- // isEnabled && enable
- return true;
}
}
@@ -536,7 +528,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
* {@code true} otherwise.
*/
public boolean getAnyDataEnabled() {
- return dataEnabled[APN_DEFAULT_ID] || dataEnabled[APN_MMS_ID] || dataEnabled[APN_SUPL_ID];
+ return (enabledCount != 0);
}
/**
@@ -618,7 +610,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
if (DBG) {
- log ("Setup watingApns : " + apnListToString(waitingApns));
+ log ("Setup waitngApns : " + apnListToString(waitingApns));
}
return setupData(reason);
} else {
@@ -629,6 +621,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
" sim=" + mGsmPhone.mSIMRecords.getRecordsLoaded() +
" UMTS=" + mGsmPhone.mSST.isConcurrentVoiceAndData() +
" phoneState=" + phone.getState() +
+ " isDataAllowed=" + isDataAllowed() +
" dataEnabled=" + getAnyDataEnabled() +
" roaming=" + roaming +
" dataOnRoamingEnable=" + getDataOnRoamingEnabled() +
@@ -1251,15 +1244,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
trySetupData(reason);
}
- protected void onRestoreDefaultApn() {
- if (DBG) Log.d(LOG_TAG, "Restore default APN");
- setEnabled(Phone.APN_TYPE_MMS, false);
- mRequestedApnType = Phone.APN_TYPE_DEFAULT;
- if (!isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
- cleanUpConnection(true, Phone.REASON_RESTORE_DEFAULT_APN);
- }
- }
-
protected void onRoamingOff() {
trySetupData(Phone.REASON_ROAMING_OFF);
}
@@ -1313,22 +1297,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if (ar.exception == null) {
// everything is setup
-
- /*
- * We may have switched away from the default PDP context
- * in order to enable a "special" APN (e.g., for MMS
- * traffic). Set a timer to switch back and/or disable the
- * special APN, so that a negligient application doesn't
- * permanently prevent data connectivity. What we are
- * protecting against here is not malicious apps, but
- * rather an app that inadvertantly fails to reset to the
- * default APN, or that dies before doing so.
- */
- if (dataEnabled[APN_MMS_ID] || dataEnabled[APN_SUPL_ID]) {
- removeMessages(EVENT_RESTORE_DEFAULT_APN);
- sendMessageDelayed(obtainMessage(EVENT_RESTORE_DEFAULT_APN),
- getRestoreDefaultApnDelay());
- }
if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
SystemProperties.set("gsm.defaultpdpcontext.active", "true");
if (canSetPreferApn && preferredApn == null) {
@@ -1432,18 +1400,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
cleanUpConnection(tearDown, reason);
}
- private int getRestoreDefaultApnDelay() {
- String restoreApnDelayStr = SystemProperties.get(APN_RESTORE_DELAY_PROP_NAME);
-
- if (restoreApnDelayStr != null && restoreApnDelayStr.length() != 0) {
- try {
- return Integer.valueOf(restoreApnDelayStr);
- } catch (NumberFormatException e) {
- }
- }
- return RESTORE_DEFAULT_APN_DELAY;
- }
-
/**
* Based on the sim operator numeric, create a list for all possible pdps
* with all apns associated with that pdp
@@ -1568,10 +1524,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
private void startDelayedRetry(PdpConnection.FailCause cause, String reason) {
notifyNoData(cause);
- if (mRequestedApnType != Phone.APN_TYPE_DEFAULT) {
- sendMessage(obtainMessage(EVENT_RESTORE_DEFAULT_APN));
- }
- else {
+ if (mRequestedApnType == Phone.APN_TYPE_DEFAULT) {
reconnectAfterFail(cause, reason);
}
}
@@ -1626,7 +1579,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
public void handleMessage (Message msg) {
-
+ if (DBG) Log.d(LOG_TAG,"GSMDataConnTrack handleMessage "+msg);
switch (msg.what) {
case EVENT_RECORDS_LOADED:
onRecordsLoaded();
@@ -1636,10 +1589,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
onEnableNewApn();
break;
- case EVENT_RESTORE_DEFAULT_APN:
- onRestoreDefaultApn();
- break;
-
case EVENT_GPRS_DETACHED:
onGprsDetached();
break;