Android -- Wifi扫描流程分析
转自 http://blog.csdn.net/csdn_of_coder/article/details/51922654
Wifi扫描的调用函数是WifiManager中的startScan()函数:
通过AIDL调用WifiService中的同名函数:
进入WifiStateMachine,向状态机中发送CMD_START_SCAN消息开启扫描流程DriverStartedState处理,开始扫描:
startScanStar():
调用native方法scan()向wpa_supplicant发送扫描指令;当wpa_s扫描结束后,WifiMonitor就会收到wpa_s上报的事件,framework层就知道扫描已经结束,可以去获取扫描结果了。WifiMonitor中:
向WifiStateMachine发送SCAN_RESULTS_EVENT消息,告知现在可以获取扫描结果。
- /**
- * Request a scan for access points. Returns immediately. The availability
- * of the results is made known later by means of an asynchronous event sent
- * on completion of the scan.
- * @return {@code true} if the operation succeeded, i.e., the scan was initiated
- */
- public boolean startScan() {
- try {
- mService.startScan(null, null);
- return true;
- } catch (RemoteException e) {
- return false;
- }
- }
- /** @hide */
- @SystemApi
- public boolean startScan(WorkSource workSource) {
- try {
- mService.startScan(null, workSource);
- return true;
- } catch (RemoteException e) {
- return false;
- }
- }
- /**
- * see {@link android.net.wifi.WifiManager#startScan}
- * and {@link android.net.wifi.WifiManager#startCustomizedScan}
- *
- * @param settings If null, use default parameter, i.e. full scan.
- * @param workSource If null, all blame is given to the calling uid.
- */
- public void startScan(ScanSettings settings, WorkSource workSource) {
- enforceChangePermission();
- synchronized (this) {
- if (mInIdleMode) {
- // Need to send an immediate scan result broadcast in case the
- // caller is waiting for a result ..
- // clear calling identity to send broadcast
- long callingIdentity = Binder.clearCallingIdentity();
- try {
- mWifiStateMachine.sendScanResultsAvailableBroadcast(/* scanSucceeded = */ false);
- } finally {
- // restore calling identity
- Binder.restoreCallingIdentity(callingIdentity);
- }
- mScanPending = true;
- return;
- }
- }
- if (settings != null) {
- settings = new ScanSettings(settings);
- if (!settings.isValid()) {
- Slog.e(TAG, "invalid scan setting");
- return;
- }
- }
- if (workSource != null) {
- enforceWorkSourcePermission();
- // WifiManager currently doesn't use names, so need to clear names out of the
- // supplied WorkSource to allow future WorkSource combining.
- workSource.clearNames();
- }
- mWifiStateMachine.startScan(Binder.getCallingUid(), scanRequestCounter++,
- settings, workSource);
- }
- private void handleScanRequest(int type, Message message) {
- ...
- // call wifi native to start the scan
- if (startScanNative(type, freqs)) {
- // only count battery consumption if scan request is accepted
- noteScanStart(message.arg1, workSource);
- // a full scan covers everything, clearing scan request buffer
- if (freqs == null)
- mBufferedScanMsg.clear();
- messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
- if (workSource != null) {
- // External worksource was passed along the scan request,
- // hence always send a broadcast
- mSendScanResultsBroadcast = true;
- }
- return;
- }
- ...
- }
- /**
- * return true iff scan request is accepted
- */
- private boolean startScanNative(int type, String freqs) {
- if (mWifiNative.scan(type, freqs)) {
- mIsScanOngoing = true;
- mIsFullScanOngoing = (freqs == null);
- lastScanFreqs = freqs;
- return true;
- }
- return false;
- }
- /**
- * 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;
- }
- }
SupplicantStartedState中处理该消息:
setScanResults()从wpa_s获取扫描结果,并保存;同时,也会进入autojoin流程,进行重连操作。最后发送ScanResults的广播,通知上层获取扫描结果。
本文讲述了基本的扫描处理流程,wpa_s中的处理,大家有兴趣可以自己研究。目前的工作中,wpa_s的代码基本都不涉及改动,所以这部分了解不多。
- case WifiMonitor.SCAN_RESULTS_EVENT:
- case WifiMonitor.SCAN_FAILED_EVENT:
- maybeRegisterNetworkFactory(); // Make sure our NetworkFactory is registered
- closeRadioScanStats();
- noteScanEnd();
- setScanResults();
- if (mIsFullScanOngoing || mSendScanResultsBroadcast) {
- /* Just updated results from full scan, let apps know about this */
- boolean scanSucceeded = message.what == WifiMonitor.SCAN_RESULTS_EVENT;
- sendScanResultsAvailableBroadcast(scanSucceeded);
- }
- mSendScanResultsBroadcast = false;
- mIsScanOngoing = false;
- mIsFullScanOngoing = false;
- if (mBufferedScanMsg.size() > 0)
- sendMessage(mBufferedScanMsg.remove());
- break;