Android -- WifiConfigStore简介
WifiConfigStore在Android的无线网络部分,主要负责网络配置信息的管理工作,包括保存、读取配置信息等。当我们在Settings中触发一个保存网络、连接网络或者auto_connect自动重连动作时,都会调用到WifiConfigStore中的方法。
WifiConfigStore继承自IpConfigStore,它提供了一套API去管理用户配置过的网络。下面介绍一些framework中经常调用到的API接口。
- public class WifiConfigStore extends IpConfigStore
一、saveNetwork()、selectNetwork()
WifiStateMachine中,WifiConfigStore对象的创建发生在其构造函数中:
我们传入了Context、当前的WifiStateMachine对象和一个WifiNative对象。通过mWifiNative对象可以向wpa_s下发一系列连接、选择的命令。
- mWifiConfigStore = new WifiConfigStore(context,this, mWifiNative);
我们在连接一个网络的时候,会先保存该网络的配置信息,调用:
saveNetwork()主要负责根据WifiConfiguration对象更新、保存网络的各配置信息;WifiConfiguration代表一个配置过的网络,主要包括该网络的加密方式、SSID、密钥等等信息。重要的一个操作是调用addOrUpdateNetworkNative()来更新配置信息、并保存到本地;该函数的函数实现虽然较多,看起来复杂,但实际处理却还是较为简单的:
- /**
- * Add/update the specified configuration and save config
- *
- * @param config WifiConfiguration to be saved
- * @return network update result
- */
- NetworkUpdateResult saveNetwork(WifiConfiguration config, int uid) {
- WifiConfiguration conf;
- // A new network cannot have null SSID
- if (config == null || (config.networkId == INVALID_NETWORK_ID &&
- config.SSID == null)) {
- return new NetworkUpdateResult(INVALID_NETWORK_ID);
- }
- if (VDBG) localLog("WifiConfigStore: saveNetwork netId", config.networkId);
- if (VDBG) {
- loge("WifiConfigStore saveNetwork, size=" + mConfiguredNetworks.size()
- + " SSID=" + config.SSID
- + " Uid=" + Integer.toString(config.creatorUid)
- + "/" + Integer.toString(config.lastUpdateUid));
- }
- if (mDeletedEphemeralSSIDs.remove(config.SSID)) {
- if (VDBG) {
- loge("WifiConfigStore: removed from ephemeral blacklist: " + config.SSID);
- }
- // NOTE: This will be flushed to disk as part of the addOrUpdateNetworkNative call
- // below, since we're creating/modifying a config.
- }
- boolean newNetwork = (config.networkId == INVALID_NETWORK_ID);
- NetworkUpdateResult result = addOrUpdateNetworkNative(config, uid);
- int netId = result.getNetworkId();
- if (VDBG) localLog("WifiConfigStore: saveNetwork got it back netId=", netId);
- /* enable a new network */
- if (newNetwork && netId != INVALID_NETWORK_ID) {
- if (VDBG) localLog("WifiConfigStore: will enable netId=", netId);
- mWifiNative.enableNetwork(netId, false);
- conf = mConfiguredNetworks.get(netId);
- if (conf != null)
- conf.status = Status.ENABLED;
- }
- conf = mConfiguredNetworks.get(netId);
- if (conf != null) {
- if (conf.autoJoinStatus != WifiConfiguration.AUTO_JOIN_ENABLED) {
- if (VDBG) localLog("WifiConfigStore: re-enabling: " + conf.SSID);
- // reenable autojoin, since new information has been provided
- conf.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
- enableNetworkWithoutBroadcast(conf.networkId, false);
- }
- if (VDBG) {
- loge("WifiConfigStore: saveNetwork got config back netId="
- + Integer.toString(netId)
- + " uid=" + Integer.toString(config.creatorUid));
- }
- }
- mWifiNative.saveConfig();
- sendConfiguredNetworksChangedBroadcast(conf, result.isNewNetwork() ?
- WifiManager.CHANGE_REASON_ADDED : WifiManager.CHANGE_REASON_CONFIG_CHANGE);
- return result;
- }
- 首先从mConfiguredNetworks中根据传入的config对象获取到先前保存过的同netId的savedConfig对象;mConfiguredNetworks是一个HasMap结构,它以某个网络的netId为key,以对应的WifiConfiguration对象作为value,由此可知它以键值对的形式保存了当前所有配置过的网络信息。后续的操作都是比对config和savedConfig直接的差异,保存到wpa_s配置文件中并进行更新,最后再将更新过的WifiConfiguration对象保存到mConfiguredNetworks中。
- 调用writeIpAndProxyConfigurationsOnChange()将新的配置信息保存到本地文件/misc/wifi/ipconfig.txt中。后面会说到,当我们重新打开Wifi时,会从该文件中读取我们所配置过的网络信息,并进行重连。
- /* Compare current and new configuration and write to file on change */
- private NetworkUpdateResult writeIpAndProxyConfigurationsOnChange(
- WifiConfiguration currentConfig,
- WifiConfiguration newConfig) {
- boolean ipChanged = false;
- boolean proxyChanged = false;
- if (VDBG) {
- loge("writeIpAndProxyConfigurationsOnChange: " + currentConfig.SSID + " -> " +
- newConfig.SSID + " path: " + ipConfigFile);
- }
- switch (newConfig.getIpAssignment()) {
- case STATIC:
- if (currentConfig.getIpAssignment() != newConfig.getIpAssignment()) {
- ipChanged = true;
- } else {
- ipChanged = !Objects.equals(
- currentConfig.getStaticIpConfiguration(),
- newConfig.getStaticIpConfiguration());
- }
- break;
- case DHCP:
- if (currentConfig.getIpAssignment() != newConfig.getIpAssignment()) {
- ipChanged = true;
- }
- break;
- case UNASSIGNED:
- /* Ignore */
- break;
- default:
- loge("Ignore invalid ip assignment during write");
- break;
- }
- switch (newConfig.getProxySettings()) {
- case STATIC:
- case PAC:
- ProxyInfo newHttpProxy = newConfig.getHttpProxy();
- ProxyInfo currentHttpProxy = currentConfig.getHttpProxy();
- if (newHttpProxy != null) {
- proxyChanged = !newHttpProxy.equals(currentHttpProxy);
- } else {
- proxyChanged = (currentHttpProxy != null);
- }
- break;
- case NONE:
- if (currentConfig.getProxySettings() != newConfig.getProxySettings()) {
- proxyChanged = true;
- }
- break;
- case UNASSIGNED:
- /* Ignore */
- break;
- default:
- loge("Ignore invalid proxy configuration during write");
- break;
- }
- if (ipChanged) {
- currentConfig.setIpAssignment(newConfig.getIpAssignment());
- currentConfig.setStaticIpConfiguration(newConfig.getStaticIpConfiguration());
- log("IP config changed SSID = " + currentConfig.SSID);
- if (currentConfig.getStaticIpConfiguration() != null) {
- log(" static configuration: " +
- currentConfig.getStaticIpConfiguration().toString());
- }
- }
- if (proxyChanged) {
- currentConfig.setProxySettings(newConfig.getProxySettings());
- currentConfig.setHttpProxy(newConfig.getHttpProxy());
- log("proxy changed SSID = " + currentConfig.SSID);
- if (currentConfig.getHttpProxy() != null) {
- log(" proxyProperties: " + currentConfig.getHttpProxy().toString());
- }
- }
- if (ipChanged || proxyChanged) {
- writeIpAndProxyConfigurations();
- sendConfiguredNetworksChangedBroadcast(currentConfig,
- WifiManager.CHANGE_REASON_CONFIG_CHANGE);
- }
- return new NetworkUpdateResult(ipChanged, proxyChanged);
- }
- public enum IpAssignment {
- /* Use statically configured IP settings. Configuration can be accessed
- * with staticIpConfiguration */
- STATIC,
- /* Use dynamically configured IP settigns */
- DHCP,
- /* no IP details are assigned, this is used to indicate
- * that any existing IP settings should be retained */
- UNASSIGNED
- }
- public enum ProxySettings {
- /* No proxy is to be used. Any existing proxy settings
- * should be cleared. */
- NONE,
- /* Use statically configured proxy. Configuration can be accessed
- * with httpProxy. */
- STATIC,
- /* no proxy details are assigned, this is used to indicate
- * that any existing proxy settings should be retained */
- UNASSIGNED,
- /* Use a Pac based proxy.
- */
- PAC
- }
- if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
- if (isRoaming()) {
- renewDhcp();
- } else {
- // Remove any IP address on the interface in case we're switching from static
- // IP configuration to DHCP. This is safe because if we get here when not
- // roaming, we don't have a usable address.
- clearIPv4Address(mInterfaceName);
- startDhcp();
- }
- obtainingIpWatchdogCount++;
- logd("Start Dhcp Watchdog " + obtainingIpWatchdogCount);
- // Get Link layer stats so as we get fresh tx packet counters
- getWifiLinkLayerStats(true);
- sendMessageDelayed(obtainMessage(CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER,
- obtainingIpWatchdogCount, 0), OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC);
- } else {
- // stop any running dhcp before assigning static IP
- stopDhcp();
- StaticIpConfiguration config = mWifiConfigStore.getStaticIpConfiguration(
- mLastNetworkId);
- if (config.ipAddress == null) {
- logd("Static IP lacks address");
- sendMessage(CMD_STATIC_IP_FAILURE);
- } else {
- InterfaceConfiguration ifcg = new InterfaceConfiguration();
- ifcg.setLinkAddress(config.ipAddress);
- ifcg.setInterfaceUp();
- try {
- mNwService.setInterfaceConfig(mInterfaceName, ifcg);
- if (DBG) log("Static IP configuration succeeded");
- DhcpResults dhcpResults = new DhcpResults(config);
- sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults);
- } catch (RemoteException re) {
- loge("Static IP configuration failed: " + re);
- sendMessage(CMD_STATIC_IP_FAILURE);
- } catch (IllegalStateException e) {
- loge("Static IP configuration failed: " + e);
- sendMessage(CMD_STATIC_IP_FAILURE);
- }
- }
- }
- /**
- * Return if the specified network is using static IP
- * @param netId id
- * @return {@code true} if using static ip for netId
- */
- boolean isUsingStaticIp(int netId) {
- WifiConfiguration config = mConfiguredNetworks.get(netId);
- if (config != null && config.getIpAssignment() == IpAssignment.STATIC) {
- return true;
- }
- return false;
- }
riteIpAndProxyConfigurationsOnChange()中会根据IpAssignment、ProxySettings的类型是否改变,去更新currentConfig对象,并writeIpAndProxyConfigurations()方法写入到本地磁盘文件:
最终写入文件的操作是父类IpConfigStore::writeConfig()方法处理的。在WifiConfigStore::writeIpAndProxyConfigurations()中,我们会将所有保存的网络配置信息从mConfiguredNetworks集合中取出,重新按照<一个唯一int值,IpConfiguration>的形式保存到一个SparseArray<IpConfiguration> networks对象中(可以看做是一个集合);ipConfigFile的值就是路径:"/misc/wifi/ipconfig.txt"。
- private void writeIpAndProxyConfigurations() {
- final SparseArray<IpConfiguration> networks = new SparseArray<IpConfiguration>();
- for(WifiConfiguration config : mConfiguredNetworks.values()) {
- if (!config.ephemeral && config.autoJoinStatus != WifiConfiguration.AUTO_JOIN_DELETED) {
- networks.put(configKey(config), config.getIpConfiguration());
- }
- }
- super.writeIpAndProxyConfigurations(ipConfigFile, networks);//in IpConfigStore
- }
- public void IpConfigStore::writeIpAndProxyConfigurations(String filePath,
- final SparseArray<IpConfiguration> networks) {
- mWriter.write(filePath, new DelayedDiskWrite.Writer() {
- public void onWriteCalled(DataOutputStream out) throws IOException{
- out.writeInt(IPCONFIG_FILE_VERSION);
- for(int i = 0; i < networks.size(); i++) {
- writeConfig(out, networks.keyAt(i), networks.valueAt(i));
- }
- }
- });
- }
- private boolean writeConfig(DataOutputStream out, int configKey,
- IpConfiguration config) throws IOException {
- boolean written = false;
- try {
- switch (config.ipAssignment) {
- case STATIC:
- out.writeUTF(IP_ASSIGNMENT_KEY);
- out.writeUTF(config.ipAssignment.toString());
- StaticIpConfiguration staticIpConfiguration = config.staticIpConfiguration;
- if (staticIpConfiguration != null) {
- if (staticIpConfiguration.ipAddress != null) {
- LinkAddress ipAddress = staticIpConfiguration.ipAddress;
- out.writeUTF(LINK_ADDRESS_KEY);
- out.writeUTF(ipAddress.getAddress().getHostAddress());
- out.writeInt(ipAddress.getPrefixLength());
- }
- if (staticIpConfiguration.gateway != null) {
- out.writeUTF(GATEWAY_KEY);
- out.writeInt(0); // Default route.
- out.writeInt(1); // Have a gateway.
- out.writeUTF(staticIpConfiguration.gateway.getHostAddress());
- }
- for (InetAddress inetAddr : staticIpConfiguration.dnsServers) {
- out.writeUTF(DNS_KEY);
- out.writeUTF(inetAddr.getHostAddress());
- }
- }
- written = true;
- break;
- case DHCP:
- out.writeUTF(IP_ASSIGNMENT_KEY);
- out.writeUTF(config.ipAssignment.toString());
- written = true;
- break;
- case UNASSIGNED:
- /* Ignore */
- break;
- default:
- loge("Ignore invalid ip assignment while writing");
- break;
- }
- switch (config.proxySettings) {
- case STATIC:
- ProxyInfo proxyProperties = config.httpProxy;
- String exclusionList = proxyProperties.getExclusionListAsString();
- out.writeUTF(PROXY_SETTINGS_KEY);
- out.writeUTF(config.proxySettings.toString());
- out.writeUTF(PROXY_HOST_KEY);
- out.writeUTF(proxyProperties.getHost());
- out.writeUTF(PROXY_PORT_KEY);
- out.writeInt(proxyProperties.getPort());
- if (exclusionList != null) {
- out.writeUTF(EXCLUSION_LIST_KEY);
- out.writeUTF(exclusionList);
- }
- written = true;
- break;
- case PAC:
- ProxyInfo proxyPacProperties = config.httpProxy;
- out.writeUTF(PROXY_SETTINGS_KEY);
- out.writeUTF(config.proxySettings.toString());
- out.writeUTF(PROXY_PAC_FILE);
- out.writeUTF(proxyPacProperties.getPacFileUrl().toString());
- written = true;
- break;
- case NONE:
- out.writeUTF(PROXY_SETTINGS_KEY);
- out.writeUTF(config.proxySettings.toString());
- written = true;
- break;
- case UNASSIGNED:
- /* Ignore */
- break;
- default:
- loge("Ignore invalid proxy settings while writing");
- break;
- }
- if (written) {
- out.writeUTF(ID_KEY);
- out.writeInt(configKey);
- }
- } catch (NullPointerException e) {
- loge("Failure in writing " + config + e);
- }
- out.writeUTF(EOS);
- return written;
- }
在IpConfigStore::writeIpAndProxyConfigurations和IpConfigStore::writeConfig()中,我们会遍历networks集合,并按照
的分类,将信息写入ipconfig.txt文件中;这里的写入也是有一定的规则的,每一个标签后面跟一个该标签对应的值。这样做方法后面的数据读取。定义的标签值有:
从这里我们可以看到一些可以定制的地方。现在,有一部分Android手机上的Wifi功能是支持无线PPPoE的;要使用PPPoE,就要用到账户信息;此时,我们是否可以在WifiConfiguration或IpConfiguration中添加对应的账户属性字段,在保存网络时,加入对账户密码字段的写入保存动作;同时,在从ipconfig.txt读取信息时,将该信息重新封装到WifiConfiguration或IpConfiguration对象中,供无线PPPoE获取IP时使用。
- switch (config.ipAssignment)
- switch (config.proxySettings)
- /* IP and proxy configuration keys */
- protected static final String ID_KEY = "id";
- protected static final String IP_ASSIGNMENT_KEY = "ipAssignment";
- protected static final String LINK_ADDRESS_KEY = "linkAddress";
- protected static final String GATEWAY_KEY = "gateway";
- protected static final String DNS_KEY = "dns";
- protected static final String PROXY_SETTINGS_KEY = "proxySettings";
- protected static final String PROXY_HOST_KEY = "proxyHost";
- protected static final String PROXY_PORT_KEY = "proxyPort";
- protected static final String PROXY_PAC_FILE = "proxyPac";
- protected static final String EXCLUSION_LIST_KEY = "exclusionList";
- protected static final String EOS = "eos";
- protected static final int IPCONFIG_FILE_VERSION = 2;
最后还会涉及到writeKnownNetworkHistory()的调用,它会向/misc/wifi/networkHistory.txt中写入每个WifiConfiguration对象中的一些字段值,包括优先级、SSID等等;写入方式跟前面相同。这里,saveNetwork()的处理就结束了。
selectNetwork()的作用是选择一个特定的网络去准备连接,这里会涉及到网络优先级更新和enable网络的部分。
- /**
- * Selects the specified network for connection. This involves
- * updating the priority of all the networks and enabling the given
- * network while disabling others.
- *
- * Selecting a network will leave the other networks disabled and
- * a call to enableAllNetworks() needs to be issued upon a connection
- * or a failure event from supplicant
- *
- * @param config network to select for connection
- * @param updatePriorities makes config highest priority network
- * @return false if the network id is invalid
- */
- boolean selectNetwork(WifiConfiguration config, boolean updatePriorities, int uid) {
- if (VDBG) localLog("selectNetwork", config.networkId);
- if (config.networkId == INVALID_NETWORK_ID) return false;
- // Reset the priority of each network at start or if it goes too high.
- if (mLastPriority == -1 || mLastPriority > 1000000) {
- for(WifiConfiguration config2 : mConfiguredNetworks.values()) {
- if (updatePriorities) {
- if (config2.networkId != INVALID_NETWORK_ID) {
- config2.priority = 0;
- setNetworkPriorityNative(config2.networkId, config.priority);
- }
- }
- }
- mLastPriority = 0;
- }
- // Set to the highest priority and save the configuration.
- if (updatePriorities) {
- config.priority = ++mLastPriority;
- setNetworkPriorityNative(config.networkId, config.priority);
- buildPnoList();
- }
- if (config.isPasspoint()) {
- /* need to slap on the SSID of selected bssid to work */
- if (getScanDetailCache(config).size() != 0) {
- ScanDetail result = getScanDetailCache(config).getFirst();
- if (result == null) {
- loge("Could not find scan result for " + config.BSSID);
- } else {
- log("Setting SSID for " + config.networkId + " to" + result.getSSID());
- setSSIDNative(config.networkId, result.getSSID());
- config.SSID = result.getSSID();
- }
- } else {
- loge("Could not find bssid for " + config);
- }
- }
- if (updatePriorities)
- mWifiNative.saveConfig();
- else
- mWifiNative.selectNetwork(config.networkId);
- updateLastConnectUid(config, uid);
- writeKnownNetworkHistory(false);
- /* Enable the given network while disabling all other networks */
- enableNetworkWithoutBroadcast(config.networkId, true);
- /* Avoid saving the config & sending a broadcast to prevent settings
- * from displaying a disabled list of networks */
- return true;
- }
- // Set to the highest priority and save the configuration.
- if (updatePriorities) {
- config.priority = ++mLastPriority;
- setNetworkPriorityNative(config.networkId, config.priority);
- buildPnoList();
- }
- /* Mark all networks except specified netId as disabled */
- private void markAllNetworksDisabledExcept(int netId) {
- for(WifiConfiguration config : mConfiguredNetworks.values()) {
- if(config != null && config.networkId != netId) {
- if (config.status != Status.DISABLED) {
- config.status = Status.DISABLED;
- config.disableReason = WifiConfiguration.DISABLED_UNKNOWN_REASON;
- }
- }
- }
- <p> }</p>
二、重新打开Wifi时,ipconfig.txt文件的读取
当我们重新打开Wifi时,Wifi正常情况下都会有网络自动重连的动作。此时,WifiStateMachine中:- mWifiConfigStore.loadAndEnableAllNetworks();
- /**
- * Fetch the list of configured networks
- * and enable all stored networks in supplicant.
- */
- void loadAndEnableAllNetworks() {
- if (DBG) log("Loading config and enabling all networks ");
- loadConfiguredNetworks();
- enableAllNetworks();
- }
- void loadConfiguredNetworks() {
- mLastPriority = 0;
- mConfiguredNetworks.clear();
- int last_id = -1;
- boolean done = false;
- while (!done) {
- String listStr = mWifiNative.listNetworks(last_id);
- if (listStr == null)
- return;
- String[] lines = listStr.split("\n");
- if (showNetworks) {
- localLog("WifiConfigStore: loadConfiguredNetworks: ");
- for (String net : lines) {
- localLog(net);
- }
- }
- // Skip the first line, which is a header
- for (int i = 1; i < lines.length; i++) {
- String[] result = lines[i].split("\t");
- // network-id | ssid | bssid | flags
- WifiConfiguration config = new WifiConfiguration();
- try {
- config.networkId = Integer.parseInt(result[0]);
- last_id = config.networkId;
- } catch(NumberFormatException e) {
- loge("Failed to read network-id '" + result[0] + "'");
- continue;
- }
- if (result.length > 3) {
- if (result[3].indexOf("[CURRENT]") != -1)
- config.status = WifiConfiguration.Status.CURRENT;
- else if (result[3].indexOf("[DISABLED]") != -1)
- config.status = WifiConfiguration.Status.DISABLED;
- else
- config.status = WifiConfiguration.Status.ENABLED;
- } else {
- config.status = WifiConfiguration.Status.ENABLED;
- }
- readNetworkVariables(config);
- Checksum csum = new CRC32();
- if (config.SSID != null) {
- csum.update(config.SSID.getBytes(), 0, config.SSID.getBytes().length);
- long d = csum.getValue();
- if (mDeletedSSIDs.contains(d)) {
- loge(" got CRC for SSID " + config.SSID + " -> " + d + ", was deleted");
- }
- }
- if (config.priority > mLastPriority) {
- mLastPriority = config.priority;
- }
- config.setIpAssignment(IpAssignment.DHCP);//默认设置DHCP
- config.setProxySettings(ProxySettings.NONE);//默认设置NONE
- if (mConfiguredNetworks.getByConfigKey(config.configKey()) != null) {
- // That SSID is already known, just ignore this duplicate entry
- if (showNetworks) localLog("discarded duplicate network ", config.networkId);
- } else if(WifiServiceImpl.isValid(config)){
- mConfiguredNetworks.put(config.networkId, config);
- if (showNetworks) localLog("loaded configured network", config.networkId);
- } else {
- if (showNetworks) log("Ignoring loaded configured for network " + config.networkId
- + " because config are not valid");
- }
- }
- done = (lines.length == 1);
- }
- readPasspointConfig();
- readIpAndProxyConfigurations();//读取ipconfig.txt
- readNetworkHistory();//读取networkHistory.txt
- readAutoJoinConfig();
- buildPnoList();
- sendConfiguredNetworksChangedBroadcast();
- if (showNetworks) localLog("loadConfiguredNetworks loaded " + mConfiguredNetworks.size() + " networks");
- if (mConfiguredNetworks.isEmpty()) {
- // no networks? Lets log if the file contents
- logKernelTime();
- logContents(SUPPLICANT_CONFIG_FILE);
- logContents(SUPPLICANT_CONFIG_FILE_BACKUP);
- logContents(networkHistoryConfigFile);
- }
- }
- 从wp_s读取保存的网络配置列表,并保存到mConfiguredNetworks中
- 调用readIpAndProxyConfigurations()方法,从ipconfig.txt中读取保存的IpConfiguration对象,更新到mConfiguredNetworks保存的各WifiConfiguration对象中
- 调用mConfiguredNetworks()方法,从/misc/wifi/networkHistory.txt文件中读取保存的信息,更新到mConfiguredNetworks保存的各WifiConfiguration对象中
读取的方式跟前面介绍的写入的方式基本相似。经过上所述的两次读取操作,我们持有的WifiConfiguration对象的信息就是比较完整的了。
如果有我们前面说过的无线PPPoE的场景,readIpAndProxyConfigurations()方法中就会把我们事先写入的账号密码信息也读取出来,存到mConfiguredNetworks中。走auto_connect流程时,获取到最近一次连接的网络netId,从mConfiguredNetworks中取出的对应的WifiConfiguration对象中就保存有PPPoE的账号密码,这样我们在PPPoE获取IP时,就有可用的账户信息了。
PS:
WifiConfigStore中定义了一个比较有意义的默认变量值:
从原生注释中,我们得知这个变量控制了当一个网络获取IP失败时,之后会继续重试的次数;如果值定义为9,那么实际的重连次数将是9+1,为10。
如果我们有定制这个值,那么重连次数将以我们自定义配置的值为准:
- /**
- * The maximum number of times we will retry a connection to an access point
- * for which we have failed in acquiring an IP address from DHCP. A value of
- * N means that we will make N+1 connection attempts in all.
- * <p>
- * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default
- * value if a Settings value is not present.
- */
- private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
- int WifiConfigStore::getMaxDhcpRetries() {
- return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT,
- DEFAULT_MAX_DHCP_RETRIES);
- }
- /**
- * The maximum number of times we will retry a connection to an access
- * point for which we have failed in acquiring an IP address from DHCP.
- * A value of N means that we will make N+1 connection attempts in all.
- */
- public static final String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
- void handleSSIDStateChange(int netId, boolean enabled, String message, String BSSID) {
- WifiConfiguration config = mConfiguredNetworks.get(netId);
- if (config != null) {
- if (enabled) {
- loge("Ignoring SSID re-enabled from supplicant: " + config.configKey() +
- " had autoJoinStatus=" + Integer.toString(config.autoJoinStatus)
- + " self added " + config.selfAdded + " ephemeral " + config.ephemeral);
- //We should not re-enable the BSSID based on Supplicant reanable.
- // Framework will re-enable it after its own blacklist timer expires
- } else {
- loge("SSID temp disabled for " + config.configKey() +
- " had autoJoinStatus=" + Integer.toString(config.autoJoinStatus)
- + " self added " + config.selfAdded + " ephemeral " + config.ephemeral);
- if (message != null) {
- loge(" message=" + message);
- }
- if (config.selfAdded && config.lastConnected == 0) {
- // This is a network we self added, and we never succeeded,
- // the user did not create this network and never entered its credentials,
- // so we want to be very aggressive in disabling it completely.
- removeConfigAndSendBroadcastIfNeeded(config.networkId);
- } else {
- if (message != null) {
- if (message.contains("no identity")) {
- config.setAutoJoinStatus(
- WifiConfiguration.AUTO_JOIN_DISABLED_NO_CREDENTIALS);
- if (DBG) {
- loge("no identity blacklisted " + config.configKey() + " to "
- + Integer.toString(config.autoJoinStatus));
- }
- } else if (message.contains("WRONG_KEY")
- || message.contains("AUTH_FAILED")) {
- // This configuration has received an auth failure, so disable it
- // temporarily because we don't want auto-join to try it out.
- // this network may be re-enabled by the "usual"
- // enableAllNetwork function
- config.numAuthFailures++;
- if (config.numAuthFailures > maxAuthErrorsToBlacklist) {
- config.setAutoJoinStatus
- (WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE);
- disableNetwork(netId,
- WifiConfiguration.DISABLED_AUTH_FAILURE);
- loge("Authentication failure, blacklist " + config.configKey() + " "
- + Integer.toString(config.networkId)
- + " num failures " + config.numAuthFailures);
- }
- } else if (message.contains("DHCP FAILURE")) {
- config.numIpConfigFailures++;
- config.lastConnectionFailure = System.currentTimeMillis();
- int maxRetries = getMaxDhcpRetries();
- // maxRetries == 0 means keep trying forever
- if (maxRetries > 0 && config.numIpConfigFailures > maxRetries) {
- /**
- * If we've exceeded the maximum number of retries for DHCP
- * to a given network, disable the network
- */
- config.setAutoJoinStatus
- (WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE);
- disableNetwork(netId, WifiConfiguration.DISABLED_DHCP_FAILURE);
- loge("DHCP failure, blacklist " + config.configKey() + " "
- + Integer.toString(config.networkId)
- + " num failures " + config.numIpConfigFailures);
- }
- // Also blacklist the BSSId if we find it
- ScanResult result = null;
- String bssidDbg = "";
- if (getScanDetailCache(config) != null && BSSID != null) {
- result = getScanDetailCache(config).get(BSSID);
- }
- if (result != null) {
- result.numIpConfigFailures ++;
- bssidDbg = BSSID + " ipfail=" + result.numIpConfigFailures;
- if (result.numIpConfigFailures > 3) {
- // Tell supplicant to stop trying this BSSID
- mWifiNative.addToBlacklist(BSSID);
- result.setAutoJoinStatus(ScanResult.AUTO_JOIN_DISABLED);
- }
- }
- if (DBG) {
- loge("blacklisted " + config.configKey() + " to "
- + config.autoJoinStatus
- + " due to IP config failures, count="
- + config.numIpConfigFailures
- + " disableReason=" + config.disableReason
- + " " + bssidDbg);
- }
- } else if (message.contains("CONN_FAILED")) {
- config.numConnectionFailures++;
- if (config.numConnectionFailures > maxConnectionErrorsToBlacklist) {
- config.setAutoJoinStatus
- (WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE);
- disableNetwork(netId,
- WifiConfiguration.DISABLED_ASSOCIATION_REJECT);
- loge("Connection failure, blacklist " + config.configKey() + " "
- + config.networkId
- + " num failures " + config.numConnectionFailures);
- }
- }
- message.replace("\n", "");
- message.replace("\r", "");
- config.lastFailure = message;
- }
- }
- }
- }
- }
- private void WifiStateMachine::handleIpConfigurationLost() {
- mWifiInfo.setInetAddress(null);
- mWifiInfo.setMeteredHint(false);
- mWifiConfigStore.handleSSIDStateChange(mLastNetworkId, false,
- "DHCP FAILURE", mWifiInfo.getBSSID());//函数调用
- /* DHCP times out after about 30 seconds, we do a
- * disconnect thru supplicant, we will let autojoin retry connecting to the network
- */
- mWifiNative.disconnect();
- }
- 根据传入的message,实现中会根据message的内容,判断当前网络发生的错误是什么,并记录相应错误的次数;比如是WRONG_KEY、还是AUTH_FAILED、还是DHCP FAILURE;然后会更新WifiConfiguration对象中各个错误对应的字段值,例如:WRONG_KEY和AUTH_FAILED对应的字段就是numAuthFailures,它记录了授权失败的次数,如果授权失败的次数大于一定的值,就会将该网络的config.autoJoinStatus设为AUTO_JOIN_DISABLED_ON_AUTH_FAILURE,并disable当前网络。那么在之后的auto_connect流程中,判断autoJoinStatus不合法,就不会去继续重连流程。
- if (config.numAuthFailures > maxAuthErrorsToBlacklist) {
- config.setAutoJoinStatus
- (WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE);//设置autostatus
- disableNetwork(netId,
- WifiConfiguration.DISABLED_AUTH_FAILURE);//disable网络
- loge("Authentication failure, blacklist " + config.configKey() + " "
- + Integer.toString(config.networkId)
- + " num failures " + config.numAuthFailures);
- }
- 这里我们传入的message是DHCP FAILURE:
- else if (message.contains("DHCP FAILURE")) {
- config.numIpConfigFailures++;
- config.lastConnectionFailure = System.currentTimeMillis();
- int maxRetries = getMaxDhcpRetries();
- // maxRetries == 0 means keep trying forever
- if (maxRetries > 0 && config.numIpConfigFailures > maxRetries) {
- /**
- * If we've exceeded the maximum number of retries for DHCP
- * to a given network, disable the network
- */
- config.setAutoJoinStatus
- (WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE);//设置autostatus
- disableNetwork(netId, WifiConfiguration.DISABLED_DHCP_FAILURE);//disable网络
- loge("DHCP failure, blacklist " + config.configKey() + " "
- + Integer.toString(config.networkId)
- + " num failures " + config.numIpConfigFailures);
- }
- // Also blacklist the BSSId if we find it
- ScanResult result = null;
- String bssidDbg = "";
- if (getScanDetailCache(config) != null && BSSID != null) {
- result = getScanDetailCache(config).get(BSSID);
- }
- if (result != null) {
- result.numIpConfigFailures ++;
- bssidDbg = BSSID + " ipfail=" + result.numIpConfigFailures;
- if (result.numIpConfigFailures > 3) {
- // Tell supplicant to stop trying this BSSID
- mWifiNative.addToBlacklist(BSSID);//也有可能将当前网络加入到blacklist中
- result.setAutoJoinStatus(ScanResult.AUTO_JOIN_DISABLED);//设置autostatus
- }
- }
- if (DBG) {
- loge("blacklisted " + config.configKey() + " to "
- + config.autoJoinStatus
- + " due to IP config failures, count="
- + config.numIpConfigFailures
- + " disableReason=" + config.disableReason
- + " " + bssidDbg);
- }
- }