Code drop from //branches/cupcake/...@124589
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index f776abf..8c82212 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -99,24 +99,38 @@
}
private int mNetworkType;
+ private int mSubtype;
+ private String mTypeName;
+ private String mSubtypeName;
private State mState;
private DetailedState mDetailedState;
private String mReason;
private String mExtraInfo;
private boolean mIsFailover;
+ private boolean mIsRoaming;
/**
* Indicates whether network connectivity is possible:
*/
private boolean mIsAvailable;
- public NetworkInfo(int type) {
+ /**
+ * TODO This is going away as soon as API council review happens.
+ * @param type network type
+ */
+ public NetworkInfo(int type) {}
+
+ NetworkInfo(int type, int subtype, String typeName, String subtypeName) {
if (!ConnectivityManager.isNetworkTypeValid(type)) {
throw new IllegalArgumentException("Invalid network type: " + type);
}
- this.mNetworkType = type;
+ mNetworkType = type;
+ mSubtype = subtype;
+ mTypeName = typeName;
+ mSubtypeName = subtypeName;
setDetailedState(DetailedState.IDLE, null, null);
mState = State.UNKNOWN;
mIsAvailable = true;
+ mIsRoaming = false;
}
/**
@@ -129,6 +143,41 @@
}
/**
+ * Return a network-type-specific integer describing the subtype
+ * of the network.
+ * @return the network subtype
+ *
+ * @hide pending API council review
+ */
+ public int getSubtype() {
+ return mSubtype;
+ }
+
+ void setSubtype(int subtype, String subtypeName) {
+ mSubtype = subtype;
+ mSubtypeName = subtypeName;
+ }
+
+ /**
+ * Return a human-readable name describe the type of the network,
+ * for example "WIFI" or "MOBILE".
+ * @return the name of the network type
+ */
+ public String getTypeName() {
+ return mTypeName;
+ }
+
+ /**
+ * Return a human-readable name describing the subtype of the network.
+ * @return the name of the network subtype
+ *
+ * @hide pending API council review
+ */
+ public String getSubtypeName() {
+ return mSubtypeName;
+ }
+
+ /**
* Indicates whether network connectivity exists or is in the process
* of being established. This is good for applications that need to
* do anything related to the network other than read or write data.
@@ -170,7 +219,7 @@
* Sets if the network is available, ie, if the connectivity is possible.
* @param isAvailable the new availability value.
*
- * {@hide}
+ * @hide
*/
public void setIsAvailable(boolean isAvailable) {
mIsAvailable = isAvailable;
@@ -187,12 +236,33 @@
return mIsFailover;
}
- /** {@hide} */
+ /**
+ * Set the failover boolean.
+ * @param isFailover {@code true} to mark the current connection attempt
+ * as a failover.
+ * @hide
+ */
public void setFailover(boolean isFailover) {
mIsFailover = isFailover;
}
/**
+ * Indicates whether the device is currently roaming on this network.
+ * When {@code true}, it suggests that use of data on this network
+ * may incur extra costs.
+ * @return {@code true} if roaming is in effect, {@code false} otherwise.
+ *
+ * @hide pending API council
+ */
+ public boolean isRoaming() {
+ return mIsRoaming;
+ }
+
+ void setRoaming(boolean isRoaming) {
+ mIsRoaming = isRoaming;
+ }
+
+ /**
* Reports the current coarse-grained state of the network.
* @return the coarse-grained state
*/
@@ -215,8 +285,6 @@
* if one was supplied. May be {@code null}.
* @param extraInfo an optional {@code String} providing addditional network state
* information passed up from the lower networking layers.
- *
- * {@hide}
*/
void setDetailedState(DetailedState detailedState, String reason, String extraInfo) {
this.mDetailedState = detailedState;
@@ -247,52 +315,59 @@
@Override
public String toString() {
StringBuilder builder = new StringBuilder("NetworkInfo: ");
- builder.append("type: ").append(getTypeName()).append(", state: ").append(mState).
- append("/").append(mDetailedState).
+ builder.append("type: ").append(getTypeName()).append("[").append(getSubtypeName()).
+ append("], state: ").append(mState).append("/").append(mDetailedState).
append(", reason: ").append(mReason == null ? "(unspecified)" : mReason).
append(", extra: ").append(mExtraInfo == null ? "(none)" : mExtraInfo).
+ append(", roaming: ").append(mIsRoaming).
append(", failover: ").append(mIsFailover).
append(", isAvailable: ").append(mIsAvailable);
return builder.toString();
}
- public String getTypeName() {
- switch (mNetworkType) {
- case ConnectivityManager.TYPE_WIFI:
- return "WIFI";
- case ConnectivityManager.TYPE_MOBILE:
- return "MOBILE";
- default:
- return "<invalid>";
- }
- }
-
- /** Implement the Parcelable interface {@hide} */
+ /**
+ * Implement the Parcelable interface
+ * @hide
+ */
public int describeContents() {
return 0;
}
- /** Implement the Parcelable interface {@hide} */
+ /**
+ * Implement the Parcelable interface.
+ * @hide
+ */
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mNetworkType);
+ dest.writeInt(mSubtype);
+ dest.writeString(mTypeName);
+ dest.writeString(mSubtypeName);
dest.writeString(mState.name());
dest.writeString(mDetailedState.name());
dest.writeInt(mIsFailover ? 1 : 0);
dest.writeInt(mIsAvailable ? 1 : 0);
+ dest.writeInt(mIsRoaming ? 1 : 0);
dest.writeString(mReason);
dest.writeString(mExtraInfo);
}
- /** Implement the Parcelable interface {@hide} */
+ /**
+ * Implement the Parcelable interface.
+ * @hide
+ */
public static final Creator<NetworkInfo> CREATOR =
new Creator<NetworkInfo>() {
public NetworkInfo createFromParcel(Parcel in) {
int netType = in.readInt();
- NetworkInfo netInfo = new NetworkInfo(netType);
+ int subtype = in.readInt();
+ String typeName = in.readString();
+ String subtypeName = in.readString();
+ NetworkInfo netInfo = new NetworkInfo(netType, subtype, typeName, subtypeName);
netInfo.mState = State.valueOf(in.readString());
netInfo.mDetailedState = DetailedState.valueOf(in.readString());
netInfo.mIsFailover = in.readInt() != 0;
netInfo.mIsAvailable = in.readInt() != 0;
+ netInfo.mIsRoaming = in.readInt() != 0;
netInfo.mReason = in.readString();
netInfo.mExtraInfo = in.readString();
return netInfo;
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 129248a..1153648 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -67,6 +67,14 @@
public native static boolean stopDhcp(String interfaceName);
/**
+ * Release the current DHCP lease.
+ * @param interfaceName the name of the interface for which the lease should
+ * be released
+ * @return {@code true} for success, {@code false} for failure
+ */
+ public native static boolean releaseDhcpLease(String interfaceName);
+
+ /**
* Return the last DHCP-related error message that was recorded.
* <p/>NOTE: This string is not localized, but currently it is only
* used in logging.
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 417ce54..8383deb 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -41,6 +41,7 @@
in_addr_t *server,
uint32_t *lease);
int dhcp_stop(const char *ifname);
+int dhcp_release_lease(const char *ifname);
char *dhcp_get_errmsg();
}
@@ -157,7 +158,7 @@
return (jboolean)(result == 0);
}
-static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname)
{
int result;
@@ -167,6 +168,16 @@
return (jboolean)(result == 0);
}
+static jboolean android_net_utils_releaseDhcpLease(JNIEnv* env, jobject clazz, jstring ifname)
+{
+ int result;
+
+ const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+ result = ::dhcp_release_lease(nameStr);
+ env->ReleaseStringUTFChars(ifname, nameStr);
+ return (jboolean)(result == 0);
+}
+
static jstring android_net_utils_getDhcpError(JNIEnv* env, jobject clazz)
{
return env->NewStringUTF(::dhcp_get_errmsg());
@@ -207,6 +218,7 @@
{ "resetConnections", "(Ljava/lang/String;)I", (void *)android_net_utils_resetConnections },
{ "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfo;)Z", (void *)android_net_utils_runDhcp },
{ "stopDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_stopDhcp },
+ { "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease },
{ "configureNative", "(Ljava/lang/String;IIIII)Z", (void *)android_net_utils_configureInterface },
{ "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
};
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 11f34cc..65e3650 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -35,7 +35,6 @@
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.provider.Settings;
-import android.telephony.TelephonyManager;
import android.util.EventLog;
import android.util.Log;
@@ -43,7 +42,7 @@
import java.io.PrintWriter;
/**
- * {@hide}
+ * @hide
*/
public class ConnectivityService extends IConnectivityManager.Stub {
@@ -59,7 +58,6 @@
* abstractly.
*/
private NetworkStateTracker mNetTrackers[];
- private boolean mTeardownRequested[];
private WifiStateTracker mWifiStateTracker;
private MobileDataStateTracker mMobileDataStateTracker;
private WifiWatchdogService mWifiWatchdogService;
@@ -69,11 +67,11 @@
private NetworkStateTracker mActiveNetwork;
private int mNumDnsEntries;
- private static int mDnsChangeCounter;
+ private static int sDnsChangeCounter;
private boolean mTestMode;
private static ConnectivityService sServiceInstance;
-
+
private static class ConnectivityThread extends Thread {
private Context mContext;
@@ -101,7 +99,9 @@
try {
// Wait until sServiceInstance has been initialized.
thread.wait();
- } catch (InterruptedException e) {
+ } catch (InterruptedException ignore) {
+ Log.e(TAG,
+ "Unexpected InterruptedException while waiting for ConnectivityService thread");
}
}
}
@@ -118,7 +118,6 @@
if (DBG) Log.v(TAG, "ConnectivityService starting up");
mContext = context;
mNetTrackers = new NetworkStateTracker[2];
- mTeardownRequested = new boolean[2];
Handler handler = new MyHandler();
mNetworkPreference = getPersistedNetworkPreference();
@@ -134,7 +133,6 @@
mWifiStateTracker = new WifiStateTracker(context, handler);
WifiService wifiService = new WifiService(context, mWifiStateTracker);
ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
- // The WifiStateTracker should appear first in the list
mNetTrackers[ConnectivityManager.TYPE_WIFI] = mWifiStateTracker;
mMobileDataStateTracker = new MobileDataStateTracker(context, handler);
@@ -160,10 +158,11 @@
public synchronized void setNetworkPreference(int preference) {
enforceChangePermission();
if (ConnectivityManager.isNetworkTypeValid(preference)) {
- int oldPreference = mNetworkPreference;
- persistNetworkPreference(preference);
- if (mNetworkPreference != oldPreference)
+ if (mNetworkPreference != preference) {
+ persistNetworkPreference(preference);
+ mNetworkPreference = preference;
enforcePreference();
+ }
}
}
@@ -174,14 +173,14 @@
private void persistNetworkPreference(int networkPreference) {
final ContentResolver cr = mContext.getContentResolver();
- Settings.System.putInt(cr, Settings.System.NETWORK_PREFERENCE, networkPreference);
+ Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, networkPreference);
}
private int getPersistedNetworkPreference() {
final ContentResolver cr = mContext.getContentResolver();
- final int networkPrefSetting = Settings.System
- .getInt(cr, Settings.System.NETWORK_PREFERENCE, -1);
+ final int networkPrefSetting = Settings.Secure
+ .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1);
if (networkPrefSetting != -1) {
return networkPrefSetting;
}
@@ -219,7 +218,7 @@
private boolean teardown(NetworkStateTracker netTracker) {
if (netTracker.teardown()) {
- mTeardownRequested[netTracker.getNetworkInfo().getType()] = true;
+ netTracker.setTeardownRequested(true);
return true;
} else {
return false;
@@ -227,9 +226,9 @@
}
/**
- * Return NetworkInfo for the active network interface. It is assumed that at most
- * one network is active at a time. If more than one is active, it is indeterminate
- * which will be returned.
+ * Return NetworkInfo for the active (i.e., connected) network interface.
+ * It is assumed that at most one network is active at a time. If more
+ * than one is active, it is indeterminate which will be returned.
* @return the info for the active network, or {@code null} if none is active
*/
public NetworkInfo getActiveNetworkInfo() {
@@ -291,7 +290,6 @@
return tracker.startUsingNetworkFeature(feature, getCallingPid(), getCallingUid());
}
return -1;
-
}
public int stopUsingNetworkFeature(int networkType, String feature) {
@@ -339,8 +337,7 @@
int numConnectedNets = 0;
for (NetworkStateTracker nt : mNetTrackers) {
- if (nt.getNetworkInfo().isConnected()
- && !mTeardownRequested[nt.getNetworkInfo().getType()]) {
+ if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
++numConnectedNets;
}
}
@@ -369,13 +366,13 @@
if (DBG) Log.v(TAG, "Handle DISCONNECT for " + info.getTypeName());
+ mNetTrackers[info.getType()].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.
*/
- mTeardownRequested[info.getType()] = false;
if (mActiveNetwork == null || info.getType() != mActiveNetwork.getNetworkInfo().getType())
return;
@@ -386,13 +383,23 @@
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())
+ if (!switchTo.isConnectedOrConnecting()) {
newNet.reconnect();
+ }
+ } else {
+ newNet.reconnect();
}
boolean otherNetworkConnected = false;
@@ -449,8 +456,12 @@
mContext.sendStickyBroadcast(intent);
}
+ /**
+ * Called when an attempt to fail over to another network has failed.
+ * @param info the {@link NetworkInfo} for the failed network
+ */
private void handleConnectionFailure(NetworkInfo info) {
- mTeardownRequested[info.getType()] = false;
+ mNetTrackers[info.getType()].setTeardownRequested(false);
if (getActiveNetworkInfo() == null) {
String reason = info.getReason();
String extraInfo = info.getExtraInfo();
@@ -496,10 +507,9 @@
otherNet = mMobileDataStateTracker;
}
/*
- * Check policy to see whether we are now connected to a network that
- * takes precedence over the other one. If so, we need to tear down
- * the other one.
- */
+ * 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()) {
@@ -510,7 +520,7 @@
}
boolean toredown = false;
- mTeardownRequested[info.getType()] = false;
+ thisNet.setTeardownRequested(false);
if (!mTestMode && deadnet != null) {
if (DBG) Log.v(TAG, "Policy requires " +
deadnet.getNetworkInfo().getTypeName() + " teardown");
@@ -520,6 +530,10 @@
}
}
+ /*
+ * 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());
@@ -592,10 +606,9 @@
int incrValue = ConnectivityManager.TYPE_MOBILE - ConnectivityManager.TYPE_WIFI;
int stopValue = ConnectivityManager.TYPE_MOBILE + incrValue;
- for (int net = ConnectivityManager.TYPE_WIFI; net != stopValue; net += incrValue) {
- NetworkStateTracker nt = mNetTrackers[net];
- if (nt.getNetworkInfo().isConnected()
- && !mTeardownRequested[nt.getNetworkInfo().getType()]) {
+ for (int netType = ConnectivityManager.TYPE_WIFI; netType != stopValue; netType += incrValue) {
+ NetworkStateTracker nt = mNetTrackers[netType];
+ if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
++numConnectedNets;
String[] dnsList = nt.getNameServers();
for (int i = 0; i < dnsList.length && dnsList[i] != null; i++) {
@@ -613,7 +626,7 @@
}
mNumDnsEntries = index - 1;
// Notify the name resolver library of the change
- SystemProperties.set("net.dnschange", String.valueOf(mDnsChangeCounter++));
+ SystemProperties.set("net.dnschange", String.valueOf(sDnsChangeCounter++));
return numConnectedNets;
}
@@ -650,13 +663,13 @@
info.getState() + "/" + info.getDetailedState());
// Connectivity state changed:
- // [31-11] Reserved for future use
- // [10-9] Mobile network connection type (as defined by the TelephonyManager)
- // [8-3] Detailed state ordinal (as defined by NetworkInfo.DetailedState)
+ // [31-13] Reserved for future use
+ // [12-9] Network subtype (for mobile network, as defined by TelephonyManager)
+ // [8-3] Detailed state ordinal (as defined by NetworkInfo.DetailedState)
// [2-0] Network type (as defined by ConnectivityManager)
int eventLogParam = (info.getType() & 0x7) |
- ((info.getDetailedState().ordinal() & 0x3f) << 3) |
- (TelephonyManager.getDefault().getNetworkType() << 9);
+ ((info.getDetailedState().ordinal() & 0x3f) << 3) |
+ (info.getSubtype() << 9);
EventLog.writeEvent(EVENTLOG_CONNECTIVITY_STATE_CHANGED, eventLogParam);
if (info.getDetailedState() == NetworkInfo.DetailedState.FAILED) {
@@ -687,6 +700,14 @@
case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
handleConfigurationChange();
break;
+
+ case NetworkStateTracker.EVENT_ROAMING_CHANGED:
+ // fill me in
+ break;
+
+ case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED:
+ // fill me in
+ break;
}
}
}