diff options
Diffstat (limited to 'services/java')
5 files changed, 465 insertions, 192 deletions
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index b1552a8..9330491 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -26,19 +26,23 @@ import android.net.ConnectivityManager; import android.net.DummyDataStateTracker; import android.net.EthernetDataTracker; import android.net.IConnectivityManager; +import android.net.LinkAddress; import android.net.LinkProperties; import android.net.MobileDataStateTracker; +import android.net.NetworkConfig; import android.net.NetworkInfo; import android.net.NetworkStateTracker; import android.net.NetworkUtils; import android.net.Proxy; import android.net.ProxyProperties; +import android.net.RouteInfo; import android.net.vpn.VpnManager; import android.net.wifi.WifiStateTracker; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; +import android.os.INetworkManagementService; import android.os.Looper; import android.os.Message; import android.os.PowerManager; @@ -58,6 +62,7 @@ import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.net.InetAddress; +import java.net.Inet4Address; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collection; @@ -79,6 +84,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final String NETWORK_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore"; + // used in recursive route setting to add gateways for the host for which + // a host route was requested. + private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10; + private Tethering mTethering; private boolean mTetheringConfigValid = false; @@ -118,6 +127,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { private AtomicBoolean mBackgroundDataEnabled = new AtomicBoolean(true); + private INetworkManagementService mNetd; + private static final int ENABLED = 1; private static final int DISABLED = 0; @@ -189,6 +200,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY = MAX_NETWORK_STATE_TRACKER_EVENT + 9; + /** + * used internally to set external dependency met/unmet + * arg1 = ENABLED (met) or DISABLED (unmet) + * arg2 = NetworkType + */ + private static final int EVENT_SET_DEPENDENCY_MET = + MAX_NETWORK_STATE_TRACKER_EVENT + 10; + private Handler mHandler; // list of DeathRecipients used to make sure features are turned off when @@ -217,28 +236,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private SettingsObserver mSettingsObserver; - private static class NetworkAttributes { - /** - * Class for holding settings read from resources. - */ - public String mName; - public int mType; - public int mRadio; - public int mPriority; - public NetworkInfo.State mLastState; - public NetworkAttributes(String init) { - String fragments[] = init.split(","); - mName = fragments[0].toLowerCase(); - mType = Integer.parseInt(fragments[1]); - mRadio = Integer.parseInt(fragments[2]); - mPriority = Integer.parseInt(fragments[3]); - mLastState = NetworkInfo.State.UNKNOWN; - } - public boolean isDefault() { - return (mType == mRadio); - } - } - NetworkAttributes[] mNetAttributes; + NetworkConfig[] mNetConfigs; int mNetworksDefined; private static class RadioAttributes { @@ -305,7 +303,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetworkPreference = getPersistedNetworkPreference(); mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1]; - mNetAttributes = new NetworkAttributes[ConnectivityManager.MAX_NETWORK_TYPE+1]; + mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1]; // Load device network attributes from resources String[] raStrings = context.getResources().getStringArray( @@ -328,23 +326,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { com.android.internal.R.array.networkAttributes); for (String naString : naStrings) { try { - NetworkAttributes n = new NetworkAttributes(naString); - if (n.mType > ConnectivityManager.MAX_NETWORK_TYPE) { + NetworkConfig n = new NetworkConfig(naString); + if (n.type > ConnectivityManager.MAX_NETWORK_TYPE) { loge("Error in networkAttributes - ignoring attempt to define type " + - n.mType); + n.type); continue; } - if (mNetAttributes[n.mType] != null) { + if (mNetConfigs[n.type] != null) { loge("Error in networkAttributes - ignoring attempt to redefine type " + - n.mType); + n.type); continue; } - if (mRadioAttributes[n.mRadio] == null) { + if (mRadioAttributes[n.radio] == null) { loge("Error in networkAttributes - ignoring attempt to use undefined " + - "radio " + n.mRadio + " in network type " + n.mType); + "radio " + n.radio + " in network type " + n.type); continue; } - mNetAttributes[n.mType] = n; + mNetConfigs[n.type] = n; mNetworksDefined++; } catch(Exception e) { // ignore it - leave the entry null @@ -358,16 +356,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { int currentLowest = 0; int nextLowest = 0; while (insertionPoint > -1) { - for (NetworkAttributes na : mNetAttributes) { + for (NetworkConfig na : mNetConfigs) { if (na == null) continue; - if (na.mPriority < currentLowest) continue; - if (na.mPriority > currentLowest) { - if (na.mPriority < nextLowest || nextLowest == 0) { - nextLowest = na.mPriority; + if (na.priority < currentLowest) continue; + if (na.priority > currentLowest) { + if (na.priority < nextLowest || nextLowest == 0) { + nextLowest = na.priority; } continue; } - mPriorityList[insertionPoint--] = na.mType; + mPriorityList[insertionPoint--] = na.type; } currentLowest = nextLowest; nextLowest = 0; @@ -393,7 +391,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { * to change very often. */ for (int netType : mPriorityList) { - switch (mNetAttributes[netType].mRadio) { + switch (mNetConfigs[netType].radio) { case ConnectivityManager.TYPE_WIFI: if (DBG) log("Starting Wifi Service."); WifiStateTracker wst = new WifiStateTracker(); @@ -409,12 +407,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { break; case ConnectivityManager.TYPE_MOBILE: mNetTrackers[netType] = new MobileDataStateTracker(netType, - mNetAttributes[netType].mName); + mNetConfigs[netType].name); mNetTrackers[netType].startMonitoring(context, mHandler); break; case ConnectivityManager.TYPE_DUMMY: mNetTrackers[netType] = new DummyDataStateTracker(netType, - mNetAttributes[netType].mName); + mNetConfigs[netType].name); mNetTrackers[netType].startMonitoring(context, mHandler); break; case ConnectivityManager.TYPE_BLUETOOTH: @@ -427,7 +425,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { break; default: loge("Trying to create a DataStateTracker for an unknown radio type " + - mNetAttributes[netType].mRadio); + mNetConfigs[netType].radio); continue; } } @@ -474,8 +472,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void handleSetNetworkPreference(int preference) { if (ConnectivityManager.isNetworkTypeValid(preference) && - mNetAttributes[preference] != null && - mNetAttributes[preference].isDefault()) { + mNetConfigs[preference] != null && + mNetConfigs[preference].isDefault()) { if (mNetworkPreference != preference) { final ContentResolver cr = mContext.getContentResolver(); Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, preference); @@ -542,21 +540,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { * active */ public NetworkInfo getActiveNetworkInfo() { - enforceAccessPermission(); - for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { - if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) { - continue; - } - NetworkStateTracker t = mNetTrackers[type]; - NetworkInfo info = t.getNetworkInfo(); - if (info.isConnected()) { - if (DBG && type != mActiveDefaultNetwork) { - loge("connected default network is not mActiveDefaultNetwork!"); - } - return info; - } - } - return null; + return getNetworkInfo(mActiveDefaultNetwork); } public NetworkInfo getNetworkInfo(int networkType) { @@ -588,18 +572,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { * none is active */ public LinkProperties getActiveLinkProperties() { - enforceAccessPermission(); - for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { - if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) { - continue; - } - NetworkStateTracker t = mNetTrackers[type]; - NetworkInfo info = t.getNetworkInfo(); - if (info.isConnected()) { - return t.getLinkProperties(); - } - } - return null; + return getLinkProperties(mActiveDefaultNetwork); } public LinkProperties getLinkProperties(int networkType) { @@ -692,7 +665,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } enforceChangePermission(); if (!ConnectivityManager.isNetworkTypeValid(networkType) || - mNetAttributes[networkType] == null) { + mNetConfigs[networkType] == null) { return Phone.APN_REQUEST_FAILED; } @@ -701,15 +674,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { // 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) || - TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) { - usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN; - } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) { - usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI; + usedNetworkType = convertFeatureToNetworkType(feature); + if (usedNetworkType < 0) { + Slog.e(TAG, "Can't match any netTracker!"); + usedNetworkType = networkType; } } NetworkStateTracker network = mNetTrackers[usedNetworkType]; @@ -735,9 +703,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetRequestersPids[usedNetworkType].add(currentPid); } } - mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK, - f), getRestoreDefaultNetworkDelay()); + int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType); + + if (restoreTimer >= 0) { + mHandler.sendMessageDelayed( + mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK, f), restoreTimer); + } if ((ni.isConnectedOrConnecting() == true) && !network.isTeardownRequested()) { @@ -853,15 +825,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { // 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) || - TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) { - usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN; - } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) { - usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI; + usedNetworkType = convertFeatureToNetworkType(feature); + if (usedNetworkType < 0) { + usedNetworkType = networkType; } } tracker = mNetTrackers[usedNetworkType]; @@ -939,7 +905,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } try { InetAddress addr = InetAddress.getByAddress(hostAddress); - return addHostRoute(tracker, addr); + return addHostRoute(tracker, addr, 0); } catch (UnknownHostException e) {} return false; } @@ -952,24 +918,49 @@ public class ConnectivityService extends IConnectivityManager.Stub { * TODO - deprecate * @return {@code true} on success, {@code false} on failure */ - private boolean addHostRoute(NetworkStateTracker nt, InetAddress hostAddress) { - if (nt.getNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI) { - return false; - } - - LinkProperties p = nt.getLinkProperties(); - if (p == null) return false; - String interfaceName = p.getInterfaceName(); + private boolean addHostRoute(NetworkStateTracker nt, InetAddress hostAddress, int cycleCount) { + LinkProperties lp = nt.getLinkProperties(); + if ((lp == null) || (hostAddress == null)) return false; + String interfaceName = lp.getInterfaceName(); if (DBG) { - log("Requested host route to " + hostAddress + "(" + interfaceName + ")"); + log("Requested host route to " + hostAddress + "(" + interfaceName + "), cycleCount=" + + cycleCount); } - if (interfaceName != null) { - return NetworkUtils.addHostRoute(interfaceName, hostAddress, null); - } else { + if (interfaceName == null) { if (DBG) loge("addHostRoute failed due to null interface name"); return false; } + + RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), hostAddress); + InetAddress gatewayAddress = null; + if (bestRoute != null) { + gatewayAddress = bestRoute.getGateway(); + // if the best route is ourself, don't relf-reference, just add the host route + if (hostAddress.equals(gatewayAddress)) gatewayAddress = null; + } + if (gatewayAddress != null) { + if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) { + loge("Error adding hostroute - too much recursion"); + return false; + } + if (!addHostRoute(nt, gatewayAddress, cycleCount+1)) return false; + } + + RouteInfo route = RouteInfo.makeHostRoute(hostAddress, gatewayAddress); + + try { + mNetd.addRoute(interfaceName, route); + return true; + } catch (Exception ex) { + return false; + } + } + + // TODO support the removal of single host routes. Keep a ref count of them so we + // aren't over-zealous + private boolean removeHostRoute(NetworkStateTracker nt, InetAddress hostAddress) { + return false; } /** @@ -1015,6 +1006,24 @@ public class ConnectivityService extends IConnectivityManager.Stub { return retVal; } + public void setDataDependency(int networkType, boolean met) { + enforceChangePermission(); + if (DBG) { + log("setDataDependency(" + networkType + ", " + met + ")"); + } + mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_DEPENDENCY_MET, + (met ? ENABLED : DISABLED), networkType)); + } + + private void handleSetDependencyMet(int networkType, boolean met) { + if (mNetTrackers[networkType] != null) { + if (DBG) { + log("handleSetDependencyMet(" + networkType + ", " + met + ")"); + } + mNetTrackers[networkType].setDependencyMet(met); + } + } + /** * @see ConnectivityManager#setMobileDataEnabled(boolean) */ @@ -1023,7 +1032,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (DBG) log("setMobileDataEnabled(" + enabled + ")"); mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA, - (enabled ? ENABLED : DISABLED), 0)); + (enabled ? ENABLED : DISABLED), 0)); } private void handleSetMobileData(boolean enabled) { @@ -1084,7 +1093,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { * getting the disconnect for a network that we explicitly disabled * in accordance with network preference policies. */ - if (!mNetAttributes[prevNetType].isDefault()) { + if (!mNetConfigs[prevNetType].isDefault()) { List pids = mNetRequestersPids[prevNetType]; for (int i = 0; i<pids.size(); i++) { Integer pid = (Integer)pids.get(i); @@ -1109,7 +1118,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { info.getExtraInfo()); } - if (mNetAttributes[prevNetType].isDefault()) { + if (mNetConfigs[prevNetType].isDefault()) { tryFailover(prevNetType); if (mActiveDefaultNetwork != -1) { NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); @@ -1139,7 +1148,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { * Try to reconnect on all available and let them hash it out when * more than one connects. */ - if (mNetAttributes[prevNetType].isDefault()) { + if (mNetConfigs[prevNetType].isDefault()) { if (mActiveDefaultNetwork == prevNetType) { mActiveDefaultNetwork = -1; } @@ -1149,12 +1158,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { // TODO - don't filter by priority now - nice optimization but risky // int currentPriority = -1; // if (mActiveDefaultNetwork != -1) { -// currentPriority = mNetAttributes[mActiveDefaultNetwork].mPriority; +// currentPriority = mNetConfigs[mActiveDefaultNetwork].mPriority; // } for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) { if (checkType == prevNetType) continue; - if (mNetAttributes[checkType] == null) continue; - if (!mNetAttributes[checkType].isDefault()) continue; + if (mNetConfigs[checkType] == null) continue; + if (!mNetConfigs[checkType].isDefault()) continue; // Enabling the isAvailable() optimization caused mobile to not get // selected if it was in the middle of error handling. Specifically @@ -1166,7 +1175,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // complete before it is really complete. // if (!mNetTrackers[checkType].isAvailable()) continue; -// if (currentPriority >= mNetAttributes[checkType].mPriority) continue; +// if (currentPriority >= mNetConfigs[checkType].mPriority) continue; NetworkStateTracker checkTracker = mNetTrackers[checkType]; NetworkInfo checkInfo = checkTracker.getNetworkInfo(); @@ -1239,7 +1248,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { info.setFailover(false); } - if (mNetAttributes[info.getType()].isDefault()) { + if (mNetConfigs[info.getType()].isDefault()) { tryFailover(info.getType()); if (mActiveDefaultNetwork != -1) { NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); @@ -1272,6 +1281,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { } void systemReady() { + IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); + mNetd = INetworkManagementService.Stub.asInterface(b); + synchronized(this) { mSystemReady = true; if (mInitialBroadcast != null) { @@ -1292,11 +1304,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { // if this is a default net and other default is running // kill the one not preferred - if (mNetAttributes[type].isDefault()) { + if (mNetConfigs[type].isDefault()) { if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) { if ((type != mNetworkPreference && - mNetAttributes[mActiveDefaultNetwork].mPriority > - mNetAttributes[type].mPriority) || + mNetConfigs[mActiveDefaultNetwork].priority > + mNetConfigs[type].priority) || mNetworkPreference == mActiveDefaultNetwork) { // don't accept this one if (DBG) { @@ -1360,14 +1372,20 @@ public class ConnectivityService extends IConnectivityManager.Stub { handleDnsConfigurationChange(netType); if (mNetTrackers[netType].getNetworkInfo().isConnected()) { - if (mNetAttributes[netType].isDefault()) { + if (mNetConfigs[netType].isDefault()) { handleApplyDefaultProxy(netType); addDefaultRoute(mNetTrackers[netType]); } else { addPrivateDnsRoutes(mNetTrackers[netType]); } + + /** Notify TetheringService if interface name has been changed. */ + if (TextUtils.equals(mNetTrackers[netType].getNetworkInfo().getReason(), + Phone.REASON_LINK_PROPERTIES_CHANGED)) { + handleTetherIfaceChange(netType); + } } else { - if (mNetAttributes[netType].isDefault()) { + if (mNetConfigs[netType].isDefault()) { removeDefaultRoute(mNetTrackers[netType]); } else { removePrivateDnsRoutes(mNetTrackers[netType]); @@ -1388,16 +1406,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (interfaceName != null && !privateDnsRouteSet) { Collection<InetAddress> dnsList = p.getDnses(); for (InetAddress dns : dnsList) { - if (DBG) log(" adding " + dns); - NetworkUtils.addHostRoute(interfaceName, dns, null); + addHostRoute(nt, dns, 0); } nt.privateDnsRouteSet(true); } } private void removePrivateDnsRoutes(NetworkStateTracker nt) { - // TODO - we should do this explicitly but the NetUtils api doesnt - // support this yet - must remove all. No worse than before LinkProperties p = nt.getLinkProperties(); if (p == null) return; String interfaceName = p.getInterfaceName(); @@ -1407,7 +1422,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("removePrivateDnsRoutes for " + nt.getNetworkInfo().getTypeName() + " (" + interfaceName + ")"); } - NetworkUtils.removeHostRoutes(interfaceName); + + Collection<InetAddress> dnsList = p.getDnses(); + for (InetAddress dns : dnsList) { + if (DBG) log(" removing " + dns); + RouteInfo route = RouteInfo.makeHostRoute(dns); + try { + mNetd.removeRoute(interfaceName, route); + } catch (Exception ex) { + loge("error (" + ex + ") removing dns route " + route); + } + } nt.privateDnsRouteSet(false); } } @@ -1418,14 +1443,27 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (p == null) return; String interfaceName = p.getInterfaceName(); if (TextUtils.isEmpty(interfaceName)) return; - for (InetAddress gateway : p.getGateways()) { - if (NetworkUtils.addHostRoute(interfaceName, gateway, null) && - NetworkUtils.addDefaultRoute(interfaceName, gateway)) { - if (DBG) { - NetworkInfo networkInfo = nt.getNetworkInfo(); - log("addDefaultRoute for " + networkInfo.getTypeName() + - " (" + interfaceName + "), GatewayAddr=" + gateway.getHostAddress()); + for (RouteInfo route : p.getRoutes()) { + //TODO - handle non-default routes + if (route.isDefaultRoute()) { + if (DBG) log("adding default route " + route); + InetAddress gateway = route.getGateway(); + if (addHostRoute(nt, gateway, 0)) { + try { + mNetd.addRoute(interfaceName, route); + } catch (Exception e) { + loge("error adding default route " + route); + continue; + } + if (DBG) { + NetworkInfo networkInfo = nt.getNetworkInfo(); + log("addDefaultRoute for " + networkInfo.getTypeName() + + " (" + interfaceName + "), GatewayAddr=" + + gateway.getHostAddress()); + } + } else { + loge("error adding host route for default route " + route); } } } @@ -1437,8 +1475,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (p == null) return; String interfaceName = p.getInterfaceName(); - if (interfaceName != null) { - if (NetworkUtils.removeDefaultRoute(interfaceName) >= 0) { + if (interfaceName == null) return; + + for (RouteInfo route : p.getRoutes()) { + //TODO - handle non-default routes + if (route.isDefaultRoute()) { + try { + mNetd.removeRoute(interfaceName, route); + } catch (Exception ex) { + loge("error (" + ex + ") removing default route " + route); + continue; + } if (DBG) { NetworkInfo networkInfo = nt.getNetworkInfo(); log("removeDefaultRoute for " + networkInfo.getTypeName() + " (" + @@ -1528,7 +1575,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { { if (DBG) log("reassessPidDns for pid " + myPid); for(int i : mPriorityList) { - if (mNetAttributes[i].isDefault()) { + if (mNetConfigs[i].isDefault()) { continue; } NetworkStateTracker nt = mNetTrackers[i]; @@ -1610,7 +1657,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (p == null) return; Collection<InetAddress> dnses = p.getDnses(); boolean changed = false; - if (mNetAttributes[netType].isDefault()) { + if (mNetConfigs[netType].isDefault()) { int j = 1; if (dnses.size() == 0 && mDefaultDns != null) { String dnsString = mDefaultDns.getHostAddress(); @@ -1657,7 +1704,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private int getRestoreDefaultNetworkDelay() { + private int getRestoreDefaultNetworkDelay(int networkType) { String restoreDefaultNetworkDelayStr = SystemProperties.get( NETWORK_RESTORE_DELAY_PROP_NAME); if(restoreDefaultNetworkDelayStr != null && @@ -1667,7 +1714,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { } catch (NumberFormatException e) { } } - return RESTORE_DEFAULT_NETWORK_DELAY; + // if the system property isn't set, use the value for the apn type + int ret = RESTORE_DEFAULT_NETWORK_DELAY; + + if ((networkType <= ConnectivityManager.MAX_NETWORK_TYPE) && + (mNetConfigs[networkType] != null)) { + ret = mNetConfigs[networkType].restoreTime; + } + return ret; } @Override @@ -1741,23 +1795,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { info = (NetworkInfo) msg.obj; int type = info.getType(); NetworkInfo.State state = info.getState(); - // only do this optimization for wifi. It going into scan mode for location - // services generates alot of noise. Meanwhile the mms apn won't send out - // subsequent notifications when on default cellular because it never - // disconnects.. so only do this to wifi notifications. Fixed better when the - // APN notifications are standardized. - if (mNetAttributes[type].mLastState == state && - mNetAttributes[type].mRadio == ConnectivityManager.TYPE_WIFI) { - if (DBG) { - // TODO - remove this after we validate the dropping doesn't break - // anything - log("Dropping ConnectivityChange for " + - info.getTypeName() + ": " + - state + "/" + info.getDetailedState()); - } - return; - } - mNetAttributes[type].mLastState = state; if (DBG) log("ConnectivityChange for " + info.getTypeName() + ": " + @@ -1796,8 +1833,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { break; case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: info = (NetworkInfo) msg.obj; - type = info.getType(); - handleConnectivityChange(type); + handleConnectivityChange(info.getType()); break; case EVENT_CLEAR_NET_TRANSITION_WAKELOCK: String causedBy = null; @@ -1851,6 +1887,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { case EVENT_APPLY_GLOBAL_HTTP_PROXY: { handleDeprecatedGlobalHttpProxy(); + break; + } + case EVENT_SET_DEPENDENCY_MET: + { + boolean met = (msg.arg1 == ENABLED); + handleSetDependencyMet(msg.arg2, met); + break; } } } @@ -2177,6 +2220,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + private void handleTetherIfaceChange(int type) { + String iface = mNetTrackers[type].getLinkProperties().getInterfaceName(); + + if (isTetheringSupported()) { + mTethering.handleTetherIfaceChange(iface); + } + } + private void log(String s) { Slog.d(TAG, s); } @@ -2184,4 +2235,24 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void loge(String s) { Slog.e(TAG, s); } + int convertFeatureToNetworkType(String feature){ + int networkType = -1; + if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { + networkType = ConnectivityManager.TYPE_MOBILE_MMS; + } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { + networkType = ConnectivityManager.TYPE_MOBILE_SUPL; + } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) || + TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) { + networkType = ConnectivityManager.TYPE_MOBILE_DUN; + } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) { + networkType = ConnectivityManager.TYPE_MOBILE_HIPRI; + } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_FOTA)) { + networkType = ConnectivityManager.TYPE_MOBILE_FOTA; + } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_IMS)) { + networkType = ConnectivityManager.TYPE_MOBILE_IMS; + } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_CBS)) { + networkType = ConnectivityManager.TYPE_MOBILE_CBS; + } + return networkType; + } } diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index 44f5df2..0b4b958 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -28,6 +28,7 @@ import android.net.InterfaceConfiguration; import android.net.INetworkManagementEventObserver; import android.net.LinkAddress; import android.net.NetworkUtils; +import android.net.RouteInfo; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration.KeyMgmt; import android.os.INetworkManagementService; @@ -43,11 +44,16 @@ import android.provider.Settings; import android.content.ContentResolver; import android.database.ContentObserver; +import java.io.BufferedReader; +import java.io.DataInputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FileReader; +import java.io.InputStreamReader; +import java.io.IOException; import java.lang.IllegalStateException; - import java.net.InetAddress; +import java.net.Inet4Address; import java.net.UnknownHostException; import java.util.concurrent.CountDownLatch; @@ -60,6 +66,9 @@ class NetworkManagementService extends INetworkManagementService.Stub { private static final boolean DBG = false; private static final String NETD_TAG = "NetdConnector"; + private static final int ADD = 1; + private static final int REMOVE = 2; + class NetdResponseCode { public static final int InterfaceListResult = 110; public static final int TetherInterfaceListResult = 111; @@ -309,6 +318,164 @@ class NetworkManagementService extends INetworkManagementService.Stub { } } + public void addRoute(String interfaceName, RouteInfo route) { + modifyRoute(interfaceName, ADD, route); + } + + public void removeRoute(String interfaceName, RouteInfo route) { + modifyRoute(interfaceName, REMOVE, route); + } + + private void modifyRoute(String interfaceName, int action, RouteInfo route) { + ArrayList<String> rsp; + + StringBuilder cmd; + + switch (action) { + case ADD: + { + cmd = new StringBuilder("interface route add " + interfaceName); + break; + } + case REMOVE: + { + cmd = new StringBuilder("interface route remove " + interfaceName); + break; + } + default: + throw new IllegalStateException("Unknown action type " + action); + } + + // create triplet: dest-ip-addr prefixlength gateway-ip-addr + LinkAddress la = route.getDestination(); + cmd.append(' '); + cmd.append(la.getAddress().getHostAddress()); + cmd.append(' '); + cmd.append(la.getNetworkPrefixLength()); + cmd.append(' '); + if (route.getGateway() == null) { + if (la.getAddress() instanceof Inet4Address) { + cmd.append("0.0.0.0"); + } else { + cmd.append ("::0"); + } + } else { + cmd.append(route.getGateway().getHostAddress()); + } + try { + rsp = mConnector.doCommand(cmd.toString()); + } catch (NativeDaemonConnectorException e) { + throw new IllegalStateException( + "Unable to communicate with native dameon to add routes - " + + e); + } + + for (String line : rsp) { + Log.v(TAG, "add route response is " + line); + } + } + + private ArrayList<String> readRouteList(String filename) { + FileInputStream fstream = null; + ArrayList<String> list = new ArrayList<String>(); + + try { + fstream = new FileInputStream(filename); + DataInputStream in = new DataInputStream(fstream); + BufferedReader br = new BufferedReader(new InputStreamReader(in)); + String s; + + // throw away the title line + + while (((s = br.readLine()) != null) && (s.length() != 0)) { + list.add(s); + } + } catch (IOException ex) { + // return current list, possibly empty + } finally { + if (fstream != null) { + try { + fstream.close(); + } catch (IOException ex) {} + } + } + + return list; + } + + public RouteInfo[] getRoutes(String interfaceName) { + ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>(); + + // v4 routes listed as: + // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT + for (String s : readRouteList("/proc/net/route")) { + String[] fields = s.split("\t"); + + if (fields.length > 7) { + String iface = fields[0]; + + if (interfaceName.equals(iface)) { + String dest = fields[1]; + String gate = fields[2]; + String flags = fields[3]; // future use? + String mask = fields[7]; + try { + // address stored as a hex string, ex: 0014A8C0 + InetAddress destAddr = + NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16)); + int prefixLength = + NetworkUtils.netmaskIntToPrefixLength( + (int)Long.parseLong(mask, 16)); + LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength); + + // address stored as a hex string, ex 0014A8C0 + InetAddress gatewayAddr = + NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16)); + + RouteInfo route = new RouteInfo(linkAddress, gatewayAddr); + routes.add(route); + } catch (Exception e) { + Log.e(TAG, "Error parsing route " + s + " : " + e); + continue; + } + } + } + } + + // v6 routes listed as: + // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface + for (String s : readRouteList("/proc/net/ipv6_route")) { + String[]fields = s.split("\\s+"); + if (fields.length > 9) { + String iface = fields[9].trim(); + if (interfaceName.equals(iface)) { + String dest = fields[0]; + String prefix = fields[1]; + String gate = fields[4]; + + try { + // prefix length stored as a hex string, ex 40 + int prefixLength = Integer.parseInt(prefix, 16); + + // address stored as a 32 char hex string + // ex fe800000000000000000000000000000 + InetAddress destAddr = NetworkUtils.hexToInet6Address(dest); + LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength); + + InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate); + + RouteInfo route = new RouteInfo(linkAddress, gateAddr); + routes.add(route); + } catch (Exception e) { + Log.e(TAG, "Error parsing route " + s + " : " + e); + continue; + } + } + } + } + return (RouteInfo[]) routes.toArray(new RouteInfo[0]); + } + public void shutdown() { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.SHUTDOWN) diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java index eb14180..a8d40b7 100644 --- a/services/java/com/android/server/TelephonyRegistry.java +++ b/services/java/com/android/server/TelephonyRegistry.java @@ -546,7 +546,6 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); Bundle data = new Bundle(); state.fillInNotifierBundle(data); intent.putExtras(data); @@ -586,7 +585,6 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra(Phone.STATE_KEY, DefaultPhoneNotifier.convertCallState(state).toString()); if (!TextUtils.isEmpty(incomingNumber)) { intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber); @@ -602,7 +600,6 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { // status bar takes care of that after taking into account all of the // required info. Intent intent = new Intent(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra(Phone.STATE_KEY, DefaultPhoneNotifier.convertDataState(state).toString()); if (!isDataConnectivityPossible) { intent.putExtra(Phone.NETWORK_UNAVAILABLE_KEY, true); @@ -627,7 +624,6 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private void broadcastDataConnectionFailed(String reason, String apnType) { Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra(Phone.FAILURE_REASON_KEY, reason); intent.putExtra(Phone.DATA_APN_TYPE_KEY, apnType); mContext.sendStickyBroadcast(intent); diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 6acc32f..9e0f26c 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -235,6 +235,15 @@ public class WifiService extends IWifiManager.Stub { } break; } + case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { + if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { + Slog.d(TAG, "Send failed, client connection lost"); + } else { + Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); + } + mClients.remove((AsyncChannel) msg.obj); + break; + } case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { AsyncChannel ac = new AsyncChannel(); ac.connect(mContext, this, msg.replyTo); @@ -312,6 +321,13 @@ public class WifiService extends IWifiManager.Stub { } break; } + case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { + Slog.e(TAG, "WifiStateMachine channel lost, msg.arg1 =" + msg.arg1); + mWifiStateMachineChannel = null; + //Re-establish connection to state machine + mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler()); + break; + } default: { Slog.d(TAG, "WifiStateMachineHandler.handleMessage ignoring msg=" + msg); break; @@ -584,7 +600,12 @@ public class WifiService extends IWifiManager.Stub { */ public WifiConfiguration getWifiApConfiguration() { enforceAccessPermission(); - return mWifiStateMachine.syncGetWifiApConfiguration(mWifiStateMachineChannel); + if (mWifiStateMachineChannel != null) { + return mWifiStateMachine.syncGetWifiApConfiguration(mWifiStateMachineChannel); + } else { + Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); + return null; + } } /** diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java index 5853696..ffadc65 100644 --- a/services/java/com/android/server/connectivity/Tethering.java +++ b/services/java/com/android/server/connectivity/Tethering.java @@ -49,8 +49,9 @@ import android.provider.Settings; import android.util.Log; import com.android.internal.telephony.Phone; -import com.android.internal.util.HierarchicalState; -import com.android.internal.util.HierarchicalStateMachine; +import com.android.internal.util.IState; +import com.android.internal.util.State; +import com.android.internal.util.StateMachine; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -122,7 +123,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { // resampled each time we turn on tethering - used as cache for settings/config-val private boolean mDunRequired; // configuration info - must use DUN apn on 3g - private HierarchicalStateMachine mTetherMasterSM; + private StateMachine mTetherMasterSM; private Notification mTetheredNotification; @@ -667,8 +668,18 @@ public class Tethering extends INetworkManagementEventObserver.Stub { return retVal; } + public void handleTetherIfaceChange(String iface) { + // check if iface is white listed + for (String regex : mUpstreamIfaceRegexs) { + if (iface.matches(regex)) { + if (DEBUG) Log.d(TAG, "Tethering got Interface Change"); + mTetherMasterSM.sendMessage(TetherMasterSM.CMD_IFACE_CHANGED, iface); + break; + } + } + } - class TetherInterfaceSM extends HierarchicalStateMachine { + class TetherInterfaceSM extends StateMachine { // notification from the master SM that it's not in tether mode static final int CMD_TETHER_MODE_DEAD = 1; // request from the user that it wants to tether @@ -694,13 +705,13 @@ public class Tethering extends INetworkManagementEventObserver.Stub { // the upstream connection has changed static final int CMD_TETHER_CONNECTION_CHANGED = 12; - private HierarchicalState mDefaultState; + private State mDefaultState; - private HierarchicalState mInitialState; - private HierarchicalState mStartingState; - private HierarchicalState mTetheredState; + private State mInitialState; + private State mStartingState; + private State mTetheredState; - private HierarchicalState mUnavailableState; + private State mUnavailableState; private boolean mAvailable; private boolean mTethered; @@ -732,7 +743,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { public String toString() { String res = new String(); res += mIfaceName + " - "; - HierarchicalState current = getCurrentState(); + IState current = getCurrentState(); if (current == mInitialState) res += "InitialState"; if (current == mStartingState) res += "StartingState"; if (current == mTetheredState) res += "TetheredState"; @@ -782,7 +793,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { return (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR); } - class InitialState extends HierarchicalState { + class InitialState extends State { @Override public void enter() { setAvailable(true); @@ -812,7 +823,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } } - class StartingState extends HierarchicalState { + class StartingState extends State { @Override public void enter() { setAvailable(false); @@ -870,7 +881,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } } - class TetheredState extends HierarchicalState { + class TetheredState extends State { @Override public void enter() { IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); @@ -1034,7 +1045,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } } - class UnavailableState extends HierarchicalState { + class UnavailableState extends State { @Override public void enter() { setAvailable(false); @@ -1064,7 +1075,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } - class TetherMasterSM extends HierarchicalStateMachine { + class TetherMasterSM extends StateMachine { // an interface SM has requested Tethering static final int CMD_TETHER_MODE_REQUESTED = 1; // an interface SM has unrequested Tethering @@ -1075,6 +1086,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub { static final int CMD_CELL_CONNECTION_RENEW = 4; // we don't have a valid upstream conn, check again after a delay static final int CMD_RETRY_UPSTREAM = 5; + // received an indication that upstream interface has changed + static final int CMD_IFACE_CHANGED = 6; // This indicates what a timeout event relates to. A state that // sends itself a delayed timeout event and handles incoming timeout events @@ -1082,14 +1095,14 @@ public class Tethering extends INetworkManagementEventObserver.Stub { // We do not flush the old ones. private int mSequenceNumber; - private HierarchicalState mInitialState; - private HierarchicalState mTetherModeAliveState; + private State mInitialState; + private State mTetherModeAliveState; - private HierarchicalState mSetIpForwardingEnabledErrorState; - private HierarchicalState mSetIpForwardingDisabledErrorState; - private HierarchicalState mStartTetheringErrorState; - private HierarchicalState mStopTetheringErrorState; - private HierarchicalState mSetDnsForwardersErrorState; + private State mSetIpForwardingEnabledErrorState; + private State mSetIpForwardingDisabledErrorState; + private State mStartTetheringErrorState; + private State mStopTetheringErrorState; + private State mSetDnsForwardersErrorState; private ArrayList mNotifyList; @@ -1125,7 +1138,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { setInitialState(mInitialState); } - class TetherMasterUtilState extends HierarchicalState { + class TetherMasterUtilState extends State { protected final static boolean TRY_TO_SETUP_MOBILE_CONNECTION = true; protected final static boolean WAIT_FOR_NETWORK_TO_SETTLE = false; @@ -1428,19 +1441,24 @@ public class Tethering extends INetworkManagementEventObserver.Stub { turnOnMobileConnection(); } break; - case CMD_RETRY_UPSTREAM: - chooseUpstreamType(mTryCell); - mTryCell = !mTryCell; - break; - default: - retValue = false; - break; + case CMD_RETRY_UPSTREAM: + chooseUpstreamType(mTryCell); + mTryCell = !mTryCell; + break; + case CMD_IFACE_CHANGED: + String iface = (String)message.obj; + if (DEBUG) Log.d(TAG, "Activie upstream interface changed: " + iface); + notifyTetheredOfNewUpstreamIface(iface); + break; + default: + retValue = false; + break; } return retValue; } } - class ErrorState extends HierarchicalState { + class ErrorState extends State { int mErrorNotification; @Override public boolean processMessage(Message message) { |