[Android]Android P(9) WIFI学习笔记 - HAL (2)

前文回顾

前言

  1. 基于Android P源码学习;
  2. 代码片为了方便阅读段经过删、裁减,请以实际源码为准;

本篇旨在补全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_indexOnRegDomainChangedHandler移除了,即一个反注册的动作;

时序图如下:

在这里插入图片描述

小结

得益于关闭时不需要等待底层上报最终结果,以及对于部分进程采用了kill这种粗暴操作(wpa_supplicant),关闭WIFI流程相对于打开WIFI简单不少;
如下是整个HAL部分的时序图:

在这里插入图片描述

下一步计划:

  • 继续梳理驱动、内核层的设计;
  • 梳理连接、断开WIFI的逻辑;

两者没有严格优先级,以个人兴趣与工作要求为准;

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值