目录

  • 前文回顾
  • 前言
  • 入口
    • WifiNative
      • 初始化
      • 打开WIFI
    • IWifiChip
    • IWifiCond
    • ISupplicant

前文回顾

  • WIFI学习笔记 - Framework (1)
  • WIFI学习笔记 - Framework (2)

前言

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

入口

根据前两篇的分析结果,调用栈都汇聚到了WifiNative:

打开Wifi:
mWifiNative.setupInterfaceForClientMode(false, mWifiNativeInterfaceCallback)
关闭Wifi:
mWifiNative.teardownInterface(mClientInterfaceName);

因此我们从WifiNative开始;

照例,我仍以“打开Wifi”为例分析(后续会补上“关闭Wifi”的部分,但仅会重点介绍差异部分)

WifiNative

初始化

构造方法只有一个:

    public WifiNative(WifiVendorHal vendorHal,SupplicantStaIfaceHal staIfaceHal, HostapdHal hostapdHal,WificondControl condControl, WifiMonitor wifiMonitor,INetworkManagementService nwService,PropertyService propertyService, WifiMetrics wifiMetrics,Handler handler) {...}

构造WifiNative对象的地方依旧是WifiInjector:

        mWifiNative = new WifiNative(mWifiVendorHal, mSupplicantStaIfaceHal, mHostapdHal, mWificondControl,mWifiMonitor, mNwManagementService, mPropertyService, mWifiMetrics,new Handler(mWifiStateMachineHandlerThread.getLooper()));

这里参数很多,需要逐一介绍下,以便于后续深入HAL的分析:

  • WifiVendorHal:mWifiVendorHal

    • android.hardware.wifi@1.0的HAL实现服务交互的工具类;
  • SupplicantStaIfaceHal:mSupplicantStaIfaceHal

    • android.hardware.wifi.supplicant@1.0的HAL实现服务交互的工具类;
    • 与vendor自定义的,有相关功能的HAL交互,例如vendor.qti.hardware.wifi.supplicant@2.0
  • HostapdHal:mHostapdHal

    • android.hardware.wifi.hostapd@1.0的HAL实现服务交互的工具类;
    • 与vendor自定义的,有相关功能的HAL交互,例如vendor.qti.hardware.wifi.hostapd@1.0
  • WificondControl:mWificondControl

    • 负责通过Binder与wificond进程交互(IWificond
  • WifiMonitor mWifiMonitor

    • 一个负责收集、分发wpa_supplicant状态的工具类;
  • INetworkManagementService:mNwManagementService

    • INetworkManagementService实现类的的客户端实例
  • PropertyService:mPropertyService

    • 类型为PropertyService的接口,实现类型为SystemPropertyService,本质是对android.os.SystemPropertiesget/set方法进行非静态封装;
  • WifiMetrics:mWifiMetrics

    • 用于记录WIFI行为,包括连接、断开事件,已保存网络个数,开放网络个数等的业务类;
  • Handler:new Handler(mWifiStateMachineHandlerThread.getLooper())

    • 用于处理异步消息的Handler

由此可见,负责与HAL交互的,更多是前面4个参数:mWifiVendorHal,mSupplicantStaIfaceHal,mHostapdHal,mWificondControl

关于这些模块的详细分析计划在后期再更新,当前仅着眼于开、关WIFI调用栈的HAL部分;

打开WIFI

即:setupInterfaceForClientMode()

public String setupInterfaceForClientMode(boolean lowPrioritySta,@NonNull InterfaceCallback interfaceCallback) {synchronized (mLock) {.../** mIfaceMgr为IfaceManager的实例对象,内部维护了一个HashMap<Integer, Iface>,* 用于管理Iface的增、删、查等操作;* allocateIface方法即为上述的“增”。* 但是需要注意,这里的“增”只是Framework层面的构造了一个Iface对象并添加到HashMap* 中,并没有发送请求到HAL去真正创建一个Iface。*/Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA);...iface.externalListener = interfaceCallback;/** 创建Iface名称,如果Vendor HAL不存在,则取属性"wifi.interface"* 如果属性没设置,返回"wlan0"*/iface.name = createStaIface(iface, lowPrioritySta);.../** 通知wificond调用createClientInterface创建iface,返回类型为IClientInterface* 的实例对象;*/if (mWificondControl.setupInterfaceForClientMode(iface.name) == null) {teardownInterface(iface.name);return null;}/** 根据不同的wpa_supplicant HAL版本决定不同的逻辑:*  - v1.1会构造一个ISupplicant.IfaceInfo,并通过addInterface添加到*    wpa_supplicant interfaces,并从其返回结果中获取到对应的*    ISupplicantIface;*  - v1.0会通过listInterfaces获取所有的ISupplicant.IfaceInfo并*    遍历,以找到匹配的结果,并再通过getInterface获取对应的*    ISupplicantIface;* 然后,创建一个事件监听回调,并传递给wpa_supplicant,使其在STA模式* 下状态发生改变时会触发回调,而该回调会进一步通知到WifiMonitor;* */if (!mSupplicantStaIfaceHal.setupIface(iface.name)) {teardownInterface(iface.name);return null;}iface.networkObserver = new NetworkObserverInternal(iface.id);/** 调用INetworkManagementService的registerObserver注册连接状态事件回调*/if (!registerNetworkObserver(iface.networkObserver)) {teardownInterface(iface.name);return null;}//注册WifiMonitor回调mWifiMonitor.startMonitoring(iface.name);//立即上报一次iface的状态;onInterfaceStateChanged(iface, isInterfaceUp(iface.name));//重置一些状态,包括IPv4地址、IPv6扩展支持等;initializeNwParamsForClientInterface(iface.name);return iface.name;}}

调用时序图参考如下:

可见,打开WIFI的调用过程中,有三个地方需要与HAL交互:

  • IWifiChip.createStaIface()
  • IWificond.createClientInterface()
  • ISupplicant:
    • (V1.1) ISupplicant.addInterface()
    • (V1.0) ISupplicant.listInterfaces() / ISupplicant.getInterfaces()

目前使用的机器走的是V1.1,因此后续以V1.1为例进行分析;

接下来逐一介绍:

IWifiChip

实现IWifiChip接口的代码路径为:hardware/interfaces/wifi/1.2/default/wifi_chip.cpp

Return<void> WifiChip::createStaIface(createStaIface_cb hidl_status_cb) {return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,&WifiChip::createStaIfaceInternal, hidl_status_cb);
}

validateAndCall()是一个模板函数:

// Use for HIDL methods which return instance of WifiStatus and a single return
// value.
template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args>
Return<void> validateAndCall(ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,const std::function<void(const WifiStatus&, ReturnT)>& hidl_cb,Args&&... args) {const auto lock = hidl_sync_util::acquireGlobalLock();if (obj->isValid()) {const auto& ret_pair = (obj->*work)(std::forward<Args>(args)...);const WifiStatus& status = std::get<0>(ret_pair);const auto& ret_value = std::get<1>(ret_pair);hidl_cb(status, ret_value);} else {hidl_cb(createWifiStatus(status_code_if_invalid),typename std::remove_reference<ReturnT>::type());}return Void();
}

直接展开模板函数可得:

Return<void> WifiChip::createStaIface(createStaIface_cb hidl_status_cb) {const auto lock = hidl_sync_util::acquireGlobalLock();if (isValid()) {const auto& ret_pair = createStaIfaceInternal();const WifiStatus& status = std::get<0>(ret_pair);const auto& ret_value = std::get<1>(ret_pair);hidl_status_cb(status, ret_value);} else {hidl_status_cb(createWifiStatus(WifiStatusCode::ERROR_WIFI_CHIP_INVALID),typename std::remove_reference<ReturnT>::type());}return Void();
}

可见,返回结果是由createStaIfaceInternal()函数提供;

std::pair<WifiStatus, sp<IWifiStaIface>> WifiChip::createStaIfaceInternal() {//如果当前工作模式不支持指定类型(此处为STA),则返回状态码ERROR_NOT_AVAILABLE,iface返回nullif (!canCurrentModeSupportIfaceOfType(IfaceType::STA)) {return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};}bool iface_created = false;/** 获取iface名称,默认返回wlan0(属性wifi.interface),如果wlan0已经被使用,返回* wlan1(属性wifi.concurrent.interface)* 若wlan1被使用,则返回wlan2(属性wifi.interface.2)* 这里介绍下被使用的情况:*     wlan0被ap热点占用(部分设备支持ap与wifi同时打开,这种情况下就会出现一个wlan0,* 一个wlan1)*     wlan0被2.4G热点占用,wlan1被5G热点占用,此时打开wifi就会走wlan2*/std::string ifname = allocateApOrStaIfaceName();/* * 检查这个iface名称是否有效,返回0表示:* 1. socket通信建立失败 (低概率)* 2. iface尚未创建*/if (!if_nametoindex(ifname.c_str())) {legacy_hal::wifi_error legacy_status =legacy_hal_.lock()->QcAddInterface(getWlan0IfaceName(), ifname,(uint32_t)IfaceType::STA);if (legacy_status != legacy_hal::WIFI_SUCCESS) {return {createWifiStatusFromLegacyError(legacy_status), {}};}iface_created = true;}//构造返回需要的IWifiIface(IWifiStaIface)sp<WifiStaIface> iface = new WifiStaIface(ifname, legacy_hal_);sta_ifaces_.push_back(iface);//如果是新创建的iface,则添加到created_sta_ifaces_向量中if (iface_created) created_sta_ifaces_.push_back(iface);for (const auto& callback : event_cb_handler_.getCallbacks()) {if (!callback->onIfaceAdded(IfaceType::STA, ifname).isOk()) {LOG(ERROR) << "Failed to invoke onIfaceAdded callback";}}//返回SUCCESS状态码以及iface实例return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
}

如上分析可知:

  • 创建iface的核心方法在QcAddInterface()函数中
  • sta_ifaces_向量中保存了所有创建的WifiStaIfacecreated_sta_ifaces_向量中仅保存随之创建了iface的WifiStaIface

继续查看QcAddInterface()函数实现:
代码路径:hardware/interfaces/wifi/1.2/default/wifi_legacy_hal.cpp

wifi_error WifiLegacyHal::QcAddInterface(const std::string& iface_name,const std::string& new_ifname,uint32_t type) {//global_func_table_.wifi_add_or_remove_virtual_intf即为wificonfig.cpp中//wifi_add_or_remove_virtual_intf函数实现;wifi_error status = global_func_table_.wifi_add_or_remove_virtual_intf(getIfaceHandle(iface_name),new_ifname.c_str(), type, true);if (status == WIFI_SUCCESS) {// refresh list of handlers now.iface_name_to_handle_.clear();status = retrieveIfaceHandles();}return status;
}

继续查看wificonfig.cppwifi_add_or_remove_virtual_intf()函数:
关于global_func_table_中的函数指针怎么对应到wificonfig.cpp中的wifi_add_or_remove_virtual_intf()函数的,可以移步这里

代码路径:qcom/wlan/qcwcn/wifi_hal/wificonfig.cpp

#ifdef WCNSS_QTI_AOSP
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;//下方两个函数实现在hardware/qcom/wlan/qcwcn/wifi_hal/common.cpp//强制类型转换interface_info *ifaceInfo = getIfaceInfo(iface);//强制类型转换为interface_info后取handle字段wifi_handle wifiHandle = getWifiHandle(iface);//构造一个WiFiConfigCommand,wifiConfigCommand = new WiFiConfigCommand(wifiHandle, get_requestid(), 0, 0);//QcAddInterface调用过来create恒为trueif (create) {nl80211_iftype type;//WifiChip::createStaIfaceInternal()调用过来恒为IfaceType::STAswitch(iface_type) {case 0:    /* IfaceType:STA */type = NL80211_IFTYPE_STATION;break;case 1:    /* IfaceType:AP */type = NL80211_IFTYPE_AP;break;case 2:    /* IfaceType:P2P */type = NL80211_IFTYPE_P2P_DEVICE;break;default:ALOGE("%s: Wrong interface type %u", __FUNCTION__, iface_type);ret = WIFI_ERROR_UNKNOWN;goto done;break;}//封装信息内容wifiConfigCommand->create_generic(NL80211_CMD_NEW_INTERFACE);wifiConfigCommand->put_u32(NL80211_ATTR_IFINDEX, ifaceInfo->id);wifiConfigCommand->put_string(NL80211_ATTR_IFNAME, ifname);wifiConfigCommand->put_u32(NL80211_ATTR_IFTYPE, type);} else {wifiConfigCommand->create_generic(NL80211_CMD_DEL_INTERFACE);wifiConfigCommand->put_u32(NL80211_ATTR_IFINDEX, if_nametoindex(ifname));}//通过Netlink发送消息到驱动侧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;
}

后面就是驱动层的实现了,这里暂不讨论;
可见,IWifiChip.createStaIface这一步主要是通知WIFI网卡驱动创建一个可用的(STA模式)Iface,如果已经创建,则直接使用即可;

这部分的流程比较简单,时序图参考如下:

IWifiCond

IWificond.createClientInterface()的实现在wificond进程中:
代码路径:system/connectivity/wificond/server.cpp

Status Server::createClientInterface(const std::string& iface_name,sp<IClientInterface>* created_interface) {InterfaceInfo interface;//如果setup失败,则直接返回,created_interface为空;if (!SetupInterface(iface_name, &interface)) {return Status::ok();}//构建一个ClientInterfaceImpl,并封装需要通过Netlink Socket发送的数据结构;unique_ptr<ClientInterfaceImpl> client_interface(new ClientInterfaceImpl(wiphy_index_,interface.name,interface.index,interface.mac_address,if_tool_.get(),netlink_utils_,scan_utils_));*created_interface = client_interface->GetBinder();BroadcastClientInterfaceReady(client_interface->GetBinder());client_interfaces_[iface_name] = std::move(client_interface);return Status::ok();
}

这里需要重点关注这个SetupInterface()函数:

bool Server::SetupInterface(const std::string& iface_name,InterfaceInfo* interface) {//通过Netlink与内核通信,获取iface的信息,如果通信失败,直接返回falseif (!RefreshWiphyIndex()) {return false;}//注册监听netlink_utils_->SubscribeRegDomainChange(wiphy_index_,std::bind(&Server::OnRegDomainChanged,this,_1));interfaces_.clear();//通过Netlink获取对应的ifaceif (!netlink_utils_->GetInterfaces(wiphy_index_, &interfaces_)) {return false;}//如果名字匹配,则返回truefor (const auto& iface : interfaces_) {if (iface.name == iface_name) {*interface = iface;return true;}}return false;
}

重点在于RefreshWiphyIndex()NetlinkUtils::GetInterfaces()两个函数:

  • RefreshWiphyIndex()会调用NetlinkUtils::GetWiphyIndex(),向内核发送NL80211_CMD_GET_WIPHY请求,获取Wiphy的下标,如果获取成功则返回true,反之返回false
  • NetlinkUtils::GetInterfaces()则是通过向内核发送NL80211_CMD_GET_INTERFACE请求,附带wiphy_index作为属性,尝试获取对应的InterfaceInfo,获取成功返回true,反之返回false

关于Wiphy

  • 指的是Wireless Physical Layer,即linux内核net子系统中的无线网络(wireless)物理层;

HAL就到此为止,后面是内核部分的逻辑了,会单独写一篇介绍;

IWifiCond部分时序示意图如下:

ISupplicant

上面提到,ISupplicant在此题中讨论V1.1版本的逻辑,因此对应的HAL实现也应该看V1.1的wpa_supplicant:

代码路径:external/wpa_supplicant_8/wpa_supplicant/hidl/1.1/supplicant.cpp

Return<void> Supplicant::addInterface(const IfaceInfo& iface_info, addInterface_cb _hidl_cb)
{return validateAndCall(this, SupplicantStatusCode::FAILURE_IFACE_INVALID,&Supplicant::addInterfaceInternal, _hidl_cb, iface_info);
}

validateAndCall()同样是一个模板函数,照例展开:

Return<void> Supplicant::addInterface(const IfaceInfo& iface_info, addInterface_cb _hidl_cb)
{if (this->isValid()) {const auto& ret_pair =addInterfaceInternal(iface_info);const SupplicantStatus& status = std::get<0>(ret_pair);const sp<ISupplicantIface> ret_value = std::get<1>(ret_pair);hidl_cb(status, ret_value);} else {hidl_cb({SupplicantStatusCode::FAILURE_IFACE_INVALID, ""},typename std::remove_reference<sp<ISupplicantIface>>::type());}return Void();
}

核心函数为addInterfaceInternal()

std::pair<SupplicantStatus, sp<ISupplicantIface>>
Supplicant::addInterfaceInternal(const IfaceInfo& iface_info)
{android::sp<ISupplicantIface> iface;...//通过getInterfaceInternal尝试获取现有匹配的interface,如果已经存在,直接返回SupplicantStatus status;std::tie(status, iface) = getInterfaceInternal(iface_info);if (status.code == SupplicantStatusCode::SUCCESS) {return {{SupplicantStatusCode::FAILURE_IFACE_EXISTS, ""},iface};}struct wpa_interface iface_params = {};//驱动默认nl80211iface_params.driver = kIfaceDriverName;//由于传入的参数为IfaceType::STA,此处不讨论P2P的逻辑if (iface_info.type == IfaceType::P2P) {...} else {/** 确认配置文件是否存在,主要逻辑有如下几步:*  - 优先确认"/data/vendor/wifi/wpa/wpa_supplicant.conf"*    是否存在且可写(RW),如果不可写,尝试chmod,如果失败,则返回-1,成功则返回0;*  - 如果前者不存在,则判断"/data/misc/wifi/wpa_supplicant.conf"是否存在,*    如果存在则将其拷贝到"/data/vendor/wifi/wpa/wpa_supplicant.conf",*    成功返回0,失败返回-1;如果文件不存在或不可读,返回1;*  - 如果前者返回1,则尝试拷贝"/vendor/etc/wifi/wpa_supplicant.conf"到*    "/data/vendor/wifi/wpa/wpa_supplicant.conf",同理成功返回0,*    失败返回-1;如果文件不存在或不可读,返回1;*  - 如果前者返回1,则尝试拷贝"/system/etc/wifi/wpa_supplicant.conf"到*    "/data/vendor/wifi/wpa/wpa_supplicant.conf",同理成功返回0,*    失败返回-1;如果文件不存在或不可读,返回1;*  - 如果前者依旧返回1,此时已经没有任何不就措施,函数返回-1*/if (ensureConfigFileExists(kStaIfaceConfPath, kOldStaIfaceConfPath) != 0) {//表示配置文件未就绪,或为权限问题,或为文件不存在,HIDL状态码返回//FAILURE_UNKNOWN,数据返回null;return {{SupplicantStatusCode::FAILURE_UNKNOWN,"Conf file does not exist"},{}};}//读取配置文件,如果存在overlay,则使用confanother变量保存overlay文件路径://"/vendor/etc/wifi/wpa_supplicant_overlay.conf"iface_params.confname = kStaIfaceConfPath;int ret = access(kStaIfaceConfOverlayPath, R_OK);if (ret == 0) {iface_params.confanother = kStaIfaceConfOverlayPath;}}iface_params.ifname = iface_info.name.c_str();//核心调用,wpa_supplicant添加STA iface的关键函数;struct wpa_supplicant* wpa_s =wpa_supplicant_add_iface(wpa_global_, &iface_params, NULL);if (!wpa_s) {return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};}最后通过getInterfaceInternal获取对应的对象返回;return getInterfaceInternal(iface_info);
}

可见,创建iface的工作在wpa_supplicant_add_iface()中完成,这部分是wpa_supplicant的逻辑了:

struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,struct wpa_interface *iface,struct wpa_supplicant *parent)
{struct wpa_supplicant *wpa_s;struct wpa_interface t_iface;struct wpa_ssid *ssid;...//初始化一个wpa_s 对象,Android中会调用calloc进行内存分配;wpa_s = wpa_supplicant_alloc(parent);...wpa_s->global = global;t_iface = *iface;//global->params中各个参数的值是main函数中解析cmdline中参数时确定的//以具体的cmdline为准;if (global->params.override_driver) {...t_iface.driver = global->params.override_driver;}if (global->params.override_ctrl_interface) {...t_iface.ctrl_interface =global->params.override_ctrl_interface;}//初始化完成返回0,否则返回-1,这里是关键代码,且逻辑比较复杂if (wpa_supplicant_init_iface(wpa_s, &t_iface)) {...//由于wpa_supplicant_init_iface流程很长,需要deinit来重置各种中间状态wpa_supplicant_deinit_iface(wpa_s, 0, 0);return NULL;}//顺利完成返回0,否则返回-1if (wpas_notify_iface_added(wpa_s)) {//由于无法通知状态,因此无效化该ifacewpa_supplicant_deinit_iface(wpa_s, 1, 0);return NULL;}...wpa_s->next = global->ifaces;global->ifaces = wpa_s;wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);#ifdef CONFIG_P2P...
#endif /* CONFIG_P2P */return wpa_s;
}

有上面分析可知,wpa_supplicant部分的处理关键在于wpa_supplicant_init_iface()函数,后者展开就比较多了(350+行的函数)。

受限于篇幅,我这对函数实现进行了大量裁剪,以便于快速获取关键信息:

static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,const struct wpa_interface *iface)
{struct wpa_driver_capa capa;int capa_res;u8 dfs_domain;if (iface->confname) {...//读取配置文件与overlay文件,路径定义见上方ensureConfigFileExists()函数附近分析wpa_s->conf = wpa_config_read(wpa_s->confname, NULL);...wpa_s->confanother = os_rel2abs_path(iface->confanother);if (wpa_s->confanother &&!wpa_config_read(wpa_s->confanother, wpa_s->conf)) {...return -1;}...//如果ctrl_interface已经由cmdline指定,则此处不再取conf文件中的配置项if (iface->ctrl_interface) {os_free(wpa_s->conf->ctrl_interface);wpa_s->conf->ctrl_interface =os_strdup(iface->ctrl_interface);}...}//如果ifname过长,会导致拷贝失败,因此需要此处判断,如果字符串长度合理,则拷贝到wpa_s->ifname中;if (os_strlen(iface->ifname) >= sizeof(wpa_s->ifname)) {return -1;}os_strlcpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));...//初始化驱动并注册事件监听、处理的Handler,android采用linux内核,这里驱动就是nl80211;//由于涉及到与内核交互,这里暂且不展开了,待驱动层分析时再继续if (wpas_init_driver(wpa_s, iface) < 0)return -1;//初始化一些函数指针的映射;if (wpa_supplicant_init_wpa(wpa_s) < 0)return -1;//将wpa_s中的部分信息通知到wpa_sm中,后者是一个cpp编写的状态机,实现的功能与JAVA层的StateMachine类似;wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname,wpa_s->bridge_ifname[0] ? wpa_s->bridge_ifname :NULL);wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);//通过与驱动层(Android基于Linux内核,此处则为nl80211)通信,获取硬件的一些特性,包括支持的频段、通道、带宽、频率等信息;wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,&wpa_s->hw.num_modes,&wpa_s->hw.flags,&dfs_domain);if (wpa_s->hw.modes) {u16 i;//遍历所有的支持模式,获取其最高的频率支持情况,并设置hw_capab(CAPAB_VHT > CAPAB_HT40 > CAPAB_HT)for (i = 0; i < wpa_s->hw.num_modes; i++) {if (wpa_s->hw.modes[i].vht_capab) {wpa_s->hw_capab = CAPAB_VHT;break;}if (wpa_s->hw.modes[i].ht_capab &HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)wpa_s->hw_capab = CAPAB_HT40;else if (wpa_s->hw.modes[i].ht_capab &&wpa_s->hw_capab == CAPAB_NO_HT_VHT)wpa_s->hw_capab = CAPAB_HT;}}//通过与驱动交互,获取一些能力支持情况,主要包括加密、认证的算法支持情况;capa_res = wpa_drv_get_capa(wpa_s, &capa);//返回0表示获取成功,则将capa中获取的信息保存到wpa_s中;if (capa_res == 0) {wpa_s->drv_capa_known = 1;wpa_s->drv_flags = capa.flags;wpa_s->drv_enc = capa.enc;wpa_s->drv_smps_modes = capa.smps_modes;wpa_s->drv_rrm_flags = capa.rrm_flags;wpa_s->probe_resp_offloads = capa.probe_resp_offloads;wpa_s->max_scan_ssids = capa.max_scan_ssids;wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;wpa_s->max_sched_scan_plans = capa.max_sched_scan_plans;wpa_s->max_sched_scan_plan_interval =capa.max_sched_scan_plan_interval;wpa_s->max_sched_scan_plan_iterations =capa.max_sched_scan_plan_iterations;wpa_s->sched_scan_supported = capa.sched_scan_supported;wpa_s->max_match_sets = capa.max_match_sets;wpa_s->max_remain_on_chan = capa.max_remain_on_chan;wpa_s->max_stations = capa.max_stations;wpa_s->extended_capa = capa.extended_capa;wpa_s->extended_capa_mask = capa.extended_capa_mask;wpa_s->extended_capa_len = capa.extended_capa_len;wpa_s->num_multichan_concurrent =capa.num_multichan_concurrent;wpa_s->wmm_ac_supported = capa.wmm_ac_supported;//mac地址随机化的支持情况,在驱动中是单独的变量记录,//但是在wpa_s中是以标志位mac_addr_rand_supported 存放的,因此需要做转换if (capa.mac_addr_rand_scan_supported)wpa_s->mac_addr_rand_supported |= MAC_ADDR_RAND_SCAN;if (wpa_s->sched_scan_supported &&capa.mac_addr_rand_sched_scan_supported)wpa_s->mac_addr_rand_supported |=(MAC_ADDR_RAND_SCHED_SCAN | MAC_ADDR_RAND_PNO);}if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)wpa_s->p2p_mgmt = iface->p2p_mgmt;...//初始化wpa_supplicant层一些接口和参数if (wpa_supplicant_driver_init(wpa_s) < 0)return -1;//初始化TDLS,该技术用于同一网络下设备间进行直连通信,需在驱动初始化后进行if (!iface->p2p_mgmt && wpa_tdls_init(wpa_s->wpa))return -1;//设置CountryCodeif (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {return -1;}//初始化WPA(Wi-Fi Protected Access)if (wpas_wps_init(wpa_s))return -1;//初始化GAS(Generic advertisement service) server - struct gas_serverwpa_s->gas_server = gas_server_init(wpa_s, wpas_gas_server_tx);...//初始化DPP(Device Provision Protocol)if (wpas_dpp_init(wpa_s) < 0)return -1;//初始化eapol,其会作为后续连接时四次握手的传输协议使用if (wpa_supplicant_init_eapol(wpa_s) < 0)return -1;wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);if (wpa_s->ctrl_iface == NULL) {return -1;}wpa_s->gas = gas_query_init(wpa_s);if (wpa_s->gas == NULL) {return -1;}if ((!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) ||wpa_s->p2p_mgmt) &&wpas_p2p_init(wpa_s->global, wpa_s) < 0) {return -1;}if (wpa_bss_init(wpa_s) < 0)return -1;if (capa_res == 0 && wpas_set_wowlan_triggers(wpa_s, &capa) < 0)return -1;if (pcsc_reader_init(wpa_s) < 0)return -1;if (wpas_init_ext_pw(wpa_s) < 0)return -1;wpas_rrm_reset(wpa_s);wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans);hs20_init(wpa_s);wpa_supplicant_set_default_scan_ies(wpa_s);return 0;
}

wpa_supplicant_init_iface()这个函数调用的东西非常多。篇幅有限,这里无法一一展开分析,先上一个大致的时序图,后续分析wpa_supplicant的时候再着重介绍;


最后,再附上一个合体的时序图:

[Android]Android P(9) WIFI学习笔记 - HAL (1)相关推荐

  1. Android开源项目SlidingMenu本学习笔记(两)

    我们已经出台SlidingMenu使用:Android开源项目SlidingMenu本学习笔记(一个),接下来再深入学习下.依据滑出项的Menu切换到相应的页面 文件夹结构: 点击Bluetooth能 ...

  2. Android Jetpack Components of LiveData 学习笔记

    Android Jetpack Components of Lifecycle 学习笔记 Android Jetpack Components of LiveData 学习笔记 Android Jet ...

  3. Android Jetpack Components of ViewModel 学习笔记

    Android Jetpack Components of Lifecycle 学习笔记 Android Jetpack Components of LiveData 学习笔记 Android Jet ...

  4. android spi读写不通,Android-SPI学习笔记

    概述 SPI(Service Provider Interface, 服务提供方接口),服务通常是指一个接口或者一个抽象类,服务提供方是对这个接口或者抽象类的具体实现,由第三方来实现接口提供具体的服务 ...

  5. 《Android开发高手课》学习笔记

    最近在学习张绍文老师的<Android开发高手课>课程,学习到了很多的干货,特别是在处理问题的策略和知识的广度方面给了我很多的启发,对未来的学习也提供了方向. 目前,技术的发展有两个趋势. ...

  6. Android 中的WiFi学习笔记(转载)----WIFI启动 代码流程走读---网络连接流程

    Android的WiFi 我们通常看到WiFi的守护进程wpa_supplicant在我们的ps的进程列表中,这个就是我们的wifi守护进程.wpa_supplicant在external/wpa_s ...

  7. android studio 远程调试,Unity3D学习笔记——Android远程真机调试(Unity Remote)

    前言:当使用Unity开发移动端的游戏,特别是使用到手机的传感器,如重力感应等,调试的时候,很麻烦, 因为每次都需要编译成APK后安装到手机中测试,而Unity Remote便能很好的解决这个问题,U ...

  8. Android推送进阶课程学习笔记

    今天在慕课网学习了Android进阶课程推送的server端处理回执的消息 . 这集课程主要介绍了,当server往client推送消息的时候,client须要发送一个回执回来确认收到了推送消息才算一 ...

  9. Android工程师进阶34讲学习笔记

    最近发现一个技术提升的平台,很多课程对于技术提升都多有益处,很多是实际上的项目实战并对底层原理讲解透彻.前几个月已经学习完了<Android 工程师进阶 34 讲>,现在重学一遍并做些总结 ...

最新文章

  1. 2021 年第十一届 MathorCup 高校数学建模挑战赛A题分析
  2. React+TypeScript练手小项目
  3. sqlite3admin触发器创建
  4. openlayer右键菜单_使用OpenLayers3 添加地图鼠标右键菜单
  5. kFreeBSD有活过来的迹象?UbuntuBSD
  6. 特征工程完全手册 - 从预处理、构造、选择、降维、不平衡处理
  7. 云计算时代,互联网金融背后的想象空间
  8. iOS开发编译错误:std::terminate(), referenced from:
  9. 最全攻略:利用LightSeq加速你的深度学习模型
  10. 17-基于51单片机的银行排队叫号系统设计
  11. 万恶的ie(还好只是ie11)
  12. 南邮-2022年6月电子商务练习自整理 - 选择篇
  13. 苹果计算机格式化磁盘,MAC格式化移动硬盘
  14. oracle其他数据对象 --- 视图(10级学员 韩晓爽课堂总结)
  15. 致敬柳传志三网合一的佳沃品牌之路
  16. python tensorflow2 deeplearning 音频处理 声学事件检测
  17. 第006话 皮皮和月亮石!
  18. 运动控制卡课程:固高,凌华,雷赛,(单一款学习时间45天,要求有C语言基础)凭良学校
  19. 修改mmsegmentation框架(deeplabV3+中加入注意力机制)
  20. 学习任务01-配置自己ssh config

热门文章

  1. 陀螺仪工作原理及创新应用
  2. 计算机瑞士留学经验,瑞士留学生活分享
  3. OffiSmart Summit智慧办公及空间管理上海线下峰会精彩亮点抢先看
  4. 计算机软考最佳时间,软考报名时间是什么时候?软考有哪些意义?
  5. 水平仪算公式计算机,水准仪的使用及计算方法
  6. linux java -cp lt; .txt_补交 20155202 蓝墨云班课 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能...
  7. [转载]自动机器学习(AutoML)领域论文合集
  8. Unity3D 基于XLua框架实现Lua组件化开发方式(一)----基于C#调用Lua
  9. Koalas - 入门基本操作
  10. html制作心形状图片,把多张图片拼接成一个爱心的形状 爱心形状的图片效果 爱心拼接照...