(一百六十七)Android P WiFi扫描成功结果上报

Wifi 专栏收录该内容
98 篇文章 34 订阅

1.引子

接之前(一百五十五)Android P wifi 扫描失败结果上报流程梳理-扫描上报梳理的疑问

看这块代码有点失望,扫描失败只是framework的上报,比如参数不对,当前处于idle模式或者没有在timeout 4s内执行扫描,都停留在framework层,扫描命令执行结果失败的上报貌似并没有。

遗留问题:那何时会触发onResults呢?

扫描命令执行失败的上报还是有的,之前梳理漏了

之前梳理WifiTracker的代码发现WifiTracker是监听到SCAN_RESULTS_AVAILABLE_ACTION即有可用扫描结果时,主动向framework获取的,另外也知道扫描命令的下发和结果的获取是异步的。

            } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
                mStaleScanResults = false;

                fetchScansAndConfigsAndUpdateAccessPoints();
            } 

之前梳理的相关链接

(五十) Android O WiFi的扫描流程梳理

(五十四)Android O WiFi 获取扫描结果流程梳理

(一百五十四)Android P wifi 扫描失败结果上报流程梳理-扫描流程梳理

扫描结果的获取流程应该是最相关的

其中流程到中间的时候其实是断开着的,不是连续的,获取扫描结果到WifiScanningServiceImpl的时候就是返回缓存了,命令不是直接一下子到netlink_manager的

WifiScanningServiceImpl

                    case WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS:
                        msg.obj = new WifiScanner.ParcelableScanResults(
                            filterCachedScanResultsByAge());
                        replySucceeded(msg);
                        return HANDLED;
                    default:
                        return NOT_HANDLED;
                }
            }

            /**
             * Filter out  any scan results that are older than
             * {@link #CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS}.
             *
             * @return Filtered list of scan results.
             */
            private ScanResult[] filterCachedScanResultsByAge() {
                // Using ScanResult.timestamp here to ensure that we use the same fields as
                // WificondScannerImpl for filtering stale results.
                long currentTimeInMillis = mClock.getElapsedSinceBootMillis();
                return mCachedScanResults.stream()
                        .filter(scanResult
                                -> ((currentTimeInMillis - (scanResult.timestamp / 1000))
                                        < CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS))
                        .toArray(ScanResult[]::new);
            }
        }

 

2.扫描结果上报梳理

看下SCAN_RESULTS_AVAILABLE_ACTION 成功的消息是谁发来的

直接从ScanRequestProxy.java的onResults的回调开始看了,这个就是下发扫描命令时一起下发的监听器/callback

    private class ScanRequestProxyScanListener implements WifiScanner.ScanListener {
        @Override
        public void onSuccess() {
            // Scan request succeeded, wait for results to report to external clients.
            if (mVerboseLoggingEnabled) {
                Log.d(TAG, "Scan request succeeded");
            }
        }

        @Override
        public void onFailure(int reason, String description) {
            Log.e(TAG, "Scan failure received. reason: " + reason + ",description: " + description);
            sendScanResultBroadcastIfScanProcessingNotComplete(false);
        }

        @Override
        public void onResults(WifiScanner.ScanData[] scanDatas) {
            if (mVerboseLoggingEnabled) {
                Log.d(TAG, "Scan results received");
            }
            // For single scans, the array size should always be 1.
            if (scanDatas.length != 1) {
                Log.wtf(TAG, "Found more than 1 batch of scan results, Failing...");
                sendScanResultBroadcastIfScanProcessingNotComplete(false);
                return;
            }
            WifiScanner.ScanData scanData = scanDatas[0];
            ScanResult[] scanResults = scanData.getResults();
            if (mVerboseLoggingEnabled) {
                Log.d(TAG, "Received " + scanResults.length + " scan results");
            }
            // Store the last scan results & send out the scan completion broadcast.
            mLastScanResults.clear();
            mLastScanResults.addAll(Arrays.asList(scanResults));
            sendScanResultBroadcastIfScanProcessingNotComplete(true);
        }

        @Override
        public void onFullResult(ScanResult fullScanResult) {
            // Ignore for single scans.
        }

        @Override
        public void onPeriodChanged(int periodInMs) {
            // Ignore for single scans.
        }
    };

看下onResults是何时被回调的,流程其实和(一百五十四)Android P wifi 扫描失败结果上报流程梳理-扫描流程梳理是一样的,只是一个失败的一个成功的区别

然后看到WifiScanningServiceImpl对应状态机处理WifiScanner.CMD_START_SINGLE_SCAN消息

                    case WifiScanner.CMD_START_SINGLE_SCAN:
                        mWifiMetrics.incrementOneshotScanCount();
                        int handler = msg.arg2;
                        Bundle scanParams = (Bundle) msg.obj;
                        if (scanParams == null) {
                            logCallback("singleScanInvalidRequest",  ci, handler, "null params");
                            replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "params null");
                            return HANDLED;
                        }
                        scanParams.setDefusable(true);
                        ScanSettings scanSettings =
                                scanParams.getParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY);
                        WorkSource workSource =
                                scanParams.getParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY);
                        if (validateScanRequest(ci, handler, scanSettings)) {
                            logScanRequest("addSingleScanRequest", ci, handler, workSource,
                                    scanSettings, null);
                            replySucceeded(msg);

                            // If there is an active scan that will fulfill the scan request then
                            // mark this request as an active scan, otherwise mark it pending.
                            // If were not currently scanning then try to start a scan. Otherwise
                            // this scan will be scheduled when transitioning back to IdleState
                            // after finishing the current scan.
                            if (getCurrentState() == mScanningState) {
                                if (activeScanSatisfies(scanSettings)) {
                                    mActiveScans.addRequest(ci, handler, workSource, scanSettings);
                                } else {
                                    mPendingScans.addRequest(ci, handler, workSource, scanSettings);
                                }
                            } else {
                                mPendingScans.addRequest(ci, handler, workSource, scanSettings);
                                tryToStartNewScan();
                            }
                        } else {
                            logCallback("singleScanInvalidRequest",  ci, handler, "bad request");
                            replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
                            mWifiMetrics.incrementScanReturnEntry(
                                    WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION, 1);
                        }
                        return HANDLED;

然后看起来是扫描命令下发成功了就认为是可以成功了,这个异步不应该是从下面比如netlink_manager报上来才算扫描成功么

    void replySucceeded(Message msg) {
        if (msg.replyTo != null) {
            Message reply = Message.obtain();
            reply.what = WifiScanner.CMD_OP_SUCCEEDED;
            reply.arg2 = msg.arg2;
            if (msg.obj != null) {
                reply.obj = msg.obj;
            }
            try {
                msg.replyTo.send(reply);
                mLog.trace("replySucceeded recvdMessage=%").c(msg.what).flush();
            } catch (RemoteException e) {
                // There's not much we can do if reply can't be sent!
            }
        } else {
            // locally generated message; doesn't need a reply!
        }
    }

WifiScanner

                    /* ActionListeners grouped together */
                case CMD_OP_SUCCEEDED :
                    ((ActionListener) listener).onSuccess();
                    break;

 哦,这里有点误解,onSuccess和onResults不是一回事,onSuccess只是打印了个success的log,仅单单表明是下发扫描命令成功了,onResults还没梳理到

                case CMD_SCAN_RESULT :
                    ((ScanListener) listener).onResults(
                            ((ParcelableScanData) msg.obj).getResults());
                    return;

是收到CMD_SCAN_RESULT才算扫描结果。

WifiScanningServiceImpl有两个状态机会发来CMD_SCAN_RESULT

2.1 WifiSingleScanStateMachine

    /**
     * State machine that holds the state of single scans. Scans should only be active in the
     * ScanningState. The pending scans and active scans maps are swapped when entering
     * ScanningState. Any requests queued while scanning will be placed in the pending queue and
     * executed after transitioning back to IdleState.
     */
    class WifiSingleScanStateMachine extends StateMachine implements WifiNative.ScanEventHandler {
...
        void reportScanResults(ScanData results) {
            if (results != null && results.getResults() != null) {
                if (results.getResults().length > 0) {
                    mWifiMetrics.incrementNonEmptyScanResultCount();
                } else {
                    mWifiMetrics.incrementEmptyScanResultCount();
                }
            }
            ScanData[] allResults = new ScanData[] {results};
            for (RequestInfo<ScanSettings> entry : mActiveScans) {
                ScanData[] resultsToDeliver = ScanScheduleUtil.filterResultsForSettings(
                        mChannelHelper, allResults, entry.settings, -1);
                WifiScanner.ParcelableScanData parcelableResultsToDeliver =
                        new WifiScanner.ParcelableScanData(resultsToDeliver);
                logCallback("singleScanResults",  entry.clientInfo, entry.handlerId,
                        describeForLog(resultsToDeliver));
                entry.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableResultsToDeliver);
                // make sure the handler is removed
                entry.reportEvent(WifiScanner.CMD_SINGLE_SCAN_COMPLETED, 0, null);
            }

            WifiScanner.ParcelableScanData parcelableAllResults =
                    new WifiScanner.ParcelableScanData(allResults);
            for (RequestInfo<Void> entry : mSingleScanListeners) {
                logCallback("singleScanResults",  entry.clientInfo, entry.handlerId,
                        describeForLog(allResults));
                entry.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableAllResults);
            }

            if (results.isAllChannelsScanned()) {
                mCachedScanResults.clear();
                mCachedScanResults.addAll(Arrays.asList(results.getResults()));
            }
        }

其中有个状态

        class ScanningState extends State {
            private WorkSource mScanWorkSource;

            @Override
            public void enter() {
                mScanWorkSource = mActiveScans.createMergedWorkSource();
                try {
                    mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource);
                } catch (RemoteException e) {
                    loge(e.toString());
                }
            }

            @Override
            public void exit() {
                mActiveScanSettings = null;
                try {
                    mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource);
                } catch (RemoteException e) {
                    loge(e.toString());
                }

                // if any scans are still active (never got results available then indicate failure)
                mWifiMetrics.incrementScanReturnEntry(
                                WifiMetricsProto.WifiLog.SCAN_UNKNOWN,
                                mActiveScans.size());
                sendOpFailedToAllAndClear(mActiveScans, WifiScanner.REASON_UNSPECIFIED,
                        "Scan was interrupted");
            }

            @Override
            public boolean processMessage(Message msg) {
                switch (msg.what) {
                    case CMD_SCAN_RESULTS_AVAILABLE:
                        mWifiMetrics.incrementScanReturnEntry(
                                WifiMetricsProto.WifiLog.SCAN_SUCCESS,
                                mActiveScans.size());
                        reportScanResults(mScannerImpl.getLatestSingleScanResults());
                        mActiveScans.clear();
                        transitionTo(mIdleState);
                        return HANDLED;

这里突然又发现了一个会告知上次扫描失败的方法sendOpFailedToAllAndClear,先暂时不看了,看下什么会发来CMD_SCAN_RESULTS_AVAILABLE

        /**
         * Called to indicate a change in state for the current scan.
         * Will dispatch a coresponding event to the state machine
         */
        @Override
        public void onScanStatus(int event) {
            if (DBG) localLog("onScanStatus event received, event=" + event);
            switch(event) {
                case WifiNative.WIFI_SCAN_RESULTS_AVAILABLE:
                case WifiNative.WIFI_SCAN_THRESHOLD_NUM_SCANS:
                case WifiNative.WIFI_SCAN_THRESHOLD_PERCENT:
                    sendMessage(CMD_SCAN_RESULTS_AVAILABLE);
                    break;
                case WifiNative.WIFI_SCAN_FAILED:
                    sendMessage(CMD_SCAN_FAILED);
                    break;
                default:
                    Log.e(TAG, "Unknown scan status event: " + event);
                    break;
            }
        }

这里又有一个扫描失败会上报的event

看下哪里会调用onScanStatus

1)

http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiVendorHal.java#2803

    /**
     * Callback for events on the STA interface.
     */
    private class StaIfaceEventCallback extends IWifiStaIfaceEventCallback.Stub {
        @Override
        public void onBackgroundScanFailure(int cmdId) {
            mVerboseLog.d("onBackgroundScanFailure " + cmdId);
            WifiNative.ScanEventHandler eventHandler;
            synchronized (sLock) {
                if (mScan == null || cmdId != mScan.cmdId) return;
                eventHandler = mScan.eventHandler;
            }
            eventHandler.onScanStatus(WifiNative.WIFI_SCAN_FAILED);
        }

        @Override
        public void onBackgroundFullScanResult(
                int cmdId, int bucketsScanned, StaScanResult result) {
            mVerboseLog.d("onBackgroundFullScanResult " + cmdId);
            WifiNative.ScanEventHandler eventHandler;
            synchronized (sLock) {
                if (mScan == null || cmdId != mScan.cmdId) return;
                eventHandler = mScan.eventHandler;
            }
            eventHandler.onFullScanResult(hidlToFrameworkScanResult(result), bucketsScanned);
        }

        @Override
        public void onBackgroundScanResults(int cmdId, ArrayList<StaScanData> scanDatas) {
            mVerboseLog.d("onBackgroundScanResults " + cmdId);
            WifiNative.ScanEventHandler eventHandler;
            // WifiScanner currently uses the results callback to fetch the scan results.
            // So, simulate that by sending out the notification and then caching the results
            // locally. This will then be returned to WifiScanner via getScanResults.
            synchronized (sLock) {
                if (mScan == null || cmdId != mScan.cmdId) return;
                eventHandler = mScan.eventHandler;
                mScan.latestScanResults = hidlToFrameworkScanDatas(cmdId, scanDatas);
            }
            eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
        }

        @Override
        public void onRssiThresholdBreached(int cmdId, byte[/* 6 */] currBssid, int currRssi) {
            mVerboseLog.d("onRssiThresholdBreached " + cmdId + "currRssi " + currRssi);
            WifiNative.WifiRssiEventHandler eventHandler;
            synchronized (sLock) {
                if (mWifiRssiEventHandler == null || cmdId != sRssiMonCmdId) return;
                eventHandler = mWifiRssiEventHandler;
            }
            eventHandler.onRssiThresholdBreached((byte) currRssi);
        }
    }

暂不梳理,这边是对应的WifiBackgroundScanStateMachine,下一部分继续梳理

 

2)

http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java#300

    private void pollLatestScanData() {
        synchronized (mSettingsLock) {
            if (mLastScanSettings == null) {
                 // got a scan before we started scanning or after scan was canceled
                return;
            }

            mNativeScanResults = mWifiNative.getScanResults(mIfaceName);
            List<ScanResult> singleScanResults = new ArrayList<>();
            int numFilteredScanResults = 0;
            for (int i = 0; i < mNativeScanResults.size(); ++i) {
                ScanResult result = mNativeScanResults.get(i).getScanResult();
                long timestamp_ms = result.timestamp / 1000; // convert us -> ms
                if (timestamp_ms > mLastScanSettings.startTime) {
                    if (mLastScanSettings.singleScanFreqs.containsChannel(
                                    result.frequency)) {
                        singleScanResults.add(result);
                    }
                } else {
                    numFilteredScanResults++;
                }
            }
            if (numFilteredScanResults != 0) {
                Log.d(TAG, "Filtering out " + numFilteredScanResults + " scan results.");
            }

            if (mLastScanSettings.singleScanEventHandler != null) {
                if (mLastScanSettings.reportSingleScanFullResults) {
                    for (ScanResult scanResult : singleScanResults) {
                        // ignore buckets scanned since there is only one bucket for a single scan
                        mLastScanSettings.singleScanEventHandler.onFullScanResult(scanResult,
                                /* bucketsScanned */ 0);
                    }
                }
                Collections.sort(singleScanResults, SCAN_RESULT_SORT_COMPARATOR);
                mLatestSingleScanResult = new WifiScanner.ScanData(0, 0, 0,
                        isAllChannelsScanned(mLastScanSettings.singleScanFreqs),
                        singleScanResults.toArray(new ScanResult[singleScanResults.size()]));
                mLastScanSettings.singleScanEventHandler
                        .onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
            }

            mLastScanSettings = null;
        }
    }

这边看是WifiMonitor通知的

    @Override
    public boolean handleMessage(Message msg) {
        switch(msg.what) {
            case WifiMonitor.SCAN_FAILED_EVENT:
                Log.w(TAG, "Scan failed");
                cancelScanTimeout();
                reportScanFailure();
                break;
            case WifiMonitor.PNO_SCAN_RESULTS_EVENT:
                pollLatestScanDataForPno();
                break;
            case WifiMonitor.SCAN_RESULTS_EVENT:
                cancelScanTimeout();
                pollLatestScanData();
                break;
            default:
                // ignore unknown event
        }
        return true;
    }

WifiMonitor

    /**
     * Broadcast scan result event to all the handlers registered for this event.
     * @param iface Name of iface on which this occurred.
     */
    public void broadcastScanResultEvent(String iface) {
        sendMessage(iface, SCAN_RESULTS_EVENT);
    }

http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java#93

    private class ScanEventHandler extends IScanEvent.Stub {
        private String mIfaceName;

        ScanEventHandler(@NonNull String ifaceName) {
            mIfaceName = ifaceName;
        }

        @Override
        public void OnScanResultReady() {
            Log.d(TAG, "Scan result ready event");
            mWifiMonitor.broadcastScanResultEvent(mIfaceName);
        }

        @Override
        public void OnScanFailed() {
            Log.d(TAG, "Scan failed event");
            mWifiMonitor.broadcastScanFailedEvent(mIfaceName);
        }
    }

这个handler是WiFi初始化wificond的时候传过去的,所以应该是wificond会回调

http://androidxref.com/9.0.0_r3/xref/system/connectivity/wificond/scanning/scanner_impl.cpp#417

void ScannerImpl::OnScanResultsReady(uint32_t interface_index, bool aborted,
                                     vector<vector<uint8_t>>& ssids,
                                     vector<uint32_t>& frequencies) {
  if (!scan_started_) {
    LOG(INFO) << "Received external scan result notification from kernel.";
  }
  scan_started_ = false;
  if (scan_event_handler_ != nullptr) {
    // TODO: Pass other parameters back once we find framework needs them.
    if (aborted) {
      LOG(WARNING) << "Scan aborted";
      scan_event_handler_->OnScanFailed();
    } else {
      scan_event_handler_->OnScanResultReady();
    }
  } else {
    LOG(WARNING) << "No scan event handler found.";
  }
}

http://androidxref.com/9.0.0_r3/xref/system/connectivity/wificond/net/netlink_manager.cpp#497

void NetlinkManager::BroadcastHandler(unique_ptr<const NL80211Packet> packet) {
  if (packet->GetMessageType() != GetFamilyId()) {
    LOG(ERROR) << "Wrong family id for multicast message";
    return;
  }
  uint32_t command = packet->GetCommand();

  if (command == NL80211_CMD_NEW_SCAN_RESULTS ||
      // Scan was aborted, for unspecified reasons.partial scan results may be
      // available.
      command == NL80211_CMD_SCAN_ABORTED) {
    OnScanResultsReady(std::move(packet));
    return;
  }

  if (command == NL80211_CMD_SCHED_SCAN_RESULTS ||
      command == NL80211_CMD_SCHED_SCAN_STOPPED) {
    OnSchedScanResultsReady(std::move(packet));
    return;
  }

void NetlinkManager::OnScanResultsReady(unique_ptr<const NL80211Packet> packet) {
  uint32_t if_index;
  if (!packet->GetAttributeValue(NL80211_ATTR_IFINDEX, &if_index)) {
    LOG(ERROR) << "Failed to get interface index from scan result notification";
    return;
  }
  bool aborted = false;
  if (packet->GetCommand() == NL80211_CMD_SCAN_ABORTED) {
    aborted = true;
  }

  const auto handler = on_scan_result_ready_handler_.find(if_index);
  if (handler == on_scan_result_ready_handler_.end()) {
    LOG(WARNING) << "No handler for scan result notification from interface"
                 << " with index: " << if_index;
    return;
  }

  vector<vector<uint8_t>> ssids;
  NL80211NestedAttr ssids_attr(0);
  if (!packet->GetAttribute(NL80211_ATTR_SCAN_SSIDS, &ssids_attr)) {
    if (!aborted) {
      LOG(WARNING) << "Failed to get scan ssids from scan result notification";
    }
  } else {
    if (!ssids_attr.GetListOfAttributeValues(&ssids)) {
      return;
    }
  }
  vector<uint32_t> freqs;
  NL80211NestedAttr freqs_attr(0);
  if (!packet->GetAttribute(NL80211_ATTR_SCAN_FREQUENCIES, &freqs_attr)) {
    if (!aborted) {
      LOG(WARNING) << "Failed to get scan freqs from scan result notification";
    }
  } else {
    if (!freqs_attr.GetListOfAttributeValues(&freqs)) {
      return;
    }
  }
  // Run scan result notification handler.
  handler->second(if_index, aborted, ssids, freqs);
}

其中ScannerImpl和NetlinkManager的调用联系是通过scan_utils传递过来的

  scan_utils_->SubscribeScanResultNotification(
      interface_index_,
      std::bind(&ScannerImpl::OnScanResultsReady, this, _1, _2, _3, _4));

而NetlinkManager应该是收到底层的数据报通知才开始流程的

void NetlinkManager::ReceivePacketAndRunHandler(int fd) {
  ssize_t len = read(fd, ReceiveBuffer, kReceiveBufferSize);
  if (len == -1) {
    LOG(ERROR) << "Failed to read packet from buffer";
    return;
  }
  if (len == 0) {
    return;
  }
  // There might be multiple message in one datagram payload.
  uint8_t* ptr = ReceiveBuffer;
  while (ptr < ReceiveBuffer + len) {
    // peek at the header.
    if (ptr + sizeof(nlmsghdr) > ReceiveBuffer + len) {
      LOG(ERROR) << "payload is broken.";
      return;
    }
    const nlmsghdr* nl_header = reinterpret_cast<const nlmsghdr*>(ptr);
    unique_ptr<NL80211Packet> packet(
        new NL80211Packet(vector<uint8_t>(ptr, ptr + nl_header->nlmsg_len)));
    ptr += nl_header->nlmsg_len;
    if (!packet->IsValid()) {
      LOG(ERROR) << "Receive invalid packet";
      return;
    }
    // Some document says message from kernel should have port id equal 0.
    // However in practice this is not always true so we don't check that.

    uint32_t sequence_number = packet->GetMessageSequence();

    // Handle multicasts.
    if (sequence_number == kBroadcastSequenceNumber) {
      BroadcastHandler(std::move(packet));
      continue;
    }

    auto itr = message_handlers_.find(sequence_number);
    // There is no handler for this sequence number.
    if (itr == message_handlers_.end()) {
      LOG(WARNING) << "No handler for message: " << sequence_number;
      return;
    }
    // A multipart message is terminated by NLMSG_DONE.
    // In this case we don't need to run the handler.
    // NLMSG_NOOP means no operation, message must be discarded.
    uint32_t message_type =  packet->GetMessageType();
    if (message_type == NLMSG_DONE || message_type == NLMSG_NOOP) {
      message_handlers_.erase(itr);
      return;
    }
    if (message_type == NLMSG_OVERRUN) {
      LOG(ERROR) << "Get message overrun notification";
      message_handlers_.erase(itr);
      return;
    }

    // In case we receive a NLMSG_ERROR message:
    // NLMSG_ERROR could be either an error or an ACK.
    // It is an ACK message only when error code field is set to 0.
    // An ACK could be return when we explicitly request that with NLM_F_ACK.
    // An ERROR could be received on NLM_F_ACK or other failure cases.
    // We should still run handler in this case, leaving it for the caller
    // to decide what to do with the packet.

    bool is_multi = packet->IsMulti();
    // Run the handler.
    itr->second(std::move(packet));
    // Remove handler after processing.
    if (!is_multi) {
      message_handlers_.erase(itr);
    }
  }
}

 

2.2 WifiBackgroundScanStateMachine

        private void reportScanResults(ScanData[] results) {
            if (results == null) {
                Log.d(TAG,"The results is null, nothing to report.");
                return;
            }
            for (ScanData result : results) {
                if (result != null && result.getResults() != null) {
                    if (result.getResults().length > 0) {
                        mWifiMetrics.incrementNonEmptyScanResultCount();
                    } else {
                        mWifiMetrics.incrementEmptyScanResultCount();
                    }
                }
            }
            for (RequestInfo<ScanSettings> entry : mActiveBackgroundScans) {
                ClientInfo ci = entry.clientInfo;
                int handler = entry.handlerId;
                ScanSettings settings = entry.settings;
                ScanData[] resultsToDeliver =
                        mBackgroundScheduler.filterResultsForSettings(results, settings);
                if (resultsToDeliver != null) {
                    logCallback("backgroundScanResults", ci, handler,
                            describeForLog(resultsToDeliver));
                    WifiScanner.ParcelableScanData parcelableScanData =
                            new WifiScanner.ParcelableScanData(resultsToDeliver);
                    ci.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, handler, parcelableScanData);
                }
            }
        }

流程和singleScan差不多

http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiVendorHal.java#2803

    /**
     * Callback for events on the STA interface.
     */
    private class StaIfaceEventCallback extends IWifiStaIfaceEventCallback.Stub {
        @Override
        public void onBackgroundScanFailure(int cmdId) {
            mVerboseLog.d("onBackgroundScanFailure " + cmdId);
            WifiNative.ScanEventHandler eventHandler;
            synchronized (sLock) {
                if (mScan == null || cmdId != mScan.cmdId) return;
                eventHandler = mScan.eventHandler;
            }
            eventHandler.onScanStatus(WifiNative.WIFI_SCAN_FAILED);
        }

        @Override
        public void onBackgroundFullScanResult(
                int cmdId, int bucketsScanned, StaScanResult result) {
            mVerboseLog.d("onBackgroundFullScanResult " + cmdId);
            WifiNative.ScanEventHandler eventHandler;
            synchronized (sLock) {
                if (mScan == null || cmdId != mScan.cmdId) return;
                eventHandler = mScan.eventHandler;
            }
            eventHandler.onFullScanResult(hidlToFrameworkScanResult(result), bucketsScanned);
        }

        @Override
        public void onBackgroundScanResults(int cmdId, ArrayList<StaScanData> scanDatas) {
            mVerboseLog.d("onBackgroundScanResults " + cmdId);
            WifiNative.ScanEventHandler eventHandler;
            // WifiScanner currently uses the results callback to fetch the scan results.
            // So, simulate that by sending out the notification and then caching the results
            // locally. This will then be returned to WifiScanner via getScanResults.
            synchronized (sLock) {
                if (mScan == null || cmdId != mScan.cmdId) return;
                eventHandler = mScan.eventHandler;
                mScan.latestScanResults = hidlToFrameworkScanDatas(cmdId, scanDatas);
            }
            eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
        }

        @Override
        public void onRssiThresholdBreached(int cmdId, byte[/* 6 */] currBssid, int currRssi) {
            mVerboseLog.d("onRssiThresholdBreached " + cmdId + "currRssi " + currRssi);
            WifiNative.WifiRssiEventHandler eventHandler;
            synchronized (sLock) {
                if (mWifiRssiEventHandler == null || cmdId != sRssiMonCmdId) return;
                eventHandler = mWifiRssiEventHandler;
            }
            eventHandler.onRssiThresholdBreached((byte) currRssi);
        }
    }

看下谁会回调这个接口

http://androidxref.com/9.0.0_r3/xref/hardware/interfaces/wifi/1.2/default/wifi_sta_iface.cpp#368

WifiStatus WifiStaIface::startBackgroundScanInternal(
    uint32_t cmd_id, const StaBackgroundScanParameters& params) {
    legacy_hal::wifi_scan_cmd_params legacy_params;
    if (!hidl_struct_util::convertHidlGscanParamsToLegacy(params,
                                                          &legacy_params)) {
        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
    }
    android::wp<WifiStaIface> weak_ptr_this(this);
    const auto& on_failure_callback =
        [weak_ptr_this](legacy_hal::wifi_request_id id) {
            const auto shared_ptr_this = weak_ptr_this.promote();
            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
                LOG(ERROR) << "Callback invoked on an invalid object";
                return;
            }
            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
                if (!callback->onBackgroundScanFailure(id).isOk()) {
                    LOG(ERROR)
                        << "Failed to invoke onBackgroundScanFailure callback";
                }
            }
        };
    const auto& on_results_callback =
        [weak_ptr_this](
            legacy_hal::wifi_request_id id,
            const std::vector<legacy_hal::wifi_cached_scan_results>& results) {
            const auto shared_ptr_this = weak_ptr_this.promote();
            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
                LOG(ERROR) << "Callback invoked on an invalid object";
                return;
            }
            std::vector<StaScanData> hidl_scan_datas;
            if (!hidl_struct_util::
                    convertLegacyVectorOfCachedGscanResultsToHidl(
                        results, &hidl_scan_datas)) {
                LOG(ERROR) << "Failed to convert scan results to HIDL structs";
                return;
            }
            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
                if (!callback->onBackgroundScanResults(id, hidl_scan_datas)
                         .isOk()) {
                    LOG(ERROR)
                        << "Failed to invoke onBackgroundScanResults callback";
                }
            }
        };

http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiVendorHal.java#893

    /**
     * Starts a background scan
     *
     * Any ongoing scan will be stopped first
     *
     * @param ifaceName    Name of the interface.
     * @param settings     to control the scan
     * @param eventHandler to call with the results
     * @return true for success
     */
    public boolean startBgScan(@NonNull String ifaceName,
                               WifiNative.ScanSettings settings,
                               WifiNative.ScanEventHandler eventHandler) {
        WifiStatus status;
        if (eventHandler == null) return boolResult(false);
        synchronized (sLock) {
            IWifiStaIface iface = getStaIface(ifaceName);
            if (iface == null) return boolResult(false);
            try {
                if (mScan != null && !mScan.paused) {
                    ok(iface.stopBackgroundScan(mScan.cmdId));
                    mScan = null;
                }
                mLastScanCmdId = (mLastScanCmdId % 9) + 1; // cycle through non-zero single digits
                CurrentBackgroundScan scan = new CurrentBackgroundScan(mLastScanCmdId, settings);
                status = iface.startBackgroundScan(scan.cmdId, scan.param);
                if (!ok(status)) return false;
                scan.eventHandler = eventHandler;
                mScan = scan;
                return true;
            } catch (RemoteException e) {
                handleRemoteException(e);
                return false;
            }
        }
    }

梳理到这边再往下就发现是

/**
 * WifiScanner implementation that takes advantage of the gscan HAL API
 * The gscan API is used to perform background scans and wificond is used for oneshot scans.
 * @see com.android.server.wifi.scanner.WifiScannerImpl for more details on each method.
 */
public class HalWifiScannerImpl extends WifiScannerImpl implements Handler.Callback {

WifiScannerImpl分HalWifiScannerImpl和WificondScannerImpl,hal来进行background scan,而wificond负责oneshot scan,这里梳理的是对应的WifiBackgroundScanStateMachine

    /**
     * Factory that create the implementation that is most appropriate for the system.
     * This factory should only ever be used once.
     */
    public static final WifiScannerImplFactory DEFAULT_FACTORY = new WifiScannerImplFactory() {
            public WifiScannerImpl create(Context context, Looper looper, Clock clock) {
                WifiNative wifiNative = WifiInjector.getInstance().getWifiNative();
                WifiMonitor wifiMonitor = WifiInjector.getInstance().getWifiMonitor();
                String ifaceName = wifiNative.getClientInterfaceName();
                if (TextUtils.isEmpty(ifaceName)) {
                    return null;
                }
                if (wifiNative.getBgScanCapabilities(
                        ifaceName, new WifiNative.ScanCapabilities())) {
                    return new HalWifiScannerImpl(context, ifaceName, wifiNative, wifiMonitor,
                            looper, clock);
                } else {
                    return new WificondScannerImpl(context, ifaceName, wifiNative, wifiMonitor,
                            new WificondChannelHelper(wifiNative), looper, clock);
                }
            }
        };

http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiVendorHal.java#662

    /**
     * Gets the scan capabilities
     *
     * @param ifaceName Name of the interface.
     * @param capabilities object to be filled in
     * @return true for success, false for failure
     */
    public boolean getBgScanCapabilities(
            @NonNull String ifaceName, WifiNative.ScanCapabilities capabilities) {
        synchronized (sLock) {
            IWifiStaIface iface = getStaIface(ifaceName);
            if (iface == null) return boolResult(false);
            try {
                MutableBoolean ans = new MutableBoolean(false);
                WifiNative.ScanCapabilities out = capabilities;
                iface.getBackgroundScanCapabilities((status, cap) -> {
                            if (!ok(status)) return;
                            mVerboseLog.info("scan capabilities %").c(cap.toString()).flush();
                            out.max_scan_cache_size = cap.maxCacheSize;
                            out.max_ap_cache_per_scan = cap.maxApCachePerScan;
                            out.max_scan_buckets = cap.maxBuckets;
                            out.max_rssi_sample_size = 0;
                            out.max_scan_reporting_threshold = cap.maxReportingThreshold;
                            ans.value = true;
                        }
                );
                return ans.value;
            } catch (RemoteException e) {
                handleRemoteException(e);
                return false;
            }
        }
    }

这里也许可以打verboselog看下。

 

3.总结

现在扫描结果上报流程看的差不多了,分wificond和hal的扫描,扫描结果成功都会一步一步将结果上报上来,wificond扫描成功或失败15s内未上报上来,也会有个失败的结果上来,hal的扫描暂时还没怎么关注过,先关注wificond的扫描吧。

 

 

 

 

  • 1
    点赞
  • 2
    评论
  • 4
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 鲸 设计师:meimeiellie 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值