我们通过代码分析wificond的scan流程,在WifiScanningService的startScan流程分析中我们分析了HAL层以上的流程,下面我们继续分析HAL层的流程,首先是ScannerImpl的scan方法:
//system/connectivity/wificond/scanning/ScannerImpl.h
class ScannerImpl : public android::net::wifi::nl80211::BnWifiScannerImpl {
private:
ScanUtils* const scan_utils_;
}
//system/connectivity/wificond/scanning/ScannerImpl.cpp
class ScannerImpl : public android::net::wifi::nl80211::BnWifiScannerImpl {
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_;
//wiphy_features_是硬件层直接返回的当前WLAN芯片支持的扫描类型
//如果请求的类型不被硬件支持,则回落为SCAN_TYPE_DEFAULT
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 = {{}};
//wiphy_features_是硬件层直接返回的当前WLAN芯片支持的扫描类型
//如果请求的类型不被硬件支持,则回落为SCAN_TYPE_DEFAULT
vector<vector<uint8_t>> skipped_scan_ssids;
vector<vector<uint8_t>> skipped_long_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;
}
if (network.ssid_.size() > 32) {
skipped_long_ssids.emplace_back(network.ssid_);
continue;
}
ssids.push_back(network.ssid_);
}
LogSsidList(skipped_scan_ssids, "Skip scan ssid for single scan");
LogSsidList(skipped_long_ssids, "Skip too long ssid");
//将扫描需要覆盖的信道频率添加到freqs向量中
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,
scan_settings.enable_6ghz_rnr_, ssids, freqs, &error_code)) { //调用ScanUtils的Scan方法
if (error_code == ENODEV) {
nodev_counter_ ++;
LOG(WARNING) << "Scan failed with error=nodev. counter=" << nodev_counter_;
}
CHECK(error_code != ENODEV || nodev_counter_ <= 3)
<< "Driver is in a bad state, restarting wificond";
*out_success = false;
return Status::ok();
}
nodev_counter_ = 0;
scan_started_ = true;
*out_success = true;
return Status::ok();
}
}
上面的函数实现,由如下几个关键点:
-
扫描请求中设定的扫描类型,如果与硬件上报支持的类型不匹配,则后续扫描类型会回落为SCAN_TYPE_DEFAULT;
-
隐藏网络扫描数量有限制,最大为max_num_scan_ssids(通过NL80211_ATTR_MAX_NUM_SCAN_SSIDS属性获取)
-
信道频率直接转存到freqs中,没有过滤;
-
处理完数据后,将参数传入scan_utils_->Scan的函数调用中,继续后面的逻辑;
//system/connectivity/wificond/scan_utils.h
class ScanUtils {
private:
NetlinkManager* netlink_manager_;
}
//system/connectivity/wificond/scan_utils.cpp
bool ScanUtils::Scan(uint32_t interface_index,
bool request_random_mac,
int scan_type,
bool enable_6ghz_rnr,
const vector<vector<uint8_t>>& ssids,
const vector<uint32_t>& freqs,
int* error_code) {
//构造一个NL80211Packet,命令为NL80211_CMD_TRIGGER_SCAN
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,key为NL80211_ATTR_IFINDEX,value为interface_index
NL80211Attr<uint32_t> if_index_attr(NL80211_ATTR_IFINDEX, interface_index);
//构造NL80211Attr,key为NL80211_ATTR_IFINDEX,value为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]));
}
//频率添加方式与上面ssids_attr类似
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]));
}
//将上面构造的NL80211Attr/NL80211NestedAttr添加进trigger_scan这个NL80211Packet
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;
//ScannerImpl::scan中处理过的一些参数,在这里以scan_flags传递
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 (enable_6ghz_rnr) {
scan_flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ;
}
//最后,将scan_flags封装进trigger_scan这个NL80211Packet
if (scan_flags) {
trigger_scan.AddAttribute(
NL80211Attr<uint32_t>(NL80211_ATTR_SCAN_FLAGS,
scan_flags));
LOG(DEBUG) << "Triggering scan with scan_flag=" << 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)) { //调用NetlinkManager的SendMessageAndGetAckOrError方法
// 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;
}
可见,ScanUtils::Scan大部分逻辑还是参数的处理、封装,最后整合到名为trigger_scan的一个NL80211Packet结构体中,并通过netlink_manager_->SendMessageAndGetAckOrError发送出去;
//system/connectivity/wificond/net/netlink_manager.h
class NetlinkManager {
}
//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(), sync_netlink_destination_)) {
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:" << sync_netlink_fd_.get() << "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;
}
上面代码是比较多,但是调用路线很明显:SendMessageAndGetAckOrError -> SendMessageAndGetSingleResponseOrError -> SendMessageAndGetResponses -> SendMessageInternal & ReceivePacketAndRunHandler,其中SendMessageInternal的代码如下
//system/connectivity/wificond/net/netlink_manager.cpp
bool NetlinkManager::SendMessageInternal(const NL80211Packet& packet, int fd,
InterceptedSocket nl_destination) {
const vector<uint8_t>& data = packet.GetConstData();
struct sockaddr_nl sa = nl_destination;
ssize_t bytes_sent = TEMP_FAILURE_RETRY(
sendto(fd, data.data(), data.size(), 0, reinterpret_cast<struct sockaddr*>(&sa), sizeof(sa))
); //通过socket将封装好的消息数据发给内核
if (bytes_sent == -1) {
PLOG(ERROR) << "Failed to send netlink message";
CHECK(!nlinterceptor::isEnabled()) << "Interceptor died, restarting wificond...";
return false;
}
return true;
}
在SendMessageInternal中使用sendto函数将封装好的消息数据发给内核的wireless驱动,之后就是Linux内核的处理了。
ReceivePacketAndRunHandler的代码如下:
//system/connectivity/wificond/net/netlink_manager.cpp
void NetlinkManager::ReceivePacketAndRunHandler(int fd) {
ssize_t len = read(fd, ReceiveBuffer, kReceiveBufferSize); //通过socket读取内部数据
if (len == -1) {
LOG(ERROR) << "Failed to read packet from buffer on fd: " << fd;
perror(" netlink error ");
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);
}
}
}
在ReceivePacketAndRunHandler中使用read函数读取内核的wireless驱动的消息数据,然后对消息的解析、分发、处理。