上一篇我们梳理了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 {
@Override
public 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 happen
impl.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() {
@Override
public 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 scans
settings.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 requests
return;
}
mChannelHelper.updateChannels();
// TODO move merging logic to a scheduler
WifiNative.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 settings
mActiveScanSettings = settings;
// swap pending and active scan requests
RequestList<ScanSettings> tmp = mActiveScans;
mActiveScans = mPendingScans;
mPendingScans = tmp;
// make sure that the pending list is clear
mPendingScans.clear();
transitionTo(mScanningState);
} else {
mWifiMetrics.incrementScanReturnEntry(
WifiMetricsProto.WifiLog.SCAN_UNKNOWN, mPendingScans.size());
// notify and cancel failed scans
sendOpFailedToAllAndClear(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;
}