diff options
Diffstat (limited to 'wifi')
-rw-r--r-- | wifi/java/android/net/wifi/WifiStateMachine.java | 185 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiStateTracker.java | 26 |
2 files changed, 164 insertions, 47 deletions
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index d4e98c5..3ccdbea 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -51,6 +51,7 @@ import android.net.LinkProperties; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkUtils; +import android.net.RouteInfo; import android.net.wifi.WpsResult.Status; import android.net.wifi.p2p.WifiP2pManager; import android.net.wifi.p2p.WifiP2pService; @@ -79,9 +80,12 @@ import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import com.android.server.net.BaseNetworkObserver; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.net.InetAddress; +import java.net.Inet6Address; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -198,8 +202,19 @@ public class WifiStateMachine extends StateMachine { /* Tracks sequence number on a driver time out */ private int mDriverStartToken = 0; + /** + * The link properties of the wifi interface. + * Do not modify this directly; use updateLinkProperties instead. + */ private LinkProperties mLinkProperties; + /** + * Subset of link properties coming from netlink. + * Currently includes IPv4 and IPv6 addresses. In the future will also include IPv6 DNS servers + * and domains obtained from router advertisements (RFC 6106). + */ + private final LinkProperties mNetlinkLinkProperties; + /* Tracks sequence number on a periodic scan message */ private int mPeriodicScanToken = 0; @@ -215,6 +230,39 @@ public class WifiStateMachine extends StateMachine { private SupplicantStateTracker mSupplicantStateTracker; private DhcpStateMachine mDhcpStateMachine; + private class InterfaceObserver extends BaseNetworkObserver { + private WifiStateMachine mWifiStateMachine; + + InterfaceObserver(WifiStateMachine wifiStateMachine) { + super(); + mWifiStateMachine = wifiStateMachine; + } + + @Override + public void addressUpdated(String address, String iface, int flags, int scope) { + if (mWifiStateMachine.mInterfaceName.equals(iface)) { + if (DBG) { + log("addressUpdated: " + address + " on " + iface + + " flags " + flags + " scope " + scope); + } + mWifiStateMachine.sendMessage(CMD_IP_ADDRESS_UPDATED, new LinkAddress(address)); + } + } + + @Override + public void addressRemoved(String address, String iface, int flags, int scope) { + if (mWifiStateMachine.mInterfaceName.equals(iface)) { + if (DBG) { + log("addressRemoved: " + address + " on " + iface + + " flags " + flags + " scope " + scope); + } + mWifiStateMachine.sendMessage(CMD_IP_ADDRESS_REMOVED, new LinkAddress(address)); + } + } + } + + private InterfaceObserver mInterfaceObserver; + private AlarmManager mAlarmManager; private PendingIntent mScanIntent; private PendingIntent mDriverStopIntent; @@ -372,6 +420,12 @@ public class WifiStateMachine extends StateMachine { public static final int CMD_START_NEXT_BATCHED_SCAN = BASE + 136; public static final int CMD_POLL_BATCHED_SCAN = BASE + 137; + /* Link configuration (IP address, DNS, ...) changes */ + /* An new IP address was added to our interface, or an existing IP address was updated */ + static final int CMD_IP_ADDRESS_UPDATED = BASE + 140; + /* An IP address was removed from our interface */ + static final int CMD_IP_ADDRESS_REMOVED = BASE + 141; + public static final int CONNECT_MODE = 1; public static final int SCAN_ONLY_MODE = 2; public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3; @@ -585,15 +639,22 @@ public class WifiStateMachine extends StateMachine { mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore, getHandler()); mLinkProperties = new LinkProperties(); + mNetlinkLinkProperties = new LinkProperties(); mWifiP2pManager = (WifiP2pManager) mContext.getSystemService(Context.WIFI_P2P_SERVICE); mNetworkInfo.setIsAvailable(false); - mLinkProperties.clear(); mLastBssid = null; mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; mLastSignalLevel = -1; + mInterfaceObserver = new InterfaceObserver(this); + try { + mNwService.registerObserver(mInterfaceObserver); + } catch (RemoteException e) { + loge("Couldn't register interface observer: " + e.toString()); + } + mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); Intent scanIntent = new Intent(ACTION_START_SCAN, null); mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0); @@ -1906,19 +1967,82 @@ public class WifiStateMachine extends StateMachine { } } - private void configureLinkProperties() { - if (mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { - mLinkProperties = mWifiConfigStore.getLinkProperties(mLastNetworkId); - } else { - synchronized (mDhcpResultsLock) { - if ((mDhcpResults != null) && (mDhcpResults.linkProperties != null)) { - mLinkProperties = mDhcpResults.linkProperties; + /** + * Updates mLinkProperties by merging information from various sources. + * + * This is needed because the information in mLinkProperties comes from multiple sources (DHCP, + * netlink, static configuration, ...). When one of these sources of information has updated + * link properties, we can't just assign them to mLinkProperties or we'd lose track of the + * information that came from other sources. Instead, when one of those sources has new + * information, we update the object that tracks the information from that source and then + * call this method to apply the change to mLinkProperties. + * + * The information in mLinkProperties is currently obtained as follows: + * - Interface name: set in the constructor. + * - IPv4 and IPv6 addresses: netlink, via mInterfaceObserver. + * - IPv4 routes, DNS servers, and domains: DHCP. + * - HTTP proxy: the wifi config store. + */ + private void updateLinkProperties() { + LinkProperties newLp = new LinkProperties(); + + // Interface name and proxy are locally configured. + newLp.setInterfaceName(mInterfaceName); + newLp.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); + + // IPv4 and IPv6 addresses come from netlink. + newLp.setLinkAddresses(mNetlinkLinkProperties.getLinkAddresses()); + + // For now, routing and DNS only come from DHCP or static configuration. In the future, + // we'll need to merge IPv6 DNS servers and domains coming from netlink. + synchronized (mDhcpResultsLock) { + // Even when we're using static configuration, we don't need to look at the config + // store, because static IP configuration also populates mDhcpResults. + if ((mDhcpResults != null) && (mDhcpResults.linkProperties != null)) { + LinkProperties lp = mDhcpResults.linkProperties; + for (RouteInfo route: lp.getRoutes()) { + newLp.addRoute(route); + } + for (InetAddress dns: lp.getDnses()) { + newLp.addDns(dns); } + newLp.setDomains(lp.getDomains()); + } + } + + // If anything has changed, and we're already connected, send out a notification. + // If we're still connecting, apps will be notified when we connect. + if (!newLp.equals(mLinkProperties)) { + if (DBG) { + log("Link configuration changed for netId: " + mLastNetworkId + + " old: " + mLinkProperties + "new: " + newLp); + } + mLinkProperties = newLp; + if (getNetworkDetailedState() == DetailedState.CONNECTED) { + sendLinkConfigurationChangedBroadcast(); } - mLinkProperties.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); } - mLinkProperties.setInterfaceName(mInterfaceName); - if (DBG) log("netId=" + mLastNetworkId + " Link configured: " + mLinkProperties); + } + + /** + * Clears all our link properties. + */ + private void clearLinkProperties() { + // If the network used DHCP, clear the LinkProperties we stored in the config store. + if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { + mWifiConfigStore.clearLinkProperties(mLastNetworkId); + } + + // Clear the link properties obtained from DHCP and netlink. + synchronized(mDhcpResultsLock) { + if (mDhcpResults != null && mDhcpResults.linkProperties != null) { + mDhcpResults.linkProperties.clear(); + } + } + mNetlinkLinkProperties.clear(); + + // Now clear the merged link properties. + mLinkProperties.clear(); } private int getMaxDhcpRetries() { @@ -2041,16 +2165,11 @@ public class WifiStateMachine extends StateMachine { mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); /* Clear network properties */ - mLinkProperties.clear(); + clearLinkProperties(); /* send event to CM & network change broadcast */ sendNetworkStateChangeBroadcast(mLastBssid); - /* Clear IP settings if the network used DHCP */ - if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { - mWifiConfigStore.clearLinkProperties(mLastNetworkId); - } - mLastBssid= null; mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; } @@ -2149,20 +2268,7 @@ public class WifiStateMachine extends StateMachine { } mWifiInfo.setInetAddress(addr); mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint()); - if (getNetworkDetailedState() == DetailedState.CONNECTED) { - //DHCP renewal in connected state - linkProperties.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); - if (!linkProperties.equals(mLinkProperties)) { - if (DBG) { - log("Link configuration changed for netId: " + mLastNetworkId - + " old: " + mLinkProperties + "new: " + linkProperties); - } - mLinkProperties = linkProperties; - sendLinkConfigurationChangedBroadcast(); - } - } else { - configureLinkProperties(); - } + updateLinkProperties(); } private void handleFailedIpConfiguration() { @@ -2387,6 +2493,17 @@ public class WifiStateMachine extends StateMachine { mTemporarilyDisconnectWifi = (message.arg1 == 1); replyToMessage(message, WifiP2pService.DISCONNECT_WIFI_RESPONSE); break; + case CMD_IP_ADDRESS_UPDATED: + // addLinkAddress is a no-op if called more than once with the same address. + if (mNetlinkLinkProperties.addLinkAddress((LinkAddress) message.obj)) { + updateLinkProperties(); + } + break; + case CMD_IP_ADDRESS_REMOVED: + if (mNetlinkLinkProperties.removeLinkAddress((LinkAddress) message.obj)) { + updateLinkProperties(); + } + break; default: loge("Error! unhandled message" + message); break; @@ -3405,8 +3522,7 @@ public class WifiStateMachine extends StateMachine { } if (result.hasProxyChanged()) { log("Reconfiguring proxy on connection"); - configureLinkProperties(); - sendLinkConfigurationChangedBroadcast(); + updateLinkProperties(); } } @@ -3460,13 +3576,14 @@ public class WifiStateMachine extends StateMachine { @Override public void enter() { if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { + // TODO: If we're switching between static IP configuration and DHCP, remove the + // static configuration first. startDhcp(); } else { // stop any running dhcp before assigning static IP stopDhcp(); DhcpResults dhcpResults = new DhcpResults( mWifiConfigStore.getLinkProperties(mLastNetworkId)); - dhcpResults.linkProperties.setInterfaceName(mInterfaceName); InterfaceConfiguration ifcg = new InterfaceConfiguration(); Iterator<LinkAddress> addrs = dhcpResults.linkProperties.getLinkAddresses().iterator(); diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java index 62630d6..615c893 100644 --- a/wifi/java/android/net/wifi/WifiStateTracker.java +++ b/wifi/java/android/net/wifi/WifiStateTracker.java @@ -22,12 +22,12 @@ import android.content.Intent; import android.content.IntentFilter; import android.net.BaseNetworkStateTracker; import android.net.LinkCapabilities; -import android.net.LinkInfo; +import android.net.LinkQualityInfo; import android.net.LinkProperties; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.SamplingDataTracker; -import android.net.WifiLinkInfo; +import android.net.WifiLinkQualityInfo; import android.os.Handler; import android.os.Message; import android.os.Messenger; @@ -203,35 +203,35 @@ public class WifiStateTracker extends BaseNetworkStateTracker { /** * Return link info - * @return an object of type WifiLinkInfo + * @return an object of type WifiLinkQualityInfo */ @Override - public LinkInfo getLinkInfo() { + public LinkQualityInfo getLinkQualityInfo() { if (mNetworkInfo == null) { // no data available yet; just return return null; } - WifiLinkInfo li = new WifiLinkInfo(); - li.mNetworkType = mNetworkInfo.getType(); + WifiLinkQualityInfo li = new WifiLinkQualityInfo(); + li.setNetworkType(mNetworkInfo.getType()); synchronized(mSamplingDataTracker.mSamplingDataLock) { - mSamplingDataTracker.setCommonLinkInfoFields(li); - li.mTxGood = mSamplingDataTracker.getSampledTxPacketCount(); - li.mTxBad = mSamplingDataTracker.getSampledTxPacketErrorCount(); + mSamplingDataTracker.setCommonLinkQualityInfoFields(li); + li.setTxGood(mSamplingDataTracker.getSampledTxPacketCount()); + li.setTxBad(mSamplingDataTracker.getSampledTxPacketErrorCount()); } // li.setTheoreticalRxBandwidth(??); // li.setTheoreticalTxBandwidth(??); if (mWifiInfo != null) { - li.mBssid = mWifiInfo.getBSSID(); + li.setBssid(mWifiInfo.getBSSID()); int rssi = mWifiInfo.getRssi(); - li.mRssi = rssi; + li.setRssi(rssi); - li.mNormalizedSignalStrength = mWifiManager.calculateSignalLevel(rssi, - LinkInfo.NORMALIZED_SIGNAL_STRENGTH_RANGE); + li.setNormalizedSignalStrength(mWifiManager.calculateSignalLevel(rssi, + LinkQualityInfo.NORMALIZED_SIGNAL_STRENGTH_RANGE)); } return li; |