目录
前文回顾
前言
- 基于Android P源码学习;
- 代码片为了方便阅读段经过删、裁减,请以实际源码为准;
本篇旨在补全WIFI学习笔记 - HAL (1)中未提及的关闭WIFI部分;
入口
同样,HAL部分从WifiNative
开始
WifiNative
由WIFI学习笔记 - Framework (2)可知,调用的是teardownInterface()
方法:
public void teardownInterface(@NonNull String ifaceName) {
synchronized (mLock) {
final Iface iface = mIfaceMgr.getIface(ifaceName);
...
//此处我们暂不讨论作为热点或桥接模式,仅讨论网卡作为STA模式下的逻辑:
if (iface.type == Iface.IFACE_TYPE_STA) {
if (!removeStaIface(iface)) {
return;
}
} else if (iface.type == Iface.IFACE_TYPE_AP) {
...
} else if (iface.type == Iface.IFACE_TYPE_BRIDGE) {
...
}
}
}
private boolean removeStaIface(@NonNull Iface iface) {
synchronized (mLock) {
if (mWifiVendorHal.isVendorHalSupported()) {
return mWifiVendorHal.removeStaIface(iface.name);
} else {
...
}
}
}
可见关键调用方法是mWifiVendorHal.removeStaIface()
。
代码路径:frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiVendorHal.java
public boolean removeStaIface(@NonNull String ifaceName) {
synchronized (sLock) {
//从mIWifiStaIfaces中查找key为ifaceName的IWifiStaIface实例
IWifiStaIface iface = getStaIface(ifaceName);
//如果没找到,直接返回false
if (iface == null) return boolResult(false);
//关键调用,其返回值会作为本方法的返回结果;
if (!mHalDeviceManager.removeIface((IWifiIface) iface)) {
return boolResult(false);
}
//删除mIWifiStaIfaces中的对应实例
mIWifiStaIfaces.remove(ifaceName);
return true;
}
}
代码路径:frameworks/opt/net/wifi/service/java/com/android/server/wifi/HalDeviceManager.java
private boolean removeIfaceInternal(IWifiIface iface) {
String name = getName(iface);
int type = getType(iface);
...
synchronized (mLock) {
...
IWifiChip chip = getChip(iface);
...
WifiStatus status = null;
try {
switch (type) {
case IfaceType.STA:
status = chip.removeStaIface(name);
break;
...
}
} catch (RemoteException e) {
Log.e(TAG, "IWifiChip.removeXxxIface exception: " + e);
}
//通知所有注册的iface对应的InterfaceDestroyedListener调用onDestroyed()方法
dispatchDestroyedListeners(name, type);
if (status != null && status.code == WifiStatusCode.SUCCESS) {
return true;
} else {
return false;
}
}
}
可见,和打开WIFI的逻辑相似,也走到了IWifiChip.removeStaIface()
;
同时需要注意这个dispatchDestroyedListeners()
方法,其会通过之前在打开WIFI时调用的createStaIface()
注册的回调走到WifiNative.onClientInterfaceDestroyed()
方法,并最终调用如下方法:
IWificond.disableSupplicant()
IWificond.tearDownInterfaces()
照例,先附上这一段逻辑的时序图:(虚线部分即为上述dispatchDestroyedListeners()
方法回调的逻辑)
IWifiChip
代码路径:hardware/interfaces/wifi/1.2/default/wifi_chip.cpp
Return<void> WifiChip::removeStaIface(const hidl_string& ifname,
removeStaIface_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::removeStaIfaceInternal, hidl_status_cb,
ifname);
}
同样是validateAndCall()
模板函数,这里就不赘述了,直接跳到WifiChip::removeStaIfaceInternal()
函数:
WifiStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) {
const auto iface = findUsingName(sta_ifaces_, ifname);
if (!iface.get()) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
if (findUsingName(created_sta_ifaces_, ifname) != nullptr) {
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->QcRemoveInterface(getWlan0IfaceName(), ifname);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to remove interface: " << ifname << " "
<< legacyErrorToString(legacy_status);
}
invalidateAndClear(created_sta_ifaces_, iface);
}
invalidateAndClear(sta_ifaces_, iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) {
LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
}
}
return createWifiStatus(WifiStatusCode::SUCCESS);
}
和打开WIFI时的QcAddInterface()
对应,关闭WIFI则是调用QcRemoveInterface()
:
代码路径:hardware/interfaces/wifi/1.2/default/wifi_legacy_hal.cpp
wifi_error WifiLegacyHal::QcRemoveInterface(const std::string& iface_name,
const std::string& ifname) {
wifi_error status = global_func_table_.wifi_add_or_remove_virtual_intf(
getIfaceHandle(iface_name),
ifname.c_str(), 0, false);
if (status == WIFI_SUCCESS) {
// refresh list of handlers now.
iface_name_to_handle_.clear();
status = retrieveIfaceHandles();
}
return status;
}
这里又回到和打开WIFI一样的函数调用了:wifi_add_or_remove_virtual_intf
,区别只是最后一个蚕食为false
:
代码路径:hardware/qcom/wlan/qcwcn/wifi_hal/wificonfig.cpp
wifi_error wifi_add_or_remove_virtual_intf(wifi_interface_handle iface,
const char* ifname, u32 iface_type,
bool create)
{
wifi_error ret;
WiFiConfigCommand *wifiConfigCommand;
interface_info *ifaceInfo = getIfaceInfo(iface);
wifi_handle wifiHandle = getWifiHandle(iface);
wifiConfigCommand = new WiFiConfigCommand(wifiHandle, get_requestid(), 0, 0);
if (wifiConfigCommand == NULL) {
return WIFI_ERROR_UNKNOWN;
}
if (create) {
...
} else {
wifiConfigCommand->create_generic(NL80211_CMD_DEL_INTERFACE);
wifiConfigCommand->put_u32(NL80211_ATTR_IFINDEX, if_nametoindex(ifname));
}
/* Send the NL msg. */
wifiConfigCommand->waitForRsp(false);
ret = wifiConfigCommand->requestEvent();
if (ret != WIFI_SUCCESS) {
ALOGE("wifi_add_or_remove_virtual_intf: requestEvent Error:%d", ret);
}
done:
delete wifiConfigCommand;
return ret;
}
可以看到,这里依旧是通过Netlink发送消息给到驱动层,只是消息变为了NL80211_CMD_DEL_INTERFACE
IWifiChip
部分时序图比较简单,如图:
IWifiCond
前面提到,IWifiCond
在关闭WIFI的流程中主要负责响应如下两个函数调用:
IWificond.disableSupplicant()
IWificond.tearDownInterfaces()
事实上,关闭WIFI相较于打开WIFI简单很多,个人认为主要是由于,相较于打开WIFI中复杂的wpa_supplicant
部分逻辑,关闭WIFI时采用的是通知wificond
进程发送kill信号给wpa_supplicant
,因此函数调用简单很多;同时,由于关闭不需要等待驱动状态返回,因此可以做到“上层先关,底层慢慢关”的效果;
接下来,简单分析下这两个函数在wificond
进程中的实现:
IWificond.disableSupplicant()
代码路径:system/connectivity/wificond/server.cpp
Status Server::disableSupplicant(bool* success) {
*success = supplicant_manager_->StopSupplicant();
return Status::ok();
}
supplicant_manager_
是类型为SupplicantManager
的变量指针,后者的声明是在frameworks/opt/net/wifi/libwifi_system/include/wifi_system/supplicant_manager.h
中的结构体,而函数stopSupplicant()
的实现则在frameworks/opt/net/wifi/libwifi_system/supplicant_manager.cpp
中:
bool SupplicantManager::StopSupplicant() {
char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
int count = 50; /* wait at most 5 seconds for completion */
/* Check whether supplicant already stopped */
if (property_get(kSupplicantInitProperty, supp_status, NULL) &&
strcmp(supp_status, "stopped") == 0) {
return true;
}
property_set("ctl.stop", kSupplicantServiceName);
sched_yield();
while (count-- > 0) {
if (property_get(kSupplicantInitProperty, supp_status, NULL)) {
if (strcmp(supp_status, "stopped") == 0) return true;
}
usleep(100000);
}
LOG(ERROR) << "Failed to stop supplicant";
return false;
}
简单粗暴,通过写"wpa_supplicant"
到属性"ctl.stop"
来通知init
进程kill掉wpa_supplicant
进程;
IWificond.tearDownInterfaces()
代码路径:system/connectivity/wificond/server.cpp
Status Server::tearDownInterfaces() {
...
MarkDownAllInterfaces();
netlink_utils_->UnsubscribeRegDomainChange(wiphy_index_);
return Status::ok();
}
MarkDownAllInterfaces()
函数会借助InterfaceTool.SetUpState()
,后者是声明在frameworks/opt/net/wifi/libwifi_system_iface/include/wifi_system/interface_tool.h
中的结构体,而SetUpState()
函数实现则在frameworks/opt/net/wifi/libwifi_system_iface/interface_tool.cpp
中:
bool InterfaceTool::SetUpState(const char* if_name, bool request_up) {
base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
if (sock.get() < 0) {
LOG(ERROR) << "Failed to open socket to set up/down state ("
<< strerror(errno) << ")";
return false;
}
struct ifreq ifr;
if (!GetIfState(if_name, sock.get(), &ifr)) {
return false; // logging done internally
}
const bool currently_up = ifr.ifr_flags & IFF_UP;
if (currently_up == request_up) {
return true;
}
if (request_up) {
ifr.ifr_flags |= IFF_UP;
} else {
ifr.ifr_flags &= ~IFF_UP;
}
if (TEMP_FAILURE_RETRY(ioctl(sock.get(), SIOCSIFFLAGS, &ifr)) != 0) {
LOG(ERROR) << "Could not set interface flags for " << if_name
<< " (" << strerror(errno) << ")";
return false;
}
return true;
}
可见,是通过向inet socket发送SIOCSIFFLAGS的ioctl系统调用通知关闭网络接口;
这里涉及到内核层的处理了,暂不展开,只需知道此处就是通知内核删除对应iface即可;
后续将驱动、内核时再详细介绍;
然后来到UnsubscribeRegDomainChange()
:
代码路径:system/connectivity/wificond/net/netlink_utils.cpp
void NetlinkUtils::UnsubscribeRegDomainChange(uint32_t wiphy_index) {
netlink_manager_->UnsubscribeRegDomainChange(wiphy_index);
}
代码路径:system/connectivity/wificond/net/netlink_manager.cpp
void NetlinkManager::UnsubscribeRegDomainChange(uint32_t wiphy_index) {
on_reg_domain_changed_handler_.erase(wiphy_index);
}
可见只是将键为wiphy_index
的OnRegDomainChangedHandler
移除了,即一个反注册的动作;
时序图如下:
小结
得益于关闭时不需要等待底层上报最终结果,以及对于部分进程采用了kill这种粗暴操作(wpa_supplicant
),关闭WIFI流程相对于打开WIFI简单不少;
如下是整个HAL部分的时序图:
下一步计划:
- 继续梳理驱动、内核层的设计;
- 梳理连接、断开WIFI的逻辑;
两者没有严格优先级,以个人兴趣与工作要求为准;