欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

WiFi 连接过程

程序员文章站 2022-06-09 19:11:33
1. 在 WifiNative 类中 connectNetwork 被调用用于连接,其主要工作为停止当前扫描过程,删除 wpa_supplicant 中的网络配置信息,并将新的配置传送给 wpa_supplicant 保存,这会触发对已有配置网络的 disconnect 操作,最后触发 reconnect 操作到 wpa_supplicant: /** * Add the provided network configuration to wpa_supplicant and init...

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);

 

本文地址:https://blog.csdn.net/Vince_/article/details/111035003

相关标签: wifi Android