本文共 6921 字,大约阅读时间需要 23 分钟。
wpa_supplicant是开源项目源码,被谷歌修改后加入android移动平台,它主要是用来支持WEP,WPA/WPA2和WAPI无线协议和加密认证的,而实际上是通过socket与驱动交互以及上报数据给用户(不管是wpa_supplicant与上层还是wpa_supplicant与驱动都采用socket通讯). 用户可以通过socket发送命令给wpa_supplicant调动驱动来对WiFi芯片操作。简单的说,wpa_supplicant就是WiFi驱动和用户的中转站,另外对协议和加密认证的支持。 从framework到wpa_supplicant的适配层(wifi.c),其中framework部分需要注意的是wifiService和wifiMoniter两部分,这两块一个是转发AP的CMD,另一个是接收来自wpa_supplicant的CMD。他们与本地库的连接都是通过JNI方法,具体实现方法在android_net_wifi_Wifi.cpp中。
android_net_wifi_Wifi.cpp中可以看出AP给wpa_supplicant发送的命令。这些命令通过wifi.c的wifi_command发送给wpa_supplicant,发送命令调用wpa_ctrl_request来完成,wpa_ctrl_request是通过socket的方式与wpa_supplicant进行通信的,然后通过wpa_ctrl_recv来接收来自wpa_supplicant的命令,并返回标识给wifi_wait_for_event。
WifiStateTracker会创建WifiMonitor接收来自底层的事件,WifiService和WifiMonitor是整个模块的核心。 WifiService负责启动关闭 wpa_supplicant、启动关闭 WifiMonitor监视线程和把命令下发给wpa_supplicant。 WifiMonitor则负责从wpa_supplicant接收事件通知。 连接 AP 1.使能 WIFI WirelessSettings在初始化的时候配置了由WifiEnabler来处理 Wifi按钮, private void initToggles() { mWifiEnabler = new WifiEnabler( this,(WifiManager) getSystemService(WIFI_SERVICE), (CheckBoxPreference) findPreference(KEY_TOGGLE_WIFI)); 当用户按下Wifi按钮后,Android会调用 WifiEnabler的onPreferenceChange,再由 WifiEnabler调用 WifiManager的setWifiEnabled接口函数,通过 AIDL,实际调用的是 WifiService的setWifiEnabled函数,WifiService接着向自身发送一条 MESSAGE_ENABLE_WIFI消息,在处理该消息的代码中做真正的使能工作:
首先装载 WIFI内核模块(该模块的位置硬编码为"/system/lib/modules/wlan.ko" ), 然后启动wpa_supplicant (配置文件硬编码为"/data/misc/wifi/wpa_supplicant.conf") 再通过 WifiStateTracker来启动WifiMonitor中的监视线程。 private boolean setWifiEnabledBlocking(boolean enable) { final int eventualWifiState = enable ?WIFI_STATE_ENABLED :WIFI_STATE_DISABLED; updateWifiState(enable ? WIFI_STATE_ENABLING:WIFI_STATE_DISABLING); if (enable) { if (!WifiNative.loadDriver()) { Log.e(TAG, "Failed to load Wi-Fidriver."); updateWifiState(WIFI_STATE_UNKNOWN); return false; } if (!WifiNative.startSupplicant()) { WifiNative.unloadDriver(); Log.e(TAG, "Failed to start supplicantdaemon."); updateWifiState(WIFI_STATE_UNKNOWN); return false; } mWifiStateTracker.startEventLoop(); } // Success! persistWifiEnabled(enable); updateWifiState(eventualWifiState); return true; } 当使能成功后,会广播发送 WIFI_STATE_CHANGED_ACTION 这个Intent通知外界WIFI已经成功使能了。WifiEnabler创建的时候就会向Android注册接收WIFI_STATE_CHANGED_ACTION,因此它会收到该 Intent,从而开始扫描。 private void handleWifiStateChanged(intwifiState) { if (wifiState == WIFI_STATE_ENABLED) { loadConfiguredAccessPoints(); attemptScan(); }
2.查找 AP 扫描的入口函数是 WifiService的 startScan,它其实也就是往 wpa_supplicant发送 SCAN命令。 static jbooleanandroid_net_wifi_scanCommand(JNIEnv* env, jobjectclazz) { jboolean result; // Ignore any error from setting the scanmode. // The scan will still work. (void)doBooleanCommand("DRIVERSCAN-ACTIVE", "OK"); result = doBooleanCommand("SCAN", "OK"); (void)doBooleanCommand("DRIVERSCAN-PASSIVE", "OK"); return result; }
当wpa_supplicant处理完SCAN命令后,它会向控制通道发送事件通知扫描完成,从而wifi_wait_for_event函数会接收到该事件,由此 WifiMonitor 中的MonitorThread会被执行来出来这个事件, void handleEvent(int event, Stringremainder) {
case SCAN_RESULTS:
mWifiStateTracker.notifyScanResultsAvailable();
break;
WifiStateTracker则接着广播发送 SCAN_RESULTS_AVAILABLE_ACTION这个Intent
case EVENT_SCAN_RESULTS_AVAILABLE:
mContext.sendBroadcast(new
Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
WifiLayer注册了接收 SCAN_RESULTS_AVAILABLE_ACTION这个Intent,所以它的相关处理函数handleScanResultsAvailable会被调用,在该函数中,先会去拿到 SCAN 的结果(最终是往 wpa_supplicant发送 SCAN_RESULT命令并读取返回值来实现的),
List<ScanResult> list=mWifiManager.getScanResults();
对每一个扫描返回的AP,WifiLayer会调用 WifiSettings的onAccessPointSetChanged函数,从而最终把该 AP加到 GUI显示列表中。
public voidonAccessPointSetChanged(AccessPointState ap, booleanadded) { AccessPointPreference pref = mAps.get(ap); if (added) { if (pref == null) { pref = new AccessPointPreference(this, ap); mAps.put(ap, pref); } else { pref.setEnabled(true); } mApCategory.addPreference(pref); } } 3.配置 AP参数 当用户在WifiSettings界面上选择了一个AP后,会显示配置 AP参数的一个对话框, public boolean onPreferenceTreeClick(PreferenceScreenpreferenceScreen,Preference preference) { if (preference instanceofAccessPointPreference) { AccessPointState state =((AccessPointPreference) preference).getAccessPointState(); showAccessPointDialog(state,AccessPointDialog.MODE_INFO); } } 4.连接 当用户在AcessPointDialog中选择好加密方式和输入密钥之后,再点击连接按钮,Android就会去连接这个AP。 private void handleConnect() { String password = getEnteredPassword(); if (!TextUtils.isEmpty(password)) { mState.setPassword(password); } mWifiLayer.connectToNetwork(mState); } WifiLayer会先检测这个AP是不是之前被配置过,这个是通过向 wpa_supplicant 发送LIST_NETWORK命令并且比较返回值来实现的, // Need WifiConfiguration for the AP WifiConfiguration config =findConfiguredNetwork(state); 如果wpa_supplicant没有这个AP的配置信息,则会向wpa_supplicant发送 ADD_NETWORK命令来添加该AP, if (config == null) { // Connecting for the first time, need to create it config =addConfiguration(state,ADD_CONFIGURATION_ENABLE|ADD_CONFIGURATION_SAVE); } ADD_NETWORK命令会返回一个 ID , WifiLayer再用这个返回的 ID作为参数向wpa_supplicant发送ENABLE_NETWORK命令,从而让 wpa_supplicant 去连接该AP。 // Make sure that network is enabled, anddisable others mReenableApsOnNetworkStateChange = true; if(!mWifiManager.enableNetwork(state.networkId, true)) { Log.e(TAG, "Could not enable networkID " + state.networkId); error(R.string.error_connecting); return false; } 5.配置 IP地址 当wpa_supplicant成功连接上AP之后,它会向控制通道发送事件通知连接上AP了,从而wifi_wait_for_event函数会接收到该事件,由此 WifiMonitor 中的 MonitorThread会被执行来出来这个事件, void handleEvent(int event, Stringremainder) { case CONNECTED: handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED,remainder); break; WifiMonitor再调用WifiStateTracker的notifyStateChange,WifiStateTracker则接着会往自身发送EVENT_DHCP_START消息来启动DHCP去获取 IP地址。 private void handleConnectedState() { setPollTimer(); mLastSignalLevel = -1; if (!mHaveIPAddress&&!mObtainingIPAddress) { mObtainingIPAddress = true; mDhcpTarget.obtainMessage(EVENT_DHCP_START).sendToTarget(); } } 然后再广播发送NETWORK_STATE_CHANGED_ACTION这个Intent case EVENT_NETWORK_STATE_CHANGED: if (result.state != DetailedState.DISCONNECTED ||!mDisconnectPending) { intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); intent.putExtra(WifiManager.EXTRA_NETWORK_INFO,mNetworkInfo); if (result.BSSID != null) intent.putExtra(WifiManager.EXTRA_BSSID,result.BSSID); mContext.sendStickyBroadcast(intent); } break; WifiLayer注册了接收 NETWORK_STATE_CHANGED_ACTION这个 Intent,所以它的相关处理函数handleNetworkStateChanged会被调用,
当DHCP拿到IP地址之后,会再发送 EVENT_DHCP_SUCCEEDED消息, private class DhcpHandler extends Handler { public void handleMessage(Message msg) { switch (msg.what) { case EVENT_DHCP_START: if (NetworkUtils.runDhcp(mInterfaceName,mDhcpInfo)) { event = EVENT_DHCP_SUCCEEDED; } WifiLayer处理 EVENT_DHCP_SUCCEEDED消息 ,会再次广播发送 NETWORK_STATE_CHANGED_ACTION这个 Intent,这次带上完整的 IP地址信息。 case EVENT_DHCP_SUCCEEDED: mWifiInfo.setIpAddress(mDhcpInfo.ipAddress); setDetailedState(DetailedState.CONNECTED); intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); intent.putExtra(WifiManager.EXTRA_NETWORK_INFO,mNetworkInfo); mContext.sendStickyBroadcast(intent); break;
至此为止,整个连接过程完成。 问题: 目前的实现不支持 Ad-hoc方式。
转载地址:http://wtcgi.baihongyu.com/