diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index f776abfb05..8c82212f0d 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -99,24 +99,38 @@ public class NetworkInfo implements Parcelable { } 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; } /** @@ -128,6 +142,41 @@ public class NetworkInfo implements Parcelable { return mNetworkType; } + /** + * 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 @@ -170,7 +219,7 @@ public class NetworkInfo implements Parcelable { * 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,11 +236,32 @@ public class NetworkInfo implements Parcelable { 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 @@ public class NetworkInfo implements Parcelable { * 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 @@ public class NetworkInfo implements Parcelable { @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 ""; - } - } - - /** 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 CREATOR = new Creator() { 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 129248aebf..1153648729 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -66,6 +66,14 @@ public class NetworkUtils { */ 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. *

NOTE: This string is not localized, but currently it is only diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 417ce541e4..8383deb59a 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -41,6 +41,7 @@ int dhcp_do_request(const char *ifname, 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 @@ static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring if 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 @@ static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring i 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 @@ static JNINativeMethod gNetworkUtilMethods[] = { { "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 11f34cc861..65e36509a9 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -35,7 +35,6 @@ import android.os.Message; 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.FileDescriptor; import java.io.PrintWriter; /** - * {@hide} + * @hide */ public class ConnectivityService extends IConnectivityManager.Stub { @@ -59,7 +58,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { * abstractly. */ private NetworkStateTracker mNetTrackers[]; - private boolean mTeardownRequested[]; private WifiStateTracker mWifiStateTracker; private MobileDataStateTracker mMobileDataStateTracker; private WifiWatchdogService mWifiWatchdogService; @@ -69,11 +67,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 class ConnectivityService extends IConnectivityManager.Stub { 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 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 @@ public class ConnectivityService extends IConnectivityManager.Stub { } /** - * 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 @@ public class ConnectivityService extends IConnectivityManager.Stub { return tracker.startUsingNetworkFeature(feature, getCallingPid(), getCallingUid()); } return -1; - } public int stopUsingNetworkFeature(int networkType, String feature) { @@ -339,8 +337,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 @@ public class ConnectivityService extends IConnectivityManager.Stub { } 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 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + /* + * 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 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 @@ public class ConnectivityService extends IConnectivityManager.Stub { } 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 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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; } } }