Android -- Wifi的save()操作
来源:互联网 发布:网络直播受众群体 编辑:程序博客网 时间:2024/05/17 04:09
Android -- Wifi的save()操作
当我们在Settings中设置静态IP连接时,会调用到WifiManager::save()函数:
/** * Save the given network in the supplicant config. If the network already * exists, the configuration is updated. A new network is enabled * by default. * * For a new network, this function is used instead of a * sequence of addNetwork(), enableNetwork() and saveConfiguration(). * * For an existing network, it accomplishes the task of updateNetwork() * and saveConfiguration() * * @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 save(WifiConfiguration config, ActionListener listener) { if (config == null) throw new IllegalArgumentException("config cannot be null"); validateChannel(); sAsyncChannel.sendMessage(SAVE_NETWORK, 0, putListener(listener), config); }有注释可知,save函数会把传入WifiConfiguration信息代表的网络保存进wpa_supplicant.conf文件中;如果网络是已经存在的,则会更新信息;如果是新添加的,则会重新添加到配置文件中。
WifiServiceImpl::ClientHandler处理该消息:
/* 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; }主要做消息转发处理,看WifiStateMachine中的处理流程。ConnectModeState状态处理该消息:
case WifiManager.SAVE_NETWORK: mWifiConnectionStatistics.numWifiManagerJoinAttempt++; // Fall thru case WifiStateMachine.CMD_AUTO_SAVE_NETWORK: lastSavedConfigurationAttempt = null; // Used for debug config = (WifiConfiguration) message.obj; if (config == null) { loge("ERROR: SAVE_NETWORK with null configuration" + mSupplicantStateTracker.getSupplicantStateName() + " my state " + getCurrentState().getName()); messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR); break; } lastSavedConfigurationAttempt = new WifiConfiguration(config); int nid = config.networkId; logd("SAVE_NETWORK id=" + Integer.toString(nid) + " config=" + config.SSID + " nid=" + config.networkId + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() + " my state " + getCurrentState().getName()); // Only record the uid if this is user initiated boolean checkUid = (message.what == WifiManager.SAVE_NETWORK); if (checkUid && !recordUidIfAuthorized(config, message.sendingUid, /* onlyAnnotate */ false)) { logw("Not authorized to update network " + " config=" + config.SSID + " cnid=" + config.networkId + " uid=" + message.sendingUid); replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.NOT_AUTHORIZED); break; } result = mWifiConfigStore.saveNetwork(config, WifiConfiguration.UNKNOWN_UID); if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { if (mWifiInfo.getNetworkId() == result.getNetworkId()) { if (result.hasIpChanged()) { // The currently connection configuration was changed // We switched from DHCP to static or from static to DHCP, or the // static IP address has changed. log("Reconfiguring IP on connection"); // TODO: clear addresses and disable IPv6 // to simplify obtainingIpState. transitionTo(mObtainingIpState); } if (result.hasProxyChanged()) { log("Reconfiguring proxy on connection"); updateLinkProperties(CMD_UPDATE_LINKPROPERTIES); } } replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config); if (VDBG) { logd("Success save network nid=" + Integer.toString(result.getNetworkId())); } synchronized(mScanResultCache) { /** * If the command comes from WifiManager, then * tell autojoin the user did try to modify and save that network, * and interpret the SAVE_NETWORK as a request to connect */ boolean user = message.what == WifiManager.SAVE_NETWORK; // Did this connect come from settings boolean persistConnect = mWifiConfigStore.checkConfigOverridePermission(message.sendingUid); if (user) { mWifiConfigStore.updateLastConnectUid(config, message.sendingUid); mWifiConfigStore.writeKnownNetworkHistory(false); } mWifiAutoJoinController.updateConfigurationHistory(result.getNetworkId() , user, persistConnect); mWifiAutoJoinController.attemptAutoJoin(); } } else { loge("Failed to save network"); messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR); } break;如果检测出IP配置信息有变化,则会切换到ObtainingIpState状态,并触发autojoin流程。如果用户使用的是静态IP,看ObtainingIpState的enter()函数:
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); } } }看else分支,在设置静态IP之前,调用stopDhcp()停掉当前的dhcp流程,获取到上层传入的静态IP配置信息:
- 如果config为null,则认为静态配置失败
- 调用mNwService.setInterfaceConfig(),设置配置的IP地址信息
- 组装DhcpResults对象,并发送CMD_STATIC_IP_SUCCESS消息,更新网络状态
CMD_STATIC_IP_SUCCESS在ObtainingIpState被处理:
case CMD_STATIC_IP_SUCCESS: handleIPv4Success((DhcpResults) message.obj, CMD_STATIC_IP_SUCCESS); 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; 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); }将当前静态IP设置的DhcpResults赋给状态机的成员变量mDchpResults,最后调用updateLinkProperties()更新连接配置信息:
// 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;跟踪CMD_IP_CONFIGURATION_SUCCESSFUL消息。ObtainingIpState不处理该消息,其父状态L2ConnectedState处理:
case CMD_IP_CONFIGURATION_SUCCESSFUL: handleSuccessfulIpConfiguration(); sendConnectedState(); transitionTo(mConnectedState); break;静态IP配置成功后,调用handleSuccessfulIpConfiguration()做之后的一些准备工作;调用sendConnectedState(),发送WifiManager.NETWORK_STATE_CHANGED_ACTION广播,通知其他组件网络连接状态的变化(此处是CONNECTED)。最后将Wifi状态机切换到ConnectedSate,代表网络已经连接完成。
0 0
- Android -- Wifi的save()操作
- Android -- Wifi的save()操作
- Android的WiFi操作
- android的wifi操作
- android中Wifi的操作
- Android开发--Wifi的操作
- Android -- Wifi的forget()操作
- Android -- Wifi的forget()操作
- Android WIFI功能开发<2>对WIfi的操作
- Android重的wifi的操作
- android连接wifi热点的操作
- Android之对Wifi的操作
- Android WIFI网络操作
- android WIFI网络操作
- android:WIFI网络操作
- android wifi 操作
- Android WIFI基本操作
- android 对WIFI 操作
- javascript高级程序设计读书笔记--BOM
- HDU1362Surround the Trees 最小凸多边形覆盖
- Codeforces 25C
- 华为上机题汇总(九)
- JS Cookie封装
- Android -- Wifi的save()操作
- 设置Launch Image 启动图片
- 冒泡排序算法
- 闪屏制作
- html5 常用 标签
- socket is closed异常的原因及其解决方法
- Java JDK Reflect
- RAID5/RAID0及LV制作
- poj 2975 NIM