Android 12 WiFi连接过程
我们从setting 入口开始分析该过程;
1.setting界面
packages\apps\Settings\src\com\android\settings\wifi\WifiSettings.java 创建Dialog2
@Override public Dialog onCreateDialog(int dialogId) { switch (dialogId) { case WIFI_DIALOG_ID: // modify network mDialog = WifiDialog2 .createModal(getActivity(), this, mDialogWifiEntry, mDialogMode); return mDialog; default: return super.onCreateDialog(dialogId); } }
2.packages\apps\Settings\src\com\android\settings\wifi\WifiDialog2.java
点击事件
private static final int BUTTON_SUBMIT = DialogInterface.BUTTON_POSITIVE; private static final int BUTTON_FORGET = DialogInterface.BUTTON_NEUTRAL;
@Override public void onClick(DialogInterface dialogInterface, int id) { if (mListener != null) { switch (id) { case BUTTON_SUBMIT: mListener.onSubmit(this); break; case BUTTON_FORGET: if (WifiUtils.isNetworkLockedDown(getContext(), mWifiEntry.getWifiConfiguration())) { RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(), RestrictedLockUtilsInternal.getDeviceOwner(getContext())); return; } mListener.onForget(this); break; } } }
private final WifiDialog2Listener mListener;
WifiDialog2Listener 在WifiSettings里实现
@Override public void onSubmit(WifiDialog2 dialog) { final int dialogMode = dialog.getMode(); final WifiConfiguration config = dialog.getController().getConfig(); final WifiEntry wifiEntry = dialog.getWifiEntry(); if (dialogMode == WifiConfigUiBase2.MODE_MODIFY) { if (config == null) { Toast.makeText(getContext(), R.string.wifi_failed_save_message, Toast.LENGTH_SHORT).show(); } else { mWifiManager.save(config, mSaveListener); } } else if (dialogMode == WifiConfigUiBase2.MODE_CONNECT || (dialogMode == WifiConfigUiBase2.MODE_VIEW && wifiEntry.canConnect())) { if (config == null) { connect(wifiEntry, false /* editIfNoConfig */, false /* fullScreenEdit*/); } else { mWifiManager.connect(config, new WifiConnectActionListener()); } } }
调用 WifiManager.connect方法进行连接
packages\modules\Wifi\framework\java\android\net\wifi\WifiManager.java
public void connect(int networkId, @Nullable ActionListener listener) { if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative"); connectInternal(null, networkId, listener); }
private void connectInternal(@Nullable WifiConfiguration config, int networkId, @Nullable ActionListener listener) { ActionListenerProxy listenerProxy = null; if (listener != null) { listenerProxy = new ActionListenerProxy("connect", mLooper, listener); } try { mService.connect(config, networkId, listenerProxy); } catch (RemoteException e) { if (listenerProxy != null) listenerProxy.onFailure(ERROR); } catch (SecurityException e) { if (listenerProxy != null) listenerProxy.onFailure(NOT_AUTHORIZED); } }
mService是IWifiManager 类型的变量,由BaseWifiService实现
packages\modules\Wifi\service\java\com\android\server\wifi\BaseWifiService.java
public class BaseWifiService extends IWifiManager.Stub {
BaseWifiService是抽象类 具体实现逻辑在WifiServiceImpl
packages\modules\Wifi\service\java\com\android\server\wifi\WifiServiceImpl.java
/** * Connects to a network. * * If the supplied config is not null, then the netId argument will be ignored and the config * will be saved (or updated if its networkId or profile key already exist) and connected to. * * If the supplied config is null, then the netId argument will be matched to a saved config to * be connected to. * * @param config New or existing config to add/update and connect to * @param netId Network ID of existing config to connect to if the supplied config is null * @param callback Listener to notify action result * * see: {@link WifiManager#connect(WifiConfiguration, WifiManager.ActionListener)} * {@link WifiManager#connect(int, WifiManager.ActionListener)} */ @Override public void connect(WifiConfiguration config, int netId, @Nullable IActionListener callback) { int uid = Binder.getCallingUid(); if (!isPrivileged(Binder.getCallingPid(), uid)) { throw new SecurityException(TAG + ": Permission denied"); } if (config != null) { config.networkId = removeSecurityTypeFromNetworkId(config.networkId); } final int netIdArg = removeSecurityTypeFromNetworkId(netId); mLog.info("connect uid=%").c(uid).flush(); mWifiThreadRunner.post(() -> { ActionListenerWrapper wrapper = new ActionListenerWrapper(callback); final NetworkUpdateResult result; // if connecting using WifiConfiguration, save the network first if (config != null) { if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) { mWifiMetrics.logUserActionEvent( UserActionEvent.EVENT_ADD_OR_UPDATE_NETWORK, config.networkId); } result = mWifiConfigManager.addOrUpdateNetwork(config, uid); if (!result.isSuccess()) { Log.e(TAG, "connect adding/updating config=" + config + " failed"); wrapper.sendFailure(WifiManager.ERROR); return; } broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config); } else { if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) { mWifiMetrics.logUserActionEvent( UserActionEvent.EVENT_MANUAL_CONNECT, netIdArg); } result = new NetworkUpdateResult(netIdArg); } WifiConfiguration configuration = mWifiConfigManager .getConfiguredNetwork(result.getNetworkId()); if (configuration == null) { Log.e(TAG, "connect to Invalid network Id=" + netIdArg); wrapper.sendFailure(WifiManager.ERROR); return; } if (configuration.enterpriseConfig != null && configuration.enterpriseConfig.isAuthenticationSimBased()) { int subId = mWifiCarrierInfoManager.getBestMatchSubscriptionId(configuration); if (!mWifiCarrierInfoManager.isSimReady(subId)) { Log.e(TAG, "connect to SIM-based config=" + configuration + "while SIM is absent"); wrapper.sendFailure(WifiManager.ERROR); return; } if (mWifiCarrierInfoManager.requiresImsiEncryption(subId) && !mWifiCarrierInfoManager.isImsiEncryptionInfoAvailable(subId)) { Log.e(TAG, "Imsi protection required but not available for Network=" + configuration); wrapper.sendFailure(WifiManager.ERROR); return; } } mMakeBeforeBreakManager.stopAllSecondaryTransientClientModeManagers(() -> mConnectHelper.connectToNetwork(result, wrapper, uid)); }); }
调用ConnectHelper的connectToNetwork方法 packages\modules\Wifi\service\java\com\android\server\wifi\ConnectHelper.java
/** * Trigger connection to an existing network and provide status via the provided callback. * This uses the primary client mode manager for making the connection. */ public void connectToNetwork( @NonNull NetworkUpdateResult result, @NonNull ActionListenerWrapper wrapper, int callingUid) { connectToNetwork( mActiveModeWarden.getPrimaryClientModeManager(), result, wrapper, callingUid); } /** * Trigger connection to an existing network and provide status via the provided callback. * This uses the provided client mode manager for making the connection. */ public void connectToNetwork( @NonNull ClientModeManager clientModeManager, @NonNull NetworkUpdateResult result, @NonNull ActionListenerWrapper wrapper, int callingUid) { int netId = result.getNetworkId(); if (mWifiConfigManager.getConfiguredNetwork(netId) == null) { Log.e(TAG, "connectToNetwork Invalid network Id=" + netId); wrapper.sendFailure(WifiManager.ERROR); return; } mWifiConfigManager.updateBeforeConnect(netId, callingUid); clientModeManager.connectNetwork(result, wrapper, callingUid); }
掉用 clientModeManager.connectNetwork(result, wrapper, callingUid);
clientModeManager packages\modules\Wifi\service\java\com\android\server\wifi\ClientModeManager.java 是接口类 具体实现是在
connectToNetwork(
mActiveModeWarden.getPrimaryClientModeManager(), result, wrapper, callingUid);
packages\modules\Wifi\service\java\com\android\server\wifi\ActiveModeWarden.java
@NonNull public ClientModeManager getPrimaryClientModeManager() { ClientModeManager cm = getPrimaryClientModeManagerNullable(); if (cm != null) return cm; // If there is no primary client manager, return the default one. return mDefaultClientModeManager; }
@Nullable public ConcreteClientModeManager getPrimaryClientModeManagerNullable() { return getClientModeManagerInRole(ROLE_CLIENT_PRIMARY); }
/** Get any client mode manager in the given role, or null if none was found. */ @Nullable public ConcreteClientModeManager getClientModeManagerInRole(ClientRole role) { for (ConcreteClientModeManager manager : mClientModeManagers) { if (manager.getRole() == role) return manager; } return null; }
所以最后调用的是ConcreteClientModeManager 的connectNetwork方法
packages\modules\Wifi\service\java\com\android\server\wifi\ConcreteClientModeManager.java
@Override public void connectNetwork(NetworkUpdateResult result, ActionListenerWrapper wrapper, int callingUid) { getClientMode().connectNetwork(result, wrapper, callingUid); }
@NonNull private ClientMode getClientMode() { if (mClientModeImpl != null) { return mClientModeImpl; } if (mScanOnlyModeImpl != null) { return mScanOnlyModeImpl; } return mDefaultClientModeManager; }
packages\modules\Wifi\service\java\com\android\server\wifi\ClientModeImpl.java
/** Trigger network connection and provide status via the provided callback. */ public void connectNetwork(NetworkUpdateResult result, ActionListenerWrapper wrapper, int callingUid) { Message message = obtainMessage(CMD_CONNECT_NETWORK, new ConnectNetworkMessage(result, wrapper)); message.sendingUid = callingUid; sendMessage(message); }
发送CMD_CONNECT_NETWORK消息
case CMD_CONNECT_NETWORK: { ConnectNetworkMessage cnm = (ConnectNetworkMessage) message.obj; if (mIpClient == null) { logd("IpClient is not ready, CONNECT_NETWORK dropped"); cnm.listener.sendFailure(WifiManager.ERROR); break; } NetworkUpdateResult result = cnm.result; int netId = result.getNetworkId(); connectToUserSelectNetwork( netId, message.sendingUid, result.hasCredentialChanged()); mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_CONNECT_NETWORK, mWifiConfigManager.getConfiguredNetwork(netId)); cnm.listener.sendSuccess(); break; }
private void connectToUserSelectNetwork(int netId, int uid, boolean forceReconnect) { logd("connectToUserSelectNetwork netId " + netId + ", uid " + uid + ", forceReconnect = " + forceReconnect); if (!forceReconnect && (mLastNetworkId == netId || mTargetNetworkId == netId)) { // We're already connecting/connected to the user specified network, don't trigger a // reconnection unless it was forced. logi("connectToUserSelectNetwork already connecting/connected=" + netId); } else { mWifiConnectivityManager.prepareForForcedConnection(netId); if (uid == Process.SYSTEM_UID) { mWifiMetrics.setNominatorForNetwork(netId, WifiMetricsProto.ConnectionEvent.NOMINATOR_MANUAL); } startConnectToNetwork(netId, uid, SUPPLICANT_BSSID_ANY); } }
/** * Automatically connect to the network specified * * @param networkId ID of the network to connect to * @param uid UID of the app triggering the connection. * @param bssid BSSID of the network */ public void startConnectToNetwork(int networkId, int uid, String bssid) { sendMessage(CMD_START_CONNECT, networkId, uid, bssid); }
case CMD_START_CONNECT: { if (mIpClient == null) { logd("IpClient is not ready, START_CONNECT dropped"); break; } /* connect command coming from auto-join */ int netId = message.arg1; int uid = message.arg2; String bssid = (String) message.obj; mSentHLPs = false; // Stop lingering (if it was lingering before) if we start a new connection. // This means that the ClientModeManager was reused for another purpose, so it // should no longer be in lingering mode. mClientModeManager.setShouldReduceNetworkScore(false); if (!hasConnectionRequests()) { if (mNetworkAgent == null) { loge("CMD_START_CONNECT but no requests and not connected," + " bailing"); //break; } else if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) { loge("CMD_START_CONNECT but no requests and connected, but app " + "does not have sufficient permissions, bailing"); break; } } WifiConfiguration config = mWifiConfigManager.getConfiguredNetworkWithoutMasking(netId); logd("CMD_START_CONNECT " + " my state " + getCurrentState().getName() + " nid=" + netId + " roam=" + mIsAutoRoaming); if (config == null) { loge("CMD_START_CONNECT and no config, bail out..."); break; } mTargetNetworkId = netId; // Update scorecard while there is still state from existing connection mLastScanRssi = mWifiConfigManager.findScanRssi(netId, mWifiHealthMonitor.getScanRssiValidTimeMs()); mWifiScoreCard.noteConnectionAttempt(mWifiInfo, mLastScanRssi, config.SSID); mWifiBlocklistMonitor.setAllowlistSsids(config.SSID, Collections.emptyList()); mWifiBlocklistMonitor.updateFirmwareRoamingConfiguration(Set.of(config.SSID)); updateWifiConfigOnStartConnection(config, bssid); reportConnectionAttemptStart(config, mTargetBssid, WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED); String currentMacAddress = mWifiNative.getMacAddress(mInterfaceName); mWifiInfo.setMacAddress(currentMacAddress); Log.i(getTag(), "Connecting with " + currentMacAddress + " as the mac address"); mTargetWifiConfiguration = config; mNetworkNotFoundEventCount = 0; /* Check for FILS configuration again after updating the config */ if (config.isFilsSha256Enabled() || config.isFilsSha384Enabled()) { boolean isIpClientStarted = startIpClient(config, true); if (isIpClientStarted) { mIpClientWithPreConnection = true; break; } } connectToNetwork(config); break; }
private void connectToNetwork(WifiConfiguration config) { if ((config != null) && mWifiNative.connectToNetwork(mInterfaceName, config)) { mWifiLastResortWatchdog.noteStartConnectTime(config.networkId); mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_CMD_START_CONNECT, config); mIsAutoRoaming = false; transitionTo(mL2ConnectingState); } else { loge("CMD_START_CONNECT Failed to start connection to network " + config); mTargetWifiConfiguration = null; stopIpClient(); reportConnectionAttemptEnd( WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED, WifiMetricsProto.ConnectionEvent.HLF_NONE, WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN); } }
packages\modules\Wifi\service\java\com\android\server\wifi\WifiNative.java
public boolean connectToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) { // Abort ongoing scan before connect() to unblock connection request. mWifiCondManager.abortScan(ifaceName); return mSupplicantStaIfaceHal.connectToNetwork(ifaceName, configuration); }
packages\modules\Wifi\service\java\com\android\server\wifi\SupplicantStaIfaceHal.java
/** * Add the provided network configuration to wpa_supplicant and initiate connection to it. * This method does the following: * 1. If |config| is different to the current supplicant network, removes all supplicant * networks and saves |config|. * 2. Select the new network in wpa_supplicant. * * @param ifaceName Name of the interface. * @param config WifiConfiguration parameters for the provided network. * @return {@code true} if it succeeds, {@code false} otherwise */ public boolean connectToNetwork(@NonNull String ifaceName, @NonNull WifiConfiguration config) { synchronized (mLock) { logd("connectToNetwork " + config.getProfileKey()); WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName); if (WifiConfigurationUtil.isSameNetwork(config, currentConfig)) { String networkSelectionBSSID = config.getNetworkSelectionStatus() .getNetworkSelectionBSSID(); String networkSelectionBSSIDCurrent = currentConfig.getNetworkSelectionStatus().getNetworkSelectionBSSID(); if (Objects.equals(networkSelectionBSSID, networkSelectionBSSIDCurrent)) { logd("Network is already saved, will not trigger remove and add operation."); } else { logd("Network is already saved, but need to update BSSID."); if (!setCurrentNetworkBssid( ifaceName, config.getNetworkSelectionStatus().getNetworkSelectionBSSID())) { loge("Failed to set current network BSSID."); return false; } mCurrentNetworkLocalConfigs.put(ifaceName, new WifiConfiguration(config)); } } else { mCurrentNetworkRemoteHandles.remove(ifaceName); mCurrentNetworkLocalConfigs.remove(ifaceName); mLinkedNetworkLocalAndRemoteConfigs.remove(ifaceName); if (!removeAllNetworks(ifaceName)) { loge("Failed to remove existing networks"); return false; } Pair<SupplicantStaNetworkHal, WifiConfiguration> pair = addNetworkAndSaveConfig(ifaceName, config); if (pair == null) { loge("Failed to add/save network configuration: " + config .getProfileKey()); return false; } mCurrentNetworkRemoteHandles.put(ifaceName, pair.first); mCurrentNetworkLocalConfigs.put(ifaceName, pair.second); } SupplicantStaNetworkHal networkHandle = checkSupplicantStaNetworkAndLogFailure(ifaceName, "connectToNetwork"); if (networkHandle == null) { loge("No valid remote network handle for network configuration: " + config.getProfileKey()); return false; } PmkCacheStoreData pmkData = mPmkCacheEntries.get(config.networkId); if (pmkData != null && !WifiConfigurationUtil.isConfigForPskNetwork(config) && pmkData.expirationTimeInSec > mClock.getElapsedSinceBootMillis() / 1000) { logi("Set PMK cache for config id " + config.networkId); if (networkHandle.setPmkCache(pmkData.data)) { mWifiMetrics.setConnectionPmkCache(ifaceName, true); } } if (!networkHandle.select()) { loge("Failed to select network configuration: " + config.getProfileKey()); return false; } return true; } }
packages\modules\Wifi\service\java\com\android\server\wifi\SupplicantStaNetworkHal.java
/** * Trigger a connection to this network. * * @return true if it succeeds, false otherwise. */ public boolean select() { synchronized (mLock) { final String methodStr = "select"; if (!checkISupplicantStaNetworkAndLogFailure(methodStr)) return false; try { SupplicantStatus status = mISupplicantStaNetwork.select(); return checkStatusAndLogFailure(status, methodStr); } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } } }
调用到hal层
hardware\interfaces\wifi\supplicant\1.0\ISupplicantStaNetwork.hal
/** * Initiate connection to this network. * * @return status Status of the operation. * Possible status codes: * |SupplicantStatusCode.SUCCESS|, * |SupplicantStatusCode.FAILURE_UNKNOWN|, * |SupplicantStatusCode.FAILURE_NETWORK_INVALID| */ select() generates (SupplicantStatus status);
接下来会进入到 external\wpa_supplicant_8\wpa_supplicant\hidl\1.4\sta_iface.cpp
SupplicantStatus StaNetwork::selectInternal() { struct wpa_ssid *wpa_ssid = retrieveNetworkPtr(); if (wpa_ssid->disabled == 2) { return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; } struct wpa_supplicant *wpa_s = retrieveIfacePtr(); wpa_s->scan_min_time.sec = 0; wpa_s->scan_min_time.usec = 0; wpa_supplicant_select_network(wpa_s, wpa_ssid); return {SupplicantStatusCode::SUCCESS, ""}; }
external\wpa_supplicant_8\wpa_supplicant\wpa_supplicant.c
/** * wpa_supplicant_select_network - Attempt association with a network * @wpa_s: wpa_supplicant structure for a network interface * @ssid: wpa_ssid structure for a configured network or %NULL for any network */ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { struct wpa_ssid *other_ssid; int disconnected = 0; if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) { if (wpa_s->wpa_state >= WPA_AUTHENTICATING) wpa_s->own_disconnect_req = 1; wpa_supplicant_deauthenticate( wpa_s, WLAN_REASON_DEAUTH_LEAVING); disconnected = 1; } if (ssid) wpas_clear_temp_disabled(wpa_s, ssid, 1); /* * Mark all other networks disabled or mark all networks enabled if no * network specified. */ for (other_ssid = wpa_s->conf->ssid; other_ssid; other_ssid = other_ssid->next) { int was_disabled = other_ssid->disabled; if (was_disabled == 2) continue; /* do not change persistent P2P group data */ other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0; if (was_disabled && !other_ssid->disabled) wpas_clear_temp_disabled(wpa_s, other_ssid, 0); if (was_disabled != other_ssid->disabled) wpas_notify_network_enabled_changed(wpa_s, other_ssid); } if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid && wpa_s->wpa_state >= WPA_AUTHENTICATING) { /* We are already associated with the selected network */ wpa_printf(MSG_DEBUG, "Already associated with the " "selected network - do nothing"); return; } if (ssid) { wpa_s->current_ssid = ssid; eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); wpa_s->connect_without_scan = (ssid->mode == WPAS_MODE_MESH) ? ssid : NULL; /* * Don't optimize next scan freqs since a new ESS has been * selected. */ os_free(wpa_s->next_scan_freqs); wpa_s->next_scan_freqs = NULL; } else { wpa_s->connect_without_scan = NULL; } wpa_s->disconnected = 0; wpa_s->reassociate = 1; wpa_s_clear_sae_rejected(wpa_s); wpa_s->last_owe_group = 0; if (ssid) { ssid->owe_transition_bss_select_count = 0; wpa_s_setup_sae_pt(wpa_s->conf, ssid); } if (wpa_s->connect_without_scan || wpa_supplicant_fast_associate(wpa_s) != 1) { wpa_s->scan_req = NORMAL_SCAN_REQ; wpas_scan_reset_sched_scan(wpa_s); wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0); } if (ssid) wpas_notify_network_selected(wpa_s, ssid); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效