上一篇我们梳理了WiFi的开启流程,Android11 WiFi开启流程,在最后我们说到ActiveModeWarden中注册了ClientListener监听器。我们接着这个逻辑继续梳理一下打开WiFi以后的扫描流程。

一、WiFi打开以后,ClientListener会监听到,这时候会更新扫描状态。
frameworks/opt/net/wifi/service/java/com/android/server/wifi/ActiveModeWarden.java

private class ClientListener extends ModeCallback implements ActiveModeManager.Listener {@Overridepublic void onStarted() {updateClientScanMode();updateBatteryStats();}

在这里enable扫描

private void updateClientScanMode() {boolean scanEnabled = hasAnyClientModeManager();boolean scanningForHiddenNetworksEnabled;if (mContext.getResources().getBoolean(R.bool.config_wifiScanHiddenNetworksScanOnlyMode)) {scanningForHiddenNetworksEnabled = hasAnyClientModeManager();} else {scanningForHiddenNetworksEnabled = hasAnyClientModeManagerInConnectivityRole();}mScanRequestProxy.enableScanning(scanEnabled, scanningForHiddenNetworksEnabled);
}

二、在这里调用WifiScanner并且发送扫描广播
frameworks/opt/net/wifi/service/java/com/android/server/wifi/ScanRequestProxy.java

public void enableScanning(boolean enable, boolean enableScanningForHiddenNetworks) {if (enable) {enableScanningInternal(true);mScanningForHiddenNetworksEnabled = enableScanningForHiddenNetworks;Log.i(TAG, "Scanning for hidden networks is "+ (enableScanningForHiddenNetworks ? "enabled" : "disabled"));} else {enableScanningInternal(false);}mScanningEnabled = enable;
}
private void enableScanningInternal(boolean enable) {if (!retrieveWifiScannerIfNecessary()) {Log.e(TAG, "Failed to retrieve wifiscanner");return;}mWifiScanner.setScanningEnabled(enable);sendScanAvailableBroadcast(mContext, enable);clearScanResults();Log.i(TAG, "Scanning is " + (enable ? "enabled" : "disabled"));}
private void sendScanAvailableBroadcast(Context context, boolean available) {Log.d(TAG, "Sending scan available broadcast: " + available);final Intent intent = new Intent(WifiManager.ACTION_WIFI_SCAN_AVAILABILITY_CHANGED);intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, available);context.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}

三、这里发送了CMD_ENABLE 消息,我们看这个消息的处理。
frameworks/base/wifi/java/android/net/wifi/WifiScanner.java

public void setScanningEnabled(boolean enable) {validateChannel();mAsyncChannel.sendMessage(enable ? CMD_ENABLE : CMD_DISABLE);
}

四、在这里启动scan,创建了WifiScannerImplFactory
frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java

switch (msg.what) {case WifiScanner.CMD_ENABLE:Log.i(TAG, "Received a request to enable scanning, UID = " + msg.sendingUid);setupScannerImpls();mBackgroundScanStateMachine.sendMessage(Message.obtain(msg));mSingleScanStateMachine.sendMessage(Message.obtain(msg));mPnoScanStateMachine.sendMessage(Message.obtain(msg));break;
private void setupScannerImpls() {Set<String> ifaceNames = mWifiNative.getClientInterfaceNames();if (ArrayUtils.isEmpty(ifaceNames)) {loge("Failed to retrieve client interface names");return;}Set<String> ifaceNamesOfImplsAlreadySetup = mScannerImpls.keySet();if (ifaceNames.equals(ifaceNamesOfImplsAlreadySetup)) {// Scanner Impls already exist for all ifaces (back to back CMD_ENABLE sent?).Log.i(TAG, "scanner impls already exists");return;}// set of impls to teardown.Set<String> ifaceNamesOfImplsToTeardown = new ArraySet<>(ifaceNamesOfImplsAlreadySetup);ifaceNamesOfImplsToTeardown.removeAll(ifaceNames);// set of impls to be considered for setup.Set<String> ifaceNamesOfImplsToSetup = new ArraySet<>(ifaceNames);ifaceNamesOfImplsToSetup.removeAll(ifaceNamesOfImplsAlreadySetup);for (String ifaceName : ifaceNamesOfImplsToTeardown) {WifiScannerImpl impl = mScannerImpls.remove(ifaceName);if (impl == null) continue; // should never happenimpl.cleanup();Log.i(TAG, "Removed an impl for " + ifaceName);}for (String ifaceName : ifaceNamesOfImplsToSetup) {WifiScannerImpl impl = mScannerImplFactory.create(mContext, mLooper, mClock, ifaceName);if (impl == null) {loge("Failed to create scanner impl for " + ifaceName);continue;}// If this new scanner impl does not offer any new bands to scan, then we should// ignore it.if (!doesAnyExistingImplSatisfy(impl)) {mScannerImpls.put(ifaceName, impl);Log.i(TAG, "Created a new impl for " + ifaceName);} else {Log.i(TAG, "All the channels on the new impl for iface " + ifaceName+ " are already satisfied by an existing impl. Skipping..");impl.cleanup(); // cleanup the impl before discarding.}}
}

五、启动Scan以后,这时候就要开始扫描了。开始扫描的逻辑是从Settings触发的。
WifiTracker接收到wifi状态改变的广播以后,
packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java

final BroadcastReceiver mReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();sVerboseLogging = mWifiManager.isVerboseLoggingEnabled();if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,WifiManager.WIFI_STATE_UNKNOWN));

如果wifi是启动的,则刷新scanner

private void updateWifiState(int state) {if (isVerboseLoggingEnabled()) {Log.d(TAG, "updateWifiState: " + state);}if (state == WifiManager.WIFI_STATE_ENABLED) {synchronized (mLock) {if (mScanner != null) {// We only need to resume if mScanner isn't null because// that means we want to be scanning.mScanner.resume();}}} mListener.onWifiStateChanged(state);
}
class Scanner extends Handler {static final int MSG_SCAN = 0;private int mRetry = 0;void resume() {if (isVerboseLoggingEnabled()) {Log.d(TAG, "Scanner resume");}if (!hasMessages(MSG_SCAN)) {sendEmptyMessage(MSG_SCAN);}}

这里接收到MSG_SCAN消息以后调用了wifimanager的startScan

public void handleMessage(Message message) {if (message.what != MSG_SCAN) return;if (mWifiManager.startScan()) {mRetry = 0;} else if (++mRetry >= 3) {mRetry = 0;if (mContext != null) {Toast.makeText(mContext, R.string.wifi_fail_to_scan, Toast.LENGTH_LONG).show();}return;}sendEmptyMessageDelayed(MSG_SCAN, WIFI_RESCAN_INTERVAL_MS);

六、wifimanager一直调用到ScanRequestProxy,在这里会初始化一些扫描的设置参数,比如扫描信道,隐藏网络等等
wifimanager --> WifiServiceImpl --> ScanRequestProxy --> WifiScanner

    public boolean startScan(int callingUid, String packageName) {if (!mScanningEnabled || !retrieveWifiScannerIfNecessary()) {Log.e(TAG, "Failed to retrieve wifiscanner");sendScanResultFailureBroadcastToPackage(packageName);return false;}boolean fromSettingsOrSetupWizard =mWifiPermissionsUtil.checkNetworkSettingsPermission(callingUid)|| mWifiPermissionsUtil.checkNetworkSetupWizardPermission(callingUid);// Check and throttle scan request unless,// a) App has either NETWORK_SETTINGS or NETWORK_SETUP_WIZARD permission.// b) Throttling has been disabled by user.if (!fromSettingsOrSetupWizard && mThrottleEnabled&& shouldScanRequestBeThrottledForApp(callingUid, packageName)) {Log.i(TAG, "Scan request from " + packageName + " throttled");sendScanResultFailureBroadcastToPackage(packageName);return false;}// Create a worksource using the caller's UID.WorkSource workSource = new WorkSource(callingUid, packageName);// Create the scan settings.WifiScanner.ScanSettings settings = new WifiScanner.ScanSettings();// Scan requests from apps with network settings will be of high accuracy type.if (fromSettingsOrSetupWizard) {settings.type = WifiScanner.SCAN_TYPE_HIGH_ACCURACY;}// always do full scanssettings.band = WifiScanner.WIFI_BAND_ALL;settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN| WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;if (mScanningForHiddenNetworksEnabled) {settings.hiddenNetworks.clear();// retrieve the list of hidden network SSIDs from saved network to scan for, if enabled.settings.hiddenNetworks.addAll(mWifiConfigManager.retrieveHiddenNetworkList());// retrieve the list of hidden network SSIDs from Network suggestion to scan for.settings.hiddenNetworks.addAll(mWifiInjector.getWifiNetworkSuggestionsManager().retrieveHiddenNetworkList());}mWifiScanner.startScan(settings, new HandlerExecutor(mHandler),new ScanRequestProxyScanListener(), workSource);return true;}

七、
frameworks/base/wifi/java/android/net/wifi/WifiScanner.java

public void startScan(ScanSettings settings, @Nullable @CallbackExecutor Executor executor,ScanListener listener, WorkSource workSource) {Objects.requireNonNull(listener, "listener cannot be null");int key = addListener(listener, executor);if (key == INVALID_KEY) return;validateChannel();Bundle scanParams = new Bundle();scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
}

可以看到replySucceeded(msg);会返回一个扫描成功的消息。
如果已经在扫描,则把新的扫描请求发送给当前扫描,如果当前没有扫描,则开启新的扫描。
frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java

class DriverStartedState extends State {public boolean processMessage(Message msg) {ClientInfo ci = mClients.get(msg.replyTo);switch (msg.what) {case WifiScanner.CMD_START_SINGLE_SCAN:Bundle scanParams = (Bundle) msg.obj;replySucceeded(msg);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();}}return HANDLED;
void tryToStartNewScan() {if (mPendingScans.size() == 0) { // no pending requestsreturn;}mChannelHelper.updateChannels();// TODO move merging logic to a schedulerWifiNative.ScanSettings settings = new WifiNative.ScanSettings();settings.num_buckets = 1;WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings();bucketSettings.bucket = 0;bucketSettings.period_ms = 0;bucketSettings.report_events = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;ChannelCollection channels = mChannelHelper.createChannelCollection();List<WifiNative.HiddenNetwork> hiddenNetworkList = new ArrayList<>();for (RequestInfo<ScanSettings> entry : mPendingScans) {settings.scanType = mergeScanTypes(settings.scanType, entry.settings.type);channels.addChannels(entry.settings);for (ScanSettings.HiddenNetwork srcNetwork : entry.settings.hiddenNetworks) {WifiNative.HiddenNetwork hiddenNetwork = new WifiNative.HiddenNetwork();hiddenNetwork.ssid = srcNetwork.ssid;hiddenNetworkList.add(hiddenNetwork);}if ((entry.settings.reportEvents & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)!= 0) {bucketSettings.report_events |= WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;}}if (hiddenNetworkList.size() > 0) {settings.hiddenNetworks = new WifiNative.HiddenNetwork[hiddenNetworkList.size()];int numHiddenNetworks = 0;for (WifiNative.HiddenNetwork hiddenNetwork : hiddenNetworkList) {settings.hiddenNetworks[numHiddenNetworks++] = hiddenNetwork;}}channels.fillBucketSettings(bucketSettings, Integer.MAX_VALUE);settings.buckets = new WifiNative.BucketSettings[] {bucketSettings};if (mScannerImplsTracker.startSingleScan(settings)) {// store the active scan settingsmActiveScanSettings = settings;// swap pending and active scan requestsRequestList<ScanSettings> tmp = mActiveScans;mActiveScans = mPendingScans;mPendingScans = tmp;// make sure that the pending list is clearmPendingScans.clear();transitionTo(mScanningState);} else {mWifiMetrics.incrementScanReturnEntry(WifiMetricsProto.WifiLog.SCAN_UNKNOWN, mPendingScans.size());// notify and cancel failed scanssendOpFailedToAllAndClear(mPendingScans, WifiScanner.REASON_UNSPECIFIED,"Failed to start single scan");}
}

八、ScannerImplsTracker --> WifiScannerImpl --> WifiScannerImplFactory

public static final WifiScannerImplFactory DEFAULT_FACTORY = new WifiScannerImplFactory() {public WifiScannerImpl create(Context context, Looper looper, Clock clock,@NonNull String ifaceName) {WifiNative wifiNative = WifiInjector.getInstance().getWifiNative();WifiMonitor wifiMonitor = WifiInjector.getInstance().getWifiMonitor();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);}}};

九、可以看到这俩个代码最后也走到了一起
frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/HalWifiScannerImpl.java
frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java

mWificondScannerDelegate =new WificondScannerImpl(context, wifiNative, wifiMonitor, mChannelHelper,looper, clock);

最后还是调到了WifiNative。逻辑理顺就好了,接下来一定是wifinative去让底层扫描并返回扫描结果

    public boolean startSingleScan(WifiNative.ScanSettings settings,WifiNative.ScanEventHandler eventHandler) {synchronized (mSettingsLock) {for (int i = 0; i < settings.num_buckets; ++i) {WifiNative.BucketSettings bucketSettings = settings.buckets[i];if ((bucketSettings.report_events& WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {reportFullResults = true;}allFreqs.addChannels(bucketSettings);}List<String> hiddenNetworkSSIDSet = new ArrayList<>();if (settings.hiddenNetworks != null) {int numHiddenNetworks =Math.min(settings.hiddenNetworks.length, MAX_HIDDEN_NETWORK_IDS_PER_SCAN);for (int i = 0; i < numHiddenNetworks; i++) {hiddenNetworkSSIDSet.add(settings.hiddenNetworks[i].ssid);}}mLastScanSettings = new LastScanSettings(mClock.getElapsedSinceBootMillis(),reportFullResults, allFreqs, eventHandler);Set<Integer> freqs;if (!allFreqs.isEmpty()) {freqs = allFreqs.getScanFreqs();success = mWifiNative.scan(getIfaceName(), settings.scanType, freqs, hiddenNetworkSSIDSet);} if (success) {mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,mClock.getElapsedSinceBootMillis() + SCAN_TIMEOUT_MS,TIMEOUT_ALARM_TAG, mScanTimeoutListener, mEventHandler);} return true;}}

十、
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java

public boolean scan(@NonNull String ifaceName, @WifiAnnotations.ScanType int scanType, Set<Integer> freqs,List<String> hiddenNetworkSSIDs) {Log.d(TAG, "Scan trigered from WifiNative");List<byte[]> hiddenNetworkSsidsArrays = new ArrayList<>();for (String hiddenNetworkSsid : hiddenNetworkSSIDs) {try {byte[] hiddenSsidBytes = WifiGbk.getRandUtfOrGbkBytes(hiddenNetworkSsid);if (hiddenSsidBytes.length > WifiGbk.MAX_SSID_LENGTH) {Log.e(TAG, "SSID is too long after conversion, skipping this ssid! SSID =" +hiddenNetworkSsid + " , SSID size = " + hiddenSsidBytes.length);continue;}hiddenNetworkSsidsArrays.add(hiddenSsidBytes);} catch (IllegalArgumentException e) {Log.e(TAG, "Illegal argument " + hiddenNetworkSsid, e);continue;}}mIfaceNameforPartialScanResult = ifaceName;boolean mScanDoneFlag = mWifiCondManager.startScan(ifaceName, scanType, freqs, hiddenNetworkSsidsArrays);if (mScanDoneFlag &&((mWifiInjector.getClientModeImpl().isDisconnected()) ||mAllowConnectionOnPartialScanResults)) {schedulePeriodicPartialScanResult();}return mScanDoneFlag;
}

这里通过HIDL到了C代码中
frameworks/base/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java

   public boolean startScan(@NonNull String ifaceName, @WifiAnnotations.ScanType int scanType,@Nullable Set<Integer> freqs, @Nullable List<byte[]> hiddenNetworkSSIDs) {IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);return scannerImpl.scan(settings);return false;}

十一、这里是代码到c++以后的流程,最后把扫描命令发送给了kernel。
system/connectivity/wificond/scanning/scanner_impl.cpp

Status ScannerImpl::scan(const SingleScanSettings& scan_settings,bool* out_success) {if (!CheckIsValid()) {*out_success = false;return Status::ok();}if (scan_started_) {LOG(WARNING) << "Scan already started";}// Only request MAC address randomization when station is not associated.bool request_random_mac =wiphy_features_.supports_random_mac_oneshot_scan &&!client_interface_->IsAssociated();int scan_type = scan_settings.scan_type_;if (!IsScanTypeSupported(scan_settings.scan_type_, wiphy_features_)) {LOG(DEBUG) << "Ignoring scan type because device does not support it";scan_type = SCAN_TYPE_DEFAULT;}// Initialize it with an empty ssid for a wild card scan.vector<vector<uint8_t>> ssids = {{}};vector<vector<uint8_t>> skipped_scan_ssids;for (auto& network : scan_settings.hidden_networks_) {if (ssids.size() + 1 > scan_capabilities_.max_num_scan_ssids) {skipped_scan_ssids.emplace_back(network.ssid_);continue;}ssids.push_back(network.ssid_);}LogSsidList(skipped_scan_ssids, "Skip scan ssid for single scan");vector<uint32_t> freqs;for (auto& channel : scan_settings.channel_settings_) {freqs.push_back(channel.frequency_);}int error_code = 0;if (!scan_utils_->Scan(interface_index_, request_random_mac, scan_type,ssids, freqs, &error_code)) {if (error_code == ENODEV) {nodev_counter_ ++;LOG(WARNING) << "Scan failed with error=nodev. counter=" << nodev_counter_;}if (error_code == ENETDOWN) {enetdown_counter_++;LOG(WARNING) << "Scan failed with error=iface down. counter=" << enetdown_counter_;}CHECK((error_code != ENODEV || nodev_counter_ <= 3) &&(error_code != ENETDOWN || enetdown_counter_ <= 10))<< "Driver is in a bad state, restarting wificond";*out_success = false;return Status::ok();}nodev_counter_ = 0;enetdown_counter_ = 0;scan_started_ = true;*out_success = true;return Status::ok();
}

system/connectivity/wificond/scanning/scan_utils.cpp

bool ScanUtils::Scan(uint32_t interface_index,bool request_random_mac,int scan_type,const vector<vector<uint8_t>>& ssids,const vector<uint32_t>& freqs,int* error_code) {NL80211Packet trigger_scan(netlink_manager_->GetFamilyId(),NL80211_CMD_TRIGGER_SCAN,netlink_manager_->GetSequenceNumber(),getpid());// If we do not use NLM_F_ACK, we only receive a unicast repsonse// when there is an error. If everything is good, scan results notification// will only be sent through multicast.// If NLM_F_ACK is set, there will always be an unicast repsonse, either an// ERROR or an ACK message. The handler will always be called and removed by// NetlinkManager.trigger_scan.AddFlag(NLM_F_ACK);NL80211Attr<uint32_t> if_index_attr(NL80211_ATTR_IFINDEX, interface_index);NL80211NestedAttr ssids_attr(NL80211_ATTR_SCAN_SSIDS);for (size_t i = 0; i < ssids.size(); i++) {ssids_attr.AddAttribute(NL80211Attr<vector<uint8_t>>(i, ssids[i]));}NL80211NestedAttr freqs_attr(NL80211_ATTR_SCAN_FREQUENCIES);for (size_t i = 0; i < freqs.size(); i++) {freqs_attr.AddAttribute(NL80211Attr<uint32_t>(i, freqs[i]));}trigger_scan.AddAttribute(if_index_attr);trigger_scan.AddAttribute(ssids_attr);// An absence of NL80211_ATTR_SCAN_FREQUENCIES attribue informs kernel to// scan all supported frequencies.if (!freqs.empty()) {trigger_scan.AddAttribute(freqs_attr);}uint32_t scan_flags = 0;if (request_random_mac) {scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;}switch (scan_type) {case IWifiScannerImpl::SCAN_TYPE_LOW_SPAN:scan_flags |= NL80211_SCAN_FLAG_LOW_SPAN;break;case IWifiScannerImpl::SCAN_TYPE_LOW_POWER:scan_flags |= NL80211_SCAN_FLAG_LOW_POWER;break;case IWifiScannerImpl::SCAN_TYPE_HIGH_ACCURACY:scan_flags |= NL80211_SCAN_FLAG_HIGH_ACCURACY;break;case IWifiScannerImpl::SCAN_TYPE_DEFAULT:break;default:CHECK(0) << "Invalid scan type received: " << scan_type;}if (scan_flags) {trigger_scan.AddAttribute(NL80211Attr<uint32_t>(NL80211_ATTR_SCAN_FLAGS,scan_flags));}// We are receiving an ERROR/ACK message instead of the actual// scan results here, so it is OK to expect a timely response because// kernel is supposed to send the ERROR/ACK back before the scan starts.vector<unique_ptr<const NL80211Packet>> response;if (!netlink_manager_->SendMessageAndGetAckOrError(trigger_scan,error_code)) {// Logging is done inside |SendMessageAndGetAckOrError|.return false;}if (*error_code != 0) {LOG(ERROR) << "NL80211_CMD_TRIGGER_SCAN failed: " << strerror(*error_code);return false;}return true;
}

system/connectivity/wificond/net/netlink_manager.cpp

bool NetlinkManager::SendMessageAndGetAckOrError(const NL80211Packet& packet,int* error_code) {unique_ptr<const NL80211Packet> response;if (!SendMessageAndGetSingleResponseOrError(packet, &response)) {return false;}uint16_t type = response->GetMessageType();if (type != NLMSG_ERROR) {LOG(ERROR) << "Receive unexpected message type :" << type;return false;}*error_code = response->GetErrorCode();return true;
}
bool NetlinkManager::SendMessageAndGetSingleResponseOrError(const NL80211Packet& packet,unique_ptr<const NL80211Packet>* response) {vector<unique_ptr<const NL80211Packet>> response_vec;if (!SendMessageAndGetResponses(packet, &response_vec)) {return false;}if (response_vec.size() != 1) {LOG(ERROR) << "Unexpected response size: " << response_vec.size();return false;}*response = std::move(response_vec[0]);return true;
}
bool NetlinkManager::SendMessageAndGetResponses(const NL80211Packet& packet,vector<unique_ptr<const NL80211Packet>>* response) {if (!SendMessageInternal(packet, sync_netlink_fd_.get())) {return false;}// Polling netlink socket, waiting for GetFamily reply.struct pollfd netlink_output;memset(&netlink_output, 0, sizeof(netlink_output));netlink_output.fd = sync_netlink_fd_.get();netlink_output.events = POLLIN;uint32_t sequence = packet.GetMessageSequence();int time_remaining = kMaximumNetlinkMessageWaitMilliSeconds;// Multipart messages may come with seperated datagrams, ending with a// NLMSG_DONE message.// ReceivePacketAndRunHandler() will remove the handler after receiving a// NLMSG_DONE message.message_handlers_[sequence] = std::bind(AppendPacket, response, _1);while (time_remaining > 0 &&message_handlers_.find(sequence) != message_handlers_.end()) {nsecs_t interval = systemTime(SYSTEM_TIME_MONOTONIC);int poll_return = poll(&netlink_output,1,time_remaining);if (poll_return == 0) {LOG(ERROR) << "Failed to poll netlink fd: time out ";message_handlers_.erase(sequence);return false;} else if (poll_return == -1) {PLOG(ERROR) << "Failed to poll netlink fd";message_handlers_.erase(sequence);return false;}ReceivePacketAndRunHandler(sync_netlink_fd_.get());interval = systemTime(SYSTEM_TIME_MONOTONIC) - interval;time_remaining -= static_cast<int>(ns2ms(interval));}if (time_remaining <= 0) {LOG(ERROR) << "Timeout waiting for netlink reply messages";message_handlers_.erase(sequence);return false;}return true;
}
bool NetlinkManager::SendMessageInternal(const NL80211Packet& packet, int fd) {const vector<uint8_t>& data = packet.GetConstData();ssize_t bytes_sent =TEMP_FAILURE_RETRY(send(fd, data.data(), data.size(), 0));if (bytes_sent == -1) {PLOG(ERROR) << "Failed to send netlink message";return false;}return true;
}

Android 11 WiFi扫描流程梳理相关推荐

  1. (四十四)Android O WiFi启动流程梳理

    前言:最近又重新拿起来WiFi模块,从WiFi 各个流程梳理开始复习一下. 参考博客:https://blog.csdn.net/csdn_of_coder/article/details/51541 ...

  2. Android 11 WiFi启动流程

    欢迎大家一起学习探讨通信之WLAN.本节重点基于Android11分析讨论WiFi开启流程.用户点击一下"WiFi"开关,WiFi开启了.看似如此简单操作,但系统流程调用还是相当复 ...

  3. Android 11 WiFi开启流程

    从刚接触WiFi时跟过wifi的开启流程,当时还是android9.到了Android11代码架构有了不小的改动,在这里重新梳理一遍,便于在工作中更快速的跟踪代码. 一.Settings里改动不大,还 ...

  4. 第六章 Wi-Fi扫描流程

    系列文章目录 第一章 国内下载AOSP最新源码的方法 第二章 下载AOSP WiFi相关的代码 第三章 将源码导入Android Studio(无需编译idegen) 文章目录 系列文章目录 前言 一 ...

  5. android p wifi一直在扫描_(一百六十八)Android P wifi 扫描失败结果上报流程梳理-扫描上报梳理②...

    接(一百五十五)Android P wifi 扫描失败结果上报流程梳理-扫描上报梳理 扫描失败上报梳理发现梳理的差了很多,特补充 1.WificondScannerImpl @Override pub ...

  6. android wifi连接流程,(九十三) Android O 连接WiFi AP流程梳理续——保存网络-Go语言中文社区...

    前言: 之前在(五十五)Android O 连接WiFi AP流程梳理 梳理连接流程梳理到SupplicantStaNetworkHal 然后没梳理的下去,现在继续梳理下. 之前梳理的时序图 1.流程 ...

  7. (九十三) Android O 连接WiFi AP流程梳理续——保存网络

    前言: 之前在(五十五)Android O 连接WiFi AP流程梳理 梳理连接流程梳理到SupplicantStaNetworkHal 然后没梳理的下去,现在继续梳理下. 之前梳理的时序图 1.流程 ...

  8. android移植wifi驱动流程porting

    android载入wifi驱动流程 wifi_load_driver check_wifi_chip_type_string get_wifi_device_id save_wifi_chip_typ ...

  9. Android R WiFi热点流程浅析

    Android R WiFi热点流程浅析 Android上的WiFi SoftAp功能是用户常用的功能之一,它能让我们分享手机的网络给其他设备使用. 那Android系统是如何实现SoftAp的呢,这 ...

最新文章

  1. 2021天津高考成绩查询时间26号几点,2021年天津高考成绩查询时间安排 什么时候出分...
  2. PostgreSQL GIN multi-key search 优化
  3. Groovy的春天从Java7诞生那日开始
  4. mysql 5.5.39 安装_CentOS7.2安装mysql5.5.39
  5. codeforces 939C Convenient For Everybody 简直羞耻
  6. 在运行时修补Java
  7. Hash表的扩容(转载)
  8. python 消息队列 get是从队首还是队尾取东西_从零开始Python对redis作为消息队列的使用...
  9. 1.5编程基础之循环控制 21 角谷猜想
  10. 24. PE结构-PE详解之基址重定位详解
  11. 修改Chrome浏览器默认背景颜色为浅绿色(转)
  12. IPSec之security acl
  13. C++内存管理之shared_ptr
  14. Python类的继承
  15. 【微机汇编语言学习笔记(四)】十进制数的ASCII转换为BCD码
  16. 【零散知识点总结2】
  17. 物联网产业前景看涨然5大挑战在眼前
  18. 分组查询:group by
  19. 夏普电视显示网络无法连接到服务器,彻底解决SQL SERVER 2005无法远程连接的问题...
  20. 叶酸修饰靶向性紫杉醇 PGA-TAXOL/羟基靶向修饰透明质酸接枝姜黄素 OH-HA-CUR/羧基靶向修饰透明质酸接枝姜黄素 COOH-HA-CUR

热门文章

  1. python图片读取优化_Python下图片的高斯模糊化的优化
  2. html怎么让div一直旋转,css3实现元素不停旋转
  3. 艾美捷卵清蛋白(OVA),高纯度低内毒素介绍
  4. 面试官角度看应聘:问题到底出在哪?(下)
  5. 启用Ubuntu 服务器上的 mDNS
  6. MacBook Air M1 macOS配置快捷键入门指南
  7. ## shell例子-expect-trap-select
  8. 二季度华为手机增速大幅放缓,预期下半年将恢复快速增长
  9. java 枚举值属性_获取枚举值的属性
  10. cocoscreator设置层级zIndex使用注意事项