前言:之前在 (四十四)Android O WiFi启动流程梳理 梳理到了WifiNative的enableSupplicant ,没有继续梳理下去,现在接着梳理。
wpa_supplicant是一个开源项目,它实现了station对无线网络的管理和控制功能,根据官方描述,它支持的功能很多,比如:1.支持WPA和IEEE802.11i所定义的大部分功能;2.支持多种EAPMethod;3.对多种无线网卡和驱动的支持等等。
具体请参考:
1.Linux WPA/WPA2/IEEE 802.1X Supplicant
2.wpa_supplicant及wpa_cli使用方法
/**
* Enable wpa_supplicant via wificond.
* @return Returns true on success.
*/
public boolean enableSupplicant() {
return mWificondControl.enableSupplicant();
}
/**
* Enable wpa_supplicant via wificond.
* @return Returns true on success.
*/
public boolean enableSupplicant() {
if (mClientInterface == null) {
Log.e(TAG, "No valid wificond client interface handler");
return false;
}
try {
return mClientInterface.enableSupplicant();
} catch (RemoteException e) {
Log.e(TAG, "Failed to enable supplicant due to remote exception");
}
return false;
}
mClientInterface在之前的(五十七)Android O WiFi的扫描流程梳理续——梳理java与c++之间的aidl-cpp通信
梳理过了,对应实现是client_interface_binder
public IClientInterface setupDriverForClientMode() {
Log.d(TAG, "Setting up driver for client mode");
mWificond = mWifiInjector.makeWificond();
if (mWificond == null) {
Log.e(TAG, "Failed to get reference to wificond");
return null;
}
IClientInterface clientInterface = null;
try {
clientInterface = mWificond.createClientInterface();
} catch (RemoteException e1) {
Log.e(TAG, "Failed to get IClientInterface due to remote exception");
return null;
}
if (clientInterface == null) {
Log.e(TAG, "Could not get IClientInterface instance from wificond");
return null;
}
Binder.allowBlocking(clientInterface.asBinder());
// Refresh Handlers
mClientInterface = clientInterface;
Status ClientInterfaceBinder::enableSupplicant(bool* success) {
*success = impl_ && impl_->EnableSupplicant();
return Status::ok();
}
而impl_对应的是client_interface_impl
bool ClientInterfaceImpl::EnableSupplicant() {
return supplicant_manager_->StartSupplicant();
}
而supplicant_manager_是在client_interface_impl的构造函数中初始化的
ClientInterfaceImpl::ClientInterfaceImpl(
uint32_t wiphy_index,
const std::string& interface_name,
uint32_t interface_index,
const std::vector& interface_mac_addr,
InterfaceTool* if_tool,
SupplicantManager* supplicant_manager,
NetlinkUtils* netlink_utils,
ScanUtils* scan_utils)
: wiphy_index_(wiphy_index),
interface_name_(interface_name),
interface_index_(interface_index),
interface_mac_addr_(interface_mac_addr),
if_tool_(if_tool),
supplicant_manager_(supplicant_manager),
client_interface_impl的构造函数之前分析过,是在server里调用的
Status Server::createClientInterface(sp* created_interface) {
InterfaceInfo interface;
if (!SetupInterface(&interface)) {
return Status::ok(); // Logging was done internally
}
unique_ptr client_interface(new ClientInterfaceImpl(
wiphy_index_,
interface.name,
interface.index,
interface.mac_address,
if_tool_.get(),
supplicant_manager_.get(),
netlink_utils_,
scan_utils_));
*created_interface = client_interface->GetBinder();
client_interfaces_.push_back(std::move(client_interface));
BroadcastClientInterfaceReady(client_interfaces_.back()->GetBinder());
return Status::ok();
}
/frameworks/opt/net/wifi/libwifi_system$ vim supplicant_manager.cpp
bool SupplicantManager::StartSupplicant() {
char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
int count = 200; /* wait at most 20 seconds for completion */
const prop_info* pi;
unsigned serial = 0;
/* Check whether already running */
if (property_get(kSupplicantInitProperty, supp_status, NULL) &&
strcmp(supp_status, "running") == 0) {
return true;
}
/* Before starting the daemon, make sure its config file exists */
if (ensure_config_file_exists(kSupplicantConfigFile) < 0) {
LOG(ERROR) << "Wi-Fi will not be enabled";
return false;
}
/*
* Some devices have another configuration file for the p2p interface.
* However, not all devices have this, and we'll let it slide if it
* is missing. For devices that do expect this file to exist,
* supplicant will refuse to start and emit a good error message.
* No need to check for it here.
*/
(void)ensure_config_file_exists(kP2pConfigFile);
/*
* Get a reference to the status property, so we can distinguish
* the case where it goes stopped => running => stopped (i.e.,
* it start up, but fails right away) from the case in which
* it starts in the stopped state and never manages to start
* running at all.
*/
pi = __system_property_find(kSupplicantInitProperty);
if (pi != NULL) {
serial = __system_property_serial(pi);
}
property_set("ctl.start", kSupplicantServiceName);
sched_yield();
while (count-- > 0) {
if (pi == NULL) {
pi = __system_property_find(kSupplicantInitProperty);
}
if (pi != NULL) {
/*
* property serial updated means that init process is scheduled
* after we sched_yield, further property status checking is based on this
*/
if (__system_property_serial(pi) != serial) {
__system_property_read(pi, NULL, supp_status);
if (strcmp(supp_status, "running") == 0) {
return true;
} else if (strcmp(supp_status, "stopped") == 0) {
return false;
}
}
}
usleep(100000);
}
return false;
}
可以观察到这个方法会先检查配置文件是否存在
const char kSupplicantInitProperty[] = "init.svc.wpa_supplicant";
const char kSupplicantConfigTemplatePath[] =
"/etc/wifi/wpa_supplicant.conf";
const char kSupplicantConfigFile[] = "/data/misc/wifi/wpa_supplicant.conf";
const char kP2pConfigFile[] = "/data/misc/wifi/p2p_supplicant.conf";
const char kSupplicantServiceName[] = "wpa_supplicant";
constexpr mode_t kConfigFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
之后通过 “setprop ctrl.start wpa_supplicant” 来触发init进程去fork一个子进程来完成supplicant的启动。
看最后的注释:
/*
* property serial updated means that init process is scheduled
* after we sched_yield, further property status checking is based on this
*/
表示调用了sched_yield后start wpa_supplicant的任务就进入时刻表中,后续基于此进行属性状态检查supplicant是否启动完成。
流程先梳理到这里吧。。。