1. 在 WifiNative 类中 connectNetwork 被调用用于连接,其主要工作为停止当前扫描过程,删除 wpa_supplicant 中的网络配置信息,并将新的配置传送给 wpa_supplicant 保存,这会触发对已有配置网络的 disconnect 操作,最后触发 reconnect 操作到 wpa_supplicant:
/**
* Add the provided network configuration to wpa_supplicant and initiate connection to it.
* This method does the following:
* 1. Abort any ongoing scan to unblock the connection request.
* 2. Remove any existing network in wpa_supplicant(This implicitly triggers disconnect).
* 3. Add a new network to wpa_supplicant.
* 4. Save the provided configuration to wpa_supplicant.
* 5. Select the new network in wpa_supplicant.
* 6. Triggers reconnect command to wpa_supplicant.
*
* @param ifaceName Name of the interface.
* @param configuration WifiConfiguration parameters for the provided network.
* @return {@code true} if it succeeds, {@code false} otherwise
*/
public boolean connectToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) {
// Abort ongoing scan before connect() to unblock connection request.
mWifiCondManager.abortScan(ifaceName);
return mSupplicantStaIfaceHal.connectToNetwork(ifaceName, configuration);
}
2. SupplicantStaIfaceHal 类中的 connectToNetwork 方法被调用:
/**
* Add the provided network configuration to wpa_supplicant and initiate connection to it.
* This method does the following:
* 1. If |config| is different to the current supplicant network, removes all supplicant
* networks and saves |config|.
* 2. Select the new network in wpa_supplicant.
*
* @param ifaceName Name of the interface.
* @param config WifiConfiguration parameters for the provided network.
* @return {@code true} if it succeeds, {@code false} otherwise
*/
public boolean connectToNetwork(@NonNull String ifaceName, @NonNull WifiConfiguration config) {
synchronized (mLock) {
logd("connectToNetwork " + config.getKey());
WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
/* 如果新旧配置对应的网络是同一个 */
if (WifiConfigurationUtil.isSameNetwork(config, currentConfig)) {
String networkSelectionBSSID = config.getNetworkSelectionStatus()
.getNetworkSelectionBSSID();
String networkSelectionBSSIDCurrent =
currentConfig.getNetworkSelectionStatus().getNetworkSelectionBSSID();
if (Objects.equals(networkSelectionBSSID, networkSelectionBSSIDCurrent)) {
logd("Network is already saved, will not trigger remove and add operation.");
} else {
logd("Network is already saved, but need to update BSSID.");
if (!setCurrentNetworkBssid(
ifaceName,
config.getNetworkSelectionStatus().getNetworkSelectionBSSID())) {
loge("Failed to set current network BSSID.");
return false;
}
mCurrentNetworkLocalConfigs.put(ifaceName, new WifiConfiguration(config));
}
} else { /* 新旧配置对应的网络部是同一个,也有可能存在一个配置是 null */
/* 删除 HashMap 中 ifaceName 对应的配置 */
mCurrentNetworkRemoteHandles.remove(ifaceName);
/* 删除 HashMap 中 ifaceName 对应的配置 */
mCurrentNetworkLocalConfigs.remove(ifaceName);
if (!removeAllNetworks(ifaceName)) {
loge("Failed to remove existing networks");
return false;
}
Pair<SupplicantStaNetworkHal, WifiConfiguration> pair =
addNetworkAndSaveConfig(ifaceName, config);
if (pair == null) {
loge("Failed to add/save network configuration: " + config.getKey());
return false;
}
mCurrentNetworkRemoteHandles.put(ifaceName, pair.first);
mCurrentNetworkLocalConfigs.put(ifaceName, pair.second);
}
SupplicantStaNetworkHal networkHandle =
checkSupplicantStaNetworkAndLogFailure(ifaceName, "connectToNetwork");
if (networkHandle == null) {
loge("No valid remote network handle for network configuration: "
+ config.getKey());
return false;
}
PmkCacheStoreData pmkData = mPmkCacheEntries.get(config.networkId);
if (pmkData != null
&& !WifiConfigurationUtil.isConfigForPskNetwork(config)
&& pmkData.expirationTimeInSec > mClock.getElapsedSinceBootMillis() / 1000) {
logi("Set PMK cache for config id " + config.networkId);
if (networkHandle.setPmkCache(pmkData.data)) {
mWifiMetrics.setConnectionPmkCache(true);
}
}
if (!networkHandle.select()) {
loge("Failed to select network configuration: " + config.getKey());
return false;
}
return true;
}
}
3. 假设一开始配置为空,新增加了一条配置,则会进入 else 操作,重点进行分析,首先来看 removeAllNetworks 接口的操作:
/**
* Remove all networks from supplicant
*
* @param ifaceName Name of the interface.
*/
public boolean removeAllNetworks(@NonNull String ifaceName) {
synchronized (mLock) {
ArrayList<Integer> networks = listNetworks(ifaceName);
if (networks == null) {
Log.e(TAG, "removeAllNetworks failed, got null networks");
return false;
}
for (int id : networks) {
if (!removeNetwork(ifaceName, id)) {
Log.e(TAG, "removeAllNetworks failed to remove network: " + id);
return false;
}
}
// Reset current network info. Probably not needed once we add support to remove/reset
// current network on receiving disconnection event from supplicant (b/32898136).
mCurrentNetworkRemoteHandles.remove(ifaceName);
mCurrentNetworkLocalConfigs.remove(ifaceName);
return true;
}
}
4. 进而来看 listNetworks,因为这里面我们会进入到底层 Hal 以及 wpa_supplicant 的操作过程:
/**
* @return a list of SupplicantNetworkID ints for all networks controlled by supplicant, returns
* null if the call fails
*/
private java.util.ArrayList<Integer> listNetworks(@NonNull String ifaceName) {
synchronized (mLock) {
final String methodStr = "listNetworks";
ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
if (iface == null) return null;
Mutable<ArrayList<Integer>> networkIdList = new Mutable<>();
try {
iface.listNetworks((SupplicantStatus status, ArrayList<Integer> networkIds) -> {
if (checkStatusAndLogFailure(status, methodStr)) {
networkIdList.value = networkIds;
}
});
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
}
return networkIdList.value;
}
}
① ISupplicantStaIface 定义在 hardware/interfaces/wifi/supplicant/1.0/ISupplicantStaIface.hal 文件中,继承自 ISupplicantIface,定义在 hardware/interfaces/wifi/supplicant/1.0/ISupplicantIface.hal 文件中,在经过 HIDL 转化之后 Native 代码实现在 external/wpa_supplicant_8/wpa_supplicant/hidl/ 目录下,而 ISupplicantStaIface 对应的 cpp 实现是 StaIface 类,定义在 sta_iface.h,实现在 sta_iface.cpp
② 上面在 framework 层的实际处理过程会进入到 HIDL 转化后的服务层 Native 代码中,进而调用到 wpa_supplicant 中的接口展开响应的操作;
③ 通过 checkSupplicantStaIfaceAndLogFailure 获取到 iface 对象,调用其 listNetworks 进而进入到 Native 层的对应接口 StaIface::listNetworks,进一步调用 listNetworksInternal;
④ listNetworksInternal 等内部操作通过 struct wpa_supplicant 对象来获取相应的信息,这些信息即为底层 wpa_supplicant 内部维护的内容,每个 struct wpa_supplicant 对应一个 iface;
5. struct wpa_supplicant 的信息管理由 struct wpa_global 统一进行,而 struct wpa_global 是在 wpa_supplicant 初始化的时候由 wpa_supplicant_init() 进行初始化的,而 wpa_supplicant_init 则是直接在 main 函数中被调用,它完成了如下操作:
① wpa_supplicant_init 初始化之后进行 wpas_notify_supplicant_initialized 以告知所有可能的控制途径 wpa_global 已经初始化完成;
② 如果定义了 CONFIG_HIDL 则 wpas_notify_supplicant_initialized 会调用 wpas_hidl_init 初始化其类型为 struct wpas_hidl_priv 的 hidl 对象;
③ wpas_hidl_init 分配对应的对象并采用 wpa_global 进行其初始化,而这里面非常重要的一步是通过 HidlManager 的 registerHidlService 方法来注册 wpa_supplicant 对应的 HIDL 服务,在这里创建了 Supplicant 类对象,以初始化后的 wpa_global 类型的 global 为参数;
④ 可以看到在 wpa_supplicant 的管理过程中如前面需要获取网络配置对应的 struct wpa_supplicat 对象,调用了 wpa_supplicant_get_iface,都是需要以 struct wpa_global 为参数进行的
6. StaIface 类对象的创建和管理由 Supplicant 进行,创建过程中会将 struct wpa_global 对象作为参数传递,从而如上面我们通过 StaIface 的 listNetworks 方法可以直接调用 wpa_supplicant 内部的公共控制接口并将 struct wpa_global 对象作为参数直接传入;
7. 同样这里查询和操作的对应接口都是在 Supplicant 类中进行创建和管理的,位于 hidl 中的 supplicant.{h,cpp} 进行了定义和实现,如 addInterface 方法,然后调用了 addInterfaceInternal 内部方法,进而调用了 wpa_supplicant 的公共管理接口 wpa_supplicant_add_iface;
8. 返回前面主流程来,在 SupplicantStaIfaceHal 的方法 connectToNetwork 中继续执行 removeAllNetworks,将获取到的 list 进行遍历,依次对其进行 removeNetwork 操作,实际上还是调用了 StaIface 的 removeNetwork 方法进入 wpa_supplicant 进行操作;
9. 删除接口之后开始进入 addNetworkAndSaveConfig 操作:
/**
* Add a network configuration to wpa_supplicant.
*
* @param config Config corresponding to the network.
* @return a Pair object including SupplicantStaNetworkHal and WifiConfiguration objects
* for the current network.
*/
private Pair<SupplicantStaNetworkHal, WifiConfiguration>
addNetworkAndSaveConfig(@NonNull String ifaceName, WifiConfiguration config) {
synchronized (mLock) {
logi("addSupplicantStaNetwork via HIDL");
if (config == null) {
loge("Cannot add NULL network!");
return null;
}
SupplicantStaNetworkHal network = addNetwork(ifaceName);
if (network == null) {
loge("Failed to add a network!");
return null;
}
boolean saveSuccess = false;
try {
saveSuccess = network.saveWifiConfiguration(config);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Exception while saving config params: " + config, e);
}
if (!saveSuccess) {
loge("Failed to save variables for: " + config.getKey());
if (!removeAllNetworks(ifaceName)) {
loge("Failed to remove all networks on failure.");
}
return null;
}
return new Pair(network, new WifiConfiguration(config));
}
}
这里重点是 addNetwork 方法,从此开始由 Iface 类型转换到 Network 类型的操作上,需要返回的是 SupplicantStaNetworkHal 对象,该对象是新创建,包含了 ISupplicantStaNetwork 的 HIDL 客户端对象,Context 信息以及 WifiMonitor 信息,而 ISupplicantStaNetwork 对象是在进行 iface 的 addNetwork 中创建的:
/* sta_iface.cpp,StaIface 类实现 */
std::pair<SupplicantStatus, sp<ISupplicantNetwork>>
StaIface::addNetworkInternal()
{
android::sp<ISupplicantStaNetwork> network;
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
struct wpa_ssid *ssid = wpa_supplicant_add_network(wpa_s);
if (!ssid) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
}
HidlManager *hidl_manager = HidlManager::getInstance();
if (!hidl_manager ||
hidl_manager->getStaNetworkHidlObjectByIfnameAndNetworkId(
wpa_s->ifname, ssid->id, &network)) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
}
return {{SupplicantStatusCode::SUCCESS, ""}, network};
}
这里调用 wpa_supplicant_add_network 添加 network,并且通过 HidlManager 的 getStaNetworkHidlObjectByIfnameAndNetworkId 获取到对应的 network 信息返回;
10. network 对应 HIDL 服务端创建过程发生在 HidlManager::registerNetwork 方法中:
/**
* Register a network to hidl manager.
*
* @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
* the network is added.
* @param ssid |wpa_ssid| struct corresponding to the network being added.
*
* @return 0 on success, 1 on failure.
*/
int HidlManager::registerNetwork(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
if (!wpa_s || !ssid)
return 1;
// Generate the key to be used to lookup the network.
const std::string network_key =
getNetworkObjectMapKey(wpa_s->ifname, ssid->id);
if (isP2pIface(wpa_s)) {
if (addHidlObjectToMap<P2pNetwork>(
network_key,
new P2pNetwork(wpa_s->global, wpa_s->ifname, ssid->id),
p2p_network_object_map_)) {
wpa_printf(
MSG_ERROR,
"Failed to register P2P network with HIDL "
"control: %d",
ssid->id);
return 1;
}
p2p_network_callbacks_map_[network_key] =
std::vector<android::sp<ISupplicantP2pNetworkCallback>>();
// Invoke the |onNetworkAdded| method on all registered
// callbacks.
callWithEachP2pIfaceCallback(
wpa_s->ifname,
std::bind(
&ISupplicantP2pIfaceCallback::onNetworkAdded,
std::placeholders::_1, ssid->id));
} else {
if (addHidlObjectToMap<StaNetwork>(
network_key,
new StaNetwork(wpa_s->global, wpa_s->ifname, ssid->id),
sta_network_object_map_)) {
wpa_printf(
MSG_ERROR,
"Failed to register STA network with HIDL "
"control: %d",
ssid->id);
return 1;
}
sta_network_callbacks_map_[network_key] =
std::vector<android::sp<ISupplicantStaNetworkCallback>>();
// Invoke the |onNetworkAdded| method on all registered
// callbacks.
callWithEachStaIfaceCallback(
wpa_s->ifname,
std::bind(
&ISupplicantStaIfaceCallback::onNetworkAdded,
std::placeholders::_1, ssid->id));
}
return 0;
}
对应的 StaNetwork 对象呗创建,并且添加到 sta_network_object_map_ 中,而 StaNetwork 类定义和实现在 sta_network.{h,cpp} 中,registerNetwork 是在 wpas_hidl_register_network 中被调用,继而被 wpas_notify_network_added 调用,调用时机是在 wpa_supplicant_add_network 内部添加了对应的 network 之后通知给监听和管理者;从而又回归到前面在分析的 StaIface::addNetworkInternal 中;
11. 继续返回到 Framework 层,addNetwork 创建 SupplicantStaNetworkHal 后将其返回,紧接着通过其 saveWiFiConfiguration 方法进行配置的保存,这里其实是调用了 SupplicantStaNetworkHal 中的接口通过 HIDL 将对应的信息配置到 wpa_supplicant 中维护的对应的 network 中,比如 ssid 信息;
12. 最终创建信息 WifiConfiguration 信息并与 network 配对之后返回 Pair<SupplicantStaNetworkHal, WifiConfiguration> 对象,WiFiConfiguration 对象为根据传递进来的 config 进行初始化的;
13. 再回到 connectToNetwork 中,将返回的 Pair 中两个配置信息分别加入到对应的 HashMap 中(mCurrentNetworkRemoteHandles 和 mCurrentNetworkLocalConfigs),更新缓存信息;
14. 紧接着调用了 SupplicantStaNetworkHal 类的 select 方法进行网络连接,实际上又回到其内部的 SupplicantStaNetwork 类,调用其 select 方法,进而调用到 Native 层 StaNetwork 类的 select 方法,继续回到 sta_network.cpp 中的 selectInternel 方法:
SupplicantStatus StaNetwork::selectInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (wpa_ssid->disabled == 2) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
wpa_s->scan_min_time.sec = 0;
wpa_s->scan_min_time.usec = 0;
wpa_supplicant_select_network(wpa_s, wpa_ssid);
return {SupplicantStatusCode::SUCCESS, ""};
}
可以看到其内部实际上调用的是 wpa_supplicant_select_network 通用控制接口,实际功能为 “Attempt association with a network”,尝试与对应的网络进行协商;
15. wpa_supplicant 连接过程会发生相应的状态变化,对应的变化过程需要通知给上层,而通知的回调则是在 SupplicantStaIfaceHal 类的 setupStaIface 接口中创建 SupplicantStaIface 的过程中注册的:
/**
* Helper function to set up StaIface with different HAL version.
*
* This helper function would try newer version recursively.
* Once the latest version is found, it would register the callback
* of the latest version and skip unnecessary older HAL init flow.
*
* New version callback will be extended from the older one, as a result,
* older callback is always created regardless of the latest version.
*
* Uprev steps:
* 1. add new helper function trySetupStaIfaceV1_Y.
* 2. call newly added function in trySetupStaIfaceV1_X (X should be Y-1).
*/
private ISupplicantStaIface setupStaIface(@NonNull String ifaceName,
@NonNull ISupplicantIface ifaceHwBinder) throws RemoteException {
/* Prepare base type for later cast. */
ISupplicantStaIface iface = getStaIfaceMockable(ifaceHwBinder);
/* try newer version first. */
if (trySetupStaIfaceV1_1(ifaceName, iface)) {
logd("Newer HAL is found, skip V1_0 remaining init flow.");
return iface;
}
SupplicantStaIfaceHalCallback callback = new SupplicantStaIfaceHalCallback(ifaceName);
if (!registerCallback(iface, callback)) {
throw new RemoteException("Init StaIface V1_0 failed.");
}
/* keep this in a store to avoid recycling by garbage collector. */
mISupplicantStaIfaceCallbacks.put(ifaceName, callback);
return iface;
}
对应的网络相关的事件都会通过该回调进行反馈,hardware/interfaces/wifi/supplicant/1.0/ISupplicantStaNetwork.hal 中关于注册接口的说明如下:
/**
* Register for callbacks from this network.
*
* These callbacks are invoked for events that are specific to this network.
* Registration of multiple callback objects is supported. These objects must
* be automatically deleted when the corresponding client process is dead or
* if this network is removed.
*
* @param callback An instance of the |ISupplicantStaNetworkCallback| HIDL
* interface object.
* @return status Status of the operation.
* Possible status codes:
* |SupplicantStatusCode.SUCCESS|,
* |SupplicantStatusCode.FAILURE_UNKNOWN|,
* |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
*/
registerCallback(ISupplicantStaNetworkCallback callback)
generates (SupplicantStatus status);