Android(安卓)-- Wifi连接流程分析
16lz
2021-12-04
Android -- Wifi连接流程分析
当我们在Android手机上通过Settings连接一个AP时,间接调用WifiManager的connect()方法: [java] view plain copy
- /**
- * Connect to a network with the given configuration. The network also
- * gets added to the supplicant configuration.
- *
- * For a new network, this function is used instead of a
- * sequence of addNetwork(), enableNetwork(), saveConfiguration() and
- * reconnect()
- *
- * @param config the set of variables that describe the configuration,
- * contained in a {@link WifiConfiguration} object.
- * @param listener for callbacks on success or failure. Can be null.
- * @throws IllegalStateException if the WifiManager instance needs to be
- * initialized again
- *
- * @hide
- */
- public void connect(WifiConfiguration config, ActionListener listener) {
- if (config == null) throw new IllegalArgumentException("config cannot be null");
- validateChannel();
- // Use INVALID_NETWORK_ID for arg1 when passing a config object
- // arg1 is used to pass network id when the network already exists
- sAsyncChannel.sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
- putListener(listener), config);
- }
- /**
- * Connect to a network with the given networkId.
- *
- * This function is used instead of a enableNetwork(), saveConfiguration() and
- * reconnect()
- *
- * @param networkId the network id identifiying the network in the
- * supplicant configuration list
- * @param listener for callbacks on success or failure. Can be null.
- * @throws IllegalStateException if the WifiManager instance needs to be
- * initialized again
- * @hide
- */
- public void connect(int networkId, ActionListener listener) {
- if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
- validateChannel();
- sAsyncChannel.sendMessage(CONNECT_NETWORK, networkId, putListener(listener));
- }
- /* Client commands are forwarded to state machine */
- case WifiManager.CONNECT_NETWORK:
- case WifiManager.SAVE_NETWORK: {
- WifiConfiguration config = (WifiConfiguration) msg.obj;
- int networkId = msg.arg1;
- if (msg.what == WifiManager.SAVE_NETWORK) {
- Slog.e("WiFiServiceImpl ", "SAVE"
- + " nid=" + Integer.toString(networkId)
- + " uid=" + msg.sendingUid
- + " name="
- + mContext.getPackageManager().getNameForUid(msg.sendingUid));
- }
- if (msg.what == WifiManager.CONNECT_NETWORK) {
- Slog.e("WiFiServiceImpl ", "CONNECT "
- + " nid=" + Integer.toString(networkId)
- + " uid=" + msg.sendingUid
- + " name="
- + mContext.getPackageManager().getNameForUid(msg.sendingUid));
- }
- if (config != null && isValid(config)) {
- if (DBG) Slog.d(TAG, "Connect with config" + config);
- mWifiStateMachine.sendMessage(Message.obtain(msg));
- } else if (config == null
- && networkId != WifiConfiguration.INVALID_NETWORK_ID) {
- if (DBG) Slog.d(TAG, "Connect with networkId" + networkId);
- mWifiStateMachine.sendMessage(Message.obtain(msg));
- } else {
- Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg);
- if (msg.what == WifiManager.CONNECT_NETWORK) {
- replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED,
- WifiManager.INVALID_ARGS);
- } else {
- replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED,
- WifiManager.INVALID_ARGS);
- }
- }
- break;
- }
- case WifiManager.CONNECT_NETWORK:
- /**
- * The connect message can contain a network id passed as arg1 on message or
- * or a config passed as obj on message.
- * For a new network, a config is passed to create and connect.
- * For an existing network, a network id is passed
- */
- netId = message.arg1;
- config = (WifiConfiguration) message.obj;
- mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
- boolean updatedExisting = false;
- /* Save the network config */
- if (config != null) {
- // When connecting to an access point, WifiStateMachine wants to update the
- // relevant config with administrative data. This update should not be
- // considered a 'real' update, therefore lockdown by Device Owner must be
- // disregarded.
- if (!recordUidIfAuthorized(config, message.sendingUid,
- /* onlyAnnotate */ true)) {
- logw("Not authorized to update network "
- + " config=" + config.SSID
- + " cnid=" + config.networkId
- + " uid=" + message.sendingUid);
- replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
- WifiManager.NOT_AUTHORIZED);
- break;
- }
- String configKey = config.configKey(true /* allowCached */);
- WifiConfiguration savedConfig =
- mWifiConfigStore.getWifiConfiguration(configKey);
- if (savedConfig != null) {
- // There is an existing config with this netId, but it wasn't exposed
- // (either AUTO_JOIN_DELETED or ephemeral; see WifiConfigStore#
- // getConfiguredNetworks). Remove those bits and update the config.
- config = savedConfig;
- logd("CONNECT_NETWORK updating existing config with id=" +
- config.networkId + " configKey=" + configKey);
- config.ephemeral = false;
- config.autoJoinStatus = WifiConfiguration.AUTO_JOIN_ENABLED;
- updatedExisting = true;
- }
- result = mWifiConfigStore.saveNetwork(config, message.sendingUid);
- netId = result.getNetworkId();
- }
- config = mWifiConfigStore.getWifiConfiguration(netId);
- if (config == null) {
- logd("CONNECT_NETWORK no config for id=" + Integer.toString(netId) + " "
- + mSupplicantStateTracker.getSupplicantStateName() + " my state "
- + getCurrentState().getName());
- replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
- WifiManager.ERROR);
- break;
- } else {
- String wasSkipped = config.autoJoinBailedDueToLowRssi ? " skipped" : "";
- logd("CONNECT_NETWORK id=" + Integer.toString(netId)
- + " config=" + config.SSID
- + " cnid=" + config.networkId
- + " supstate=" + mSupplicantStateTracker.getSupplicantStateName()
- + " my state " + getCurrentState().getName()
- + " uid = " + message.sendingUid
- + wasSkipped);
- }
- autoRoamSetBSSID(netId, "any");
- if (message.sendingUid == Process.WIFI_UID
- || message.sendingUid == Process.SYSTEM_UID) {
- // As a sanity measure, clear the BSSID in the supplicant network block.
- // If system or Wifi Settings want to connect, they will not
- // specify the BSSID.
- // If an app however had added a BSSID to this configuration, and the BSSID
- // was wrong, Then we would forever fail to connect until that BSSID
- // is cleaned up.
- clearConfigBSSID(config, "CONNECT_NETWORK");
- }
- if (deferForUserInput(message, netId, true)) {
- break;
- } else if (mWifiConfigStore.getWifiConfiguration(netId).userApproved ==
- WifiConfiguration.USER_BANNED) {
- replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
- WifiManager.NOT_AUTHORIZED);
- break;
- }
- mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
- /* Tell autojoin the user did try to connect to that network if from settings */
- boolean persist =
- mWifiConfigStore.checkConfigOverridePermission(message.sendingUid);
- mWifiAutoJoinController.updateConfigurationHistory(netId, true, persist);
- mWifiConfigStore.setLastSelectedConfiguration(netId);
- didDisconnect = false;
- if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID
- && mLastNetworkId != netId) {
- /** Supplicant will ignore the reconnect if we are currently associated,
- * hence trigger a disconnect
- */
- didDisconnect = true;
- mWifiNative.disconnect();
- }
- // Make sure the network is enabled, since supplicant will not reenable it
- mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false);
- if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ true,
- message.sendingUid) && mWifiNative.reconnect()) {
- lastConnectAttemptTimestamp = System.currentTimeMillis();
- targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId);
- /* The state tracker handles enabling networks upon completion/failure */
- mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK);
- replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
- if (didDisconnect) {
- /* Expect a disconnection from the old connection */
- transitionTo(mDisconnectingState);
- } else if (updatedExisting && getCurrentState() == mConnectedState &&
- getCurrentWifiConfiguration().networkId == netId) {
- // Update the current set of network capabilities, but stay in the
- // current state.
- updateCapabilities(config);
- } else {
- /**
- * Directly go to disconnected state where we
- * process the connection events from supplicant
- **/
- transitionTo(mDisconnectedState);
- }
- } else {
- loge("Failed to connect config: " + config + " netId: " + netId);
- replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
- WifiManager.ERROR);
- break;
- }
- break;
- 将connect()传过来的AP信息保存到WifiConfigStore对象中
- 通过WifiConfigStore::selectNetwork()函数更新WifiConfigStore和config的Priority优先级属性,最后更新到wpa_s配置文件中;enable当前要连接的AP,disable其他的AP
- 通过WifiNative::reconnect()函数向wpa_s发送连接指令,连接选定的AP
- /**
- * Handle all supplicant events except STATE-CHANGE
- * @param event the event type
- * @param remainder the rest of the string following the
- * event name and " — "
- */
- void handleEvent(int event, String remainder) {
- if (DBG) {
- logDbg("handleEvent " + Integer.toString(event) + " " + remainder);
- }
- switch (event) {
- case DISCONNECTED:
- handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder);
- break;
- case CONNECTED:
- handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder);
- break;
- case SCAN_RESULTS:
- mStateMachine.sendMessage(SCAN_RESULTS_EVENT);
- break;
- case SCAN_FAILED:
- mStateMachine.sendMessage(SCAN_FAILED_EVENT);
- break;
- case UNKNOWN:
- if (DBG) {
- logDbg("handleEvent unknown: " + Integer.toString(event) + " " + remainder);
- }
- break;
- default:
- break;
- }
- }
- private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) {
- String BSSID = null;
- int networkId = -1;
- int reason = 0;
- int ind = -1;
- int local = 0;
- Matcher match;
- if (newState == NetworkInfo.DetailedState.CONNECTED) {
- match = mConnectedEventPattern.matcher(data);
- if (!match.find()) {
- if (DBG) Log.d(TAG, "handleNetworkStateChange: Couldnt find BSSID in event string");
- } else {
- BSSID = match.group(1);
- try {
- networkId = Integer.parseInt(match.group(2));
- } catch (NumberFormatException e) {
- networkId = -1;
- }
- }
- notifyNetworkStateChange(newState, BSSID, networkId, reason);
- } else if (newState == NetworkInfo.DetailedState.DISCONNECTED) {
- match = mDisconnectedEventPattern.matcher(data);
- if (!match.find()) {
- if (DBG) Log.d(TAG, "handleNetworkStateChange: Could not parse disconnect string");
- } else {
- BSSID = match.group(1);
- try {
- reason = Integer.parseInt(match.group(2));
- } catch (NumberFormatException e) {
- reason = -1;
- }
- try {
- local = Integer.parseInt(match.group(3));
- } catch (NumberFormatException e) {
- local = -1;
- }
- }
- notifyNetworkStateChange(newState, BSSID, local, reason);
- }
- }
- /**
- * Send the state machine a notification that the state of Wifi connectivity
- * has changed.
- * @param newState the new network state
- * @param BSSID when the new state is {@link NetworkInfo.DetailedState#CONNECTED},
- * this is the MAC address of the access point. Otherwise, it
- * is {@code null}.
- * @param netId the configured network on which the state change occurred
- */
- void notifyNetworkStateChange(NetworkInfo.DetailedState newState,
- String BSSID, int netId, int reason) {
- if (newState == NetworkInfo.DetailedState.CONNECTED) {
- Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT,
- netId, reason, BSSID);
- mStateMachine.sendMessage(m);
- } else {
- Message m = mStateMachine.obtainMessage(NETWORK_DISCONNECTION_EVENT,
- netId, reason, BSSID);
- if (DBG) logDbg("WifiMonitor notify network disconnect: "
- + BSSID
- + " reason=" + Integer.toString(reason));
- mStateMachine.sendMessage(m);
- }
- }
- case WifiMonitor.NETWORK_CONNECTION_EVENT:
- if (DBG) log("Network connection established");
- mLastNetworkId = message.arg1; //成功加入到某无线网络中的AP的NetworkId
- mLastBssid = (String) message.obj;
- mWifiInfo.setBSSID(mLastBssid);
- mWifiInfo.setNetworkId(mLastNetworkId);
- sendNetworkStateChangeBroadcast(mLastBssid);
- transitionTo(mObtainingIpState);
- break;
- public void enter() {
- mRssiPollToken++;
- if (mEnableRssiPolling) {
- sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
- }
- if (mNetworkAgent != null) {
- loge("Have NetworkAgent when entering L2Connected");
- setNetworkDetailedState(DetailedState.DISCONNECTED);
- }
- setNetworkDetailedState(DetailedState.CONNECTING);//更新当前的网络连接状态
- if (!TextUtils.isEmpty(mTcpBufferSizes)) {
- mLinkProperties.setTcpBufferSizes(mTcpBufferSizes);
- }
- mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext,
- "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter,
- mLinkProperties, 60);//此处创建一个NetworkAgent对象用于向ConnectivityService通知相应的网络配置更新操作
- // We must clear the config BSSID, as the wifi chipset may decide to roam
- // from this point on and having the BSSID specified in the network block would
- // cause the roam to faile and the device to disconnect
- clearCurrentConfigBSSID("L2ConnectedState");
- try {
- mIpReachabilityMonitor = new IpReachabilityMonitor(
- mInterfaceName,
- new IpReachabilityMonitor.Callback() {
- @Override
- public void notifyLost(InetAddress ip, String logMsg) {
- sendMessage(CMD_IP_REACHABILITY_LOST, logMsg);
- }
- });
- } catch (IllegalArgumentException e) {
- Log.wtf("Failed to create IpReachabilityMonitor", e);
- }
- }
- @Override
- public void enter() {
- if (DBG) {
- String key = "";
- if (getCurrentWifiConfiguration() != null) {
- key = getCurrentWifiConfiguration().configKey();
- }
- log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId)
- + " " + key + " "
- + " roam=" + mAutoRoaming
- + " static=" + mWifiConfigStore.isUsingStaticIp(mLastNetworkId)
- + " watchdog= " + obtainingIpWatchdogCount);
- }
- // Reset link Debouncing, indicating we have successfully re-connected to the AP
- // We might still be roaming
- linkDebouncing = false;
- // Send event to CM & network change broadcast
- setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
- // We must clear the config BSSID, as the wifi chipset may decide to roam
- // from this point on and having the BSSID specified in the network block would
- // cause the roam to faile and the device to disconnect
- clearCurrentConfigBSSID("ObtainingIpAddress");
- try {
- mNwService.enableIpv6(mInterfaceName);
- } catch (RemoteException re) {
- loge("Failed to enable IPv6: " + re);
- } catch (IllegalStateException e) {
- loge("Failed to enable IPv6: " + e);
- }
- 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();// DHCP过程启动
- }
- 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);
- }
- }
- }
- }
- void startDhcp() {
- maybeInitDhcpStateMachine(); //确保初始化WifiStateMachine持有的mDhcpStateMachine对象,会传入当前的WifiStateMachine对象,用来回发消息
- mDhcpStateMachine.registerForPreDhcpNotification();//注册mRegisteredForPreDhcpNotification字段为true,表明我们在发送DHCP包之前需要做一些准备工作
- mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);//发送开始DHCP的消息
- }
- case CMD_START_DHCP:
- if (mRegisteredForPreDhcpNotification) {
- /* Notify controller before starting DHCP */
- mController.sendMessage(CMD_PRE_DHCP_ACTION);
- transitionTo(mWaitBeforeStartState);
- } else {
- if (runDhcpStart()) {
- transitionTo(mRunningState);
- }
- }
- break;
- case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
- handlePreDhcpSetup();
- break;
- void handlePreDhcpSetup() {
- mDhcpActive = true;
- if (!mBluetoothConnectionActive) {
- /*
- * There are problems setting the Wi-Fi driver's power
- * mode to active when bluetooth coexistence mode is
- * enabled or sense.
- *
- * We set Wi-Fi to active mode when
- * obtaining an IP address because we've found
- * compatibility issues with some routers with low power
- * mode.
- *
- * In order for this active power mode to properly be set,
- * we disable coexistence mode until we're done with
- * obtaining an IP address. One exception is if we
- * are currently connected to a headset, since disabling
- * coexistence would interrupt that connection.
- */
- // Disable the coexistence mode
- mWifiNative.setBluetoothCoexistenceMode(
- mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
- }
- // Disable power save and suspend optimizations during DHCP
- // Note: The order here is important for now. Brcm driver changes
- // power settings when we control suspend mode optimizations.
- // TODO: Remove this comment when the driver is fixed.
- setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false);
- mWifiNative.setPowerSave(false);
- // Update link layer stats
- getWifiLinkLayerStats(false);
- /* P2p discovery breaks dhcp, shut it down in order to get through this */
- Message msg = new Message();
- msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY;
- msg.arg1 = WifiP2pServiceImpl.ENABLED;
- msg.arg2 = DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE;
- msg.obj = mDhcpStateMachine;
- mWifiP2pChannel.sendMessage(msg);
- }
- case CMD_PRE_DHCP_ACTION_COMPLETE:
- if (runDhcpStart()) {
- transitionTo(mRunningState);
- } else {
- transitionTo(mPollingState);
- }
- break;
- private boolean runDhcpStart() {
- /* Stop any existing DHCP daemon before starting new */
- NetworkUtils.stopDhcp(mInterfaceName);//在启动新的DHCP流程之前,停止当前正在进行的DHCP过程
- mDhcpResults = null;
- if (DBG) Log.d(TAG, "DHCP request on " + mInterfaceName);
- if (!NetworkUtils.startDhcp(mInterfaceName) || !dhcpSucceeded()) {
- Log.e(TAG, "DHCP request failed on " + mInterfaceName + ": " +
- NetworkUtils.getDhcpError());
- mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0)
- .sendToTarget();
- return false;
- }
- return true;
- }
- private boolean dhcpSucceeded() {
- DhcpResults dhcpResults = new DhcpResults();
- if (!NetworkUtils.getDhcpResults(mInterfaceName, dhcpResults)) {
- return false;
- }
- if (DBG) Log.d(TAG, "DHCP results found for " + mInterfaceName);
- long leaseDuration = dhcpResults.leaseDuration; //int to long conversion
- //Sanity check for renewal
- if (leaseDuration >= 0) {
- //TODO: would be good to notify the user that his network configuration is
- //bad and that the device cannot renew below MIN_RENEWAL_TIME_SECS
- if (leaseDuration < MIN_RENEWAL_TIME_SECS) {
- leaseDuration = MIN_RENEWAL_TIME_SECS;
- }
- //Do it a bit earlier than half the lease duration time
- //to beat the native DHCP client and avoid extra packets
- //48% for one hour lease time = 29 minutes
- mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() +
- leaseDuration * 480, //in milliseconds
- mDhcpRenewalIntent);
- } else {
- //infinite lease time, no renewal needed
- }
- // Fill in any missing fields in dhcpResults from the previous results.
- // If mDhcpResults is null (i.e. this is the first server response),
- // this is a noop.
- dhcpResults.updateFromDhcpRequest(mDhcpResults);
- mDhcpResults = dhcpResults;
- mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpResults)
- .sendToTarget();
- return true;
- }
- case DhcpStateMachine.CMD_POST_DHCP_ACTION:
- handlePostDhcpSetup();
- if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
- if (DBG) log("DHCP successful");
- handleIPv4Success((DhcpResults) message.obj, DhcpStateMachine.DHCP_SUCCESS);
- // We advance to mConnectedState because handleIPv4Success will call
- // updateLinkProperties, which then sends CMD_IP_CONFIGURATION_SUCCESSFUL.
- } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
- mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_DHCP_FAILURE);
- if (DBG) {
- int count = -1;
- WifiConfiguration config = getCurrentWifiConfiguration();
- if (config != null) {
- count = config.numConnectionFailures;
- }
- log("DHCP failure count=" + count);
- }
- handleIPv4Failure(DhcpStateMachine.DHCP_FAILURE);
- // As above, we transition to mDisconnectingState via updateLinkProperties.
- }
- break;
- private void handleIPv4Success(DhcpResults dhcpResults, int reason) {
- if (PDBG) {
- logd("handleIPv4Success <" + dhcpResults.toString() + ">");
- logd("link address " + dhcpResults.ipAddress);
- }
- Inet4Address addr;
- synchronized (mDhcpResultsLock) {
- mDhcpResults = dhcpResults;//保存当前的DHCP结果
- addr = (Inet4Address) dhcpResults.ipAddress.getAddress();
- }
- if (isRoaming()) {
- int previousAddress = mWifiInfo.getIpAddress();
- int newAddress = NetworkUtils.inetAddressToInt(addr);
- if (previousAddress != newAddress) {
- logd("handleIPv4Success, roaming and address changed" +
- mWifiInfo + " got: " + addr);
- }
- }
- mWifiInfo.setInetAddress(addr);
- mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint());
- updateLinkProperties(reason);//更新网络配置信息
- }
- private void updateLinkProperties(int reason) {
- LinkProperties newLp = makeLinkProperties();//根据DHCP的结果创建新的LinkProperties对象,用于对比DHCP前后的网络配置是否已经改变
- final boolean linkChanged = !newLp.equals(mLinkProperties);
- final boolean wasProvisioned = isProvisioned(mLinkProperties);
- final boolean isProvisioned = isProvisioned(newLp);
- // TODO: Teach LinkProperties how to understand static assignment
- // and simplify all this provisioning change detection logic by
- // unifying it under LinkProperties.compareProvisioning().
- final boolean lostProvisioning =
- (wasProvisioned && !isProvisioned) ||
- (mLinkProperties.hasIPv4Address() && !newLp.hasIPv4Address()) ||
- (mLinkProperties.isIPv6Provisioned() && !newLp.isIPv6Provisioned());
- final DetailedState detailedState = getNetworkDetailedState();
- if (linkChanged) { //网络配置信息改变
- if (DBG) {
- log("Link configuration changed for netId: " + mLastNetworkId
- + " old: " + mLinkProperties + " new: " + newLp);
- }
- mLinkProperties = newLp;//将新的配置信息保存到该字段中
- if (mIpReachabilityMonitor != null) {
- mIpReachabilityMonitor.updateLinkProperties(mLinkProperties);
- }
- if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties);//通过NetworkAgent对象通知ConnectifyService更新网络配置信息
- }
- if (lostProvisioning) {
- log("Lost IP layer provisioning!" +
- " was: " + mLinkProperties +
- " now: " + newLp);
- }
- // If we just configured or lost IP configuration, do the needful.
- // We don't just call handleSuccessfulIpConfiguration() or handleIpConfigurationLost()
- // here because those should only be called if we're attempting to connect or already
- // connected, whereas updateLinkProperties can be called at any time.
- switch (reason) {
- case DhcpStateMachine.DHCP_SUCCESS:
- case CMD_STATIC_IP_SUCCESS:
- // IPv4 provisioning succeded. Advance to connected state.
- sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL);
- if (!isProvisioned) {
- // Can never happen unless DHCP reports success but isProvisioned thinks the
- // resulting configuration is invalid (e.g., no IPv4 address, or the state in
- // mLinkProperties is out of sync with reality, or there's a bug in this code).
- // TODO: disconnect here instead. If our configuration is not usable, there's no
- // point in staying connected, and if mLinkProperties is out of sync with
- // reality, that will cause problems in the future.
- logd("IPv4 config succeeded, but not provisioned");
- }
- break;
- case DhcpStateMachine.DHCP_FAILURE:
- // DHCP failed. If we're not already provisioned, or we had IPv4 and now lost it,
- // give up and disconnect.
- // If we're already provisioned (e.g., IPv6-only network), stay connected.
- if (!isProvisioned || lostProvisioning) {
- sendMessage(CMD_IP_CONFIGURATION_LOST);
- } else {
- // DHCP failed, but we're provisioned (e.g., if we're on an IPv6-only network).
- sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL);
- // To be sure we don't get stuck with a non-working network if all we had is
- // IPv4, remove the IPv4 address from the interface (since we're using DHCP,
- // and DHCP failed). If we had an IPv4 address before, the deletion of the
- // address will cause a CMD_UPDATE_LINKPROPERTIES. If the IPv4 address was
- // necessary for provisioning, its deletion will cause us to disconnect.
- //
- // This shouldn't be needed, because on an IPv4-only network a DHCP failure will
- // have empty DhcpResults and thus empty LinkProperties, and isProvisioned will
- // not return true if we're using DHCP and don't have an IPv4 default route. So
- // for now it's only here for extra redundancy. However, it will increase
- // robustness if we move to getting IPv4 routes from netlink as well.
- loge("DHCP failure: provisioned, clearing IPv4 address.");
- if (!clearIPv4Address(mInterfaceName)) {
- sendMessage(CMD_IP_CONFIGURATION_LOST);
- }
- }
- break;
- case CMD_STATIC_IP_FAILURE:
- // Static configuration was invalid, or an error occurred in applying it. Give up.
- sendMessage(CMD_IP_CONFIGURATION_LOST);
- break;
- case CMD_UPDATE_LINKPROPERTIES:
- // IP addresses, DNS servers, etc. changed. Act accordingly.
- if (lostProvisioning) {
- // We no longer have a usable network configuration. Disconnect.
- sendMessage(CMD_IP_CONFIGURATION_LOST);
- } else if (!wasProvisioned && isProvisioned) {
- // We have a usable IPv6-only config. Advance to connected state.
- sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL);
- }
- if (linkChanged && getNetworkDetailedState() == DetailedState.CONNECTED) {
- // If anything has changed and we're already connected, send out a notification.
- sendLinkConfigurationChangedBroadcast();
- }
- break;
- }
- }
- case CMD_IP_CONFIGURATION_SUCCESSFUL:
- handleSuccessfulIpConfiguration();
- sendConnectedState();
- transitionTo(mConnectedState);
- private void handleSuccessfulIpConfiguration() {
- mLastSignalLevel = -1; // Force update of signal strength
- WifiConfiguration c = getCurrentWifiConfiguration();//获取代表当前连接的网络的WifiConfiguration对象
- if (c != null) {
- // Reset IP failure tracking
- c.numConnectionFailures = 0;
- //重置numConnectionFailures字段,因为在WifiConfigStore中,会根据numConnectionFailures字段判断当前网络的连接失败次数,默认失败10次时,会终止重连操作
- // Tell the framework whether the newly connected network is trusted or untrusted.
- updateCapabilities(c);
- }
- if (c != null) {
- ScanResult result = getCurrentScanResult();
- if (result == null) {
- logd("WifiStateMachine: handleSuccessfulIpConfiguration and no scan results" +
- c.configKey());
- } else {
- // Clear the per BSSID failure count
- result.numIpConfigFailures = 0;
- // Clear the WHOLE BSSID blacklist, which means supplicant is free to retry
- // any BSSID, even though it may already have a non zero ip failure count,
- // this will typically happen if the user walks away and come back to his arrea
- // TODO: implement blacklisting based on a timer, i.e. keep BSSID blacklisted
- // in supplicant for a couple of hours or a day
- mWifiConfigStore.clearBssidBlacklist();
- }
- }
- }
- /**
- * The link properties of the wifi interface.
- * Do not modify this directly; use updateLinkProperties instead.
- */
- private LinkProperties mLinkProperties; //保存当前网络连接的配置信息,包括IP地址集、DNS地址集、路由地址集等
- // NOTE: Do not return to clients - use #getWiFiInfoForUid(int)
- private WifiInfo mWifiInfo;//描述了一个Wifi连接的状态,通过该对象我们可以得知当前Wifi连接的SSID、netId、IP地址、Mac地址等信息
- private NetworkInfo mNetworkInfo;//表示一个网络接口(wlan0/eth0)的连接状态,通过该对象可以得知当前Wifi连接处于哪一步、是否连接等状态
PS:
4.4之后Android加入了AP评分机制。这个机制根据某个AP的很多配置信息一通处理,最后得出一个score,来表明某个AP的可连接性。它评判的属性有点多,后面在研究,现在本渣还是没有搞明白,囧.... 在framework里面,其实屏蔽了很多复杂的操作,比如WifiNative里面的大多数方法都是要通过JNI调用wifi.c,再调到wpa_s。这些中间过程其实比framework的处理要复杂的多,代码也更晦涩。例如runDhcp()动作,有个专门的dhcpcd守护进程进行处理;它的实现跟wpa_s一样,都是很复杂的。即使了解DHCP协议的工作流程,要看懂它的代码实现也很痛苦。Android里还有的PPPoE拨号方式,它的守护进程pppd的实现也很复杂......;要做这方面的定制,对于偏向framework的人来说,是比较痛苦的。
更多相关文章
- Android下载网络图片到本地
- Android中有关Handler的使用(二)
- android grantRuntimePermission 详解
- android grantRuntimePermission 详解
- Android中Handler引起的内存泄露
- Android中有关Handler的使用(二)
- android 通过php 连接 mysql
- Android下使用Socket连接网络电脑
- AbstractProcessor注解处理器