Android10 高通平台 softap热点基本流程2

上一篇讲到SoftApManager.IdleState状态中处理CMD_START消息,这个消息用来打开热点功能。我们从这里继续看热点功能基本流程。

public boolean processMessage(Message message) {
    switch (message.what) {
        case CMD_START:
            WifiConfiguration config = (WifiConfiguration) message.obj;
            mApInterfaceName = mWifiNative.setupInterfaceForSoftApMode(
                                mWifiNativeInterfaceCallback);
            int result = startSoftAp((WifiConfiguration) message.obj);
            transitionTo(mStartedState);
    }
}

这里有两个重要的方法,一个是WifiNative.setupInterfaceForSoftApMode和startSoftAp,现在先看setupInterfaceForSoftApMode的实现。

@WifiNative.java
public String setupInterfaceForSoftApMode(@NonNull InterfaceCallback interfaceCallback) {
    startHal();
    startHostapd()
}

startHal用来启动WIFI hal层代码,对hal进行初始化。将通过HIDL和hal进行通信。

startHal()  -> WifiNative.java
    startVendorHal() -> WifiVendorHal.java
        start() -> HalDeviceManager.java
            mWifi = IWifi.getService(true /* retry */);
            mWifi.start();

mWifi是hal层中实现的一个服务,现在需要进入到hardware/interfaces/wifi/1.3/default/wifi.h 目录下去查看start()的实现。

@hardware/interfaces/wifi/1.3/default/wifi.cpp 
Return<void> Wifi::start(start_cb hidl_status_cb) {
    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
                            &Wifi::startInternal, hidl_status_cb);
}

WifiStatus Wifi::startInternal() {
    WifiStatus wifi_status = initializeModeControllerAndLegacyHal();
    chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_,
                            iface_util_, feature_flags_);
    return wifi_status;
}

initializeModeControllerAndLegacyHal()函数中将原始hal层的init函数。legacy_hal_为WifiLegacyHal类的实例。WifiLegacyHal::initialize()方法为:

@hardware/interfaces/wifi/1.3/default/wifi_legacy_hal.cpp 
wifi_error WifiLegacyHal::initialize() {
    initHalFuncTableWithStubs(&global_func_table_)) ;
    wifi_error status = init_wifi_vendor_hal_func_table(&global_func_table_);
}

这里的func_tab在hardware/qcom/wlan/qcwcn/wifi_hal/wifi_hal.cpp中实现,里面有wifi操作的各种方法,通过这个table完成对WIFI的操作。init方法中主要做的事情是操作和驱动程序的nl socket连接,完成通信基础。能和驱动建立连接,hal层就算初始化完成了。

在初始化hal完成后, 实例化了一个WifiChip元素,WifiChip构造方法参数中是一些使用的参数,比如legacy_hal_,可以用来操作WIFI芯片。

到这里,在HalDeviceManager中的mWifi.start()就基本完成。

在WifiNative中,除了有startHal()外,还有startHostapd(),我们看startHostapd实现。

    private boolean startAndWaitForHostapdConnection() {
        // Start initialization if not already started.
        if (!mHostapdHal.isInitializationStarted()
                && !mHostapdHal.initialize()) {
            return false;
        }
        if (!mHostapdHal.startDaemon()) {
            Log.e(TAG, "Failed to startup hostapd");
            return false;
        }
        boolean connected = false;
        int connectTries = 0;
        while (!connected && connectTries++ < CONNECT_TO_HOSTAPD_RETRY_TIMES) {
            // Check if the initialization is complete.
            connected = mHostapdHal.isInitializationComplete();
            if (connected) {
                break;
            }
            try {
                Thread.sleep(CONNECT_TO_HOSTAPD_RETRY_INTERVAL_MS);
            } catch (InterruptedException ignore) {
            }
        }
        return connected;

这里调用mHostapdHal.startDaemon()来启动hostapd进程。startDaemon()方法,猜测是通过过去一个没有打开的服务,来记过服务。hostapd的服务定义在external/wpa_supplicant_8/hostapd/hostapd.android.rc.

14 service hostapd /vendor/bin/hw/hostapd -dd -g /data/vendor/wifi/hostapd/global
15     interface android.hardware.wifi.hostapd@1.0::IHostapd default
16     interface android.hardware.wifi.hostapd@1.1::IHostapd default
17     class main
18     capabilities NET_ADMIN NET_RAW
19     user wifi
20     group wifi net_raw net_admin
21     disabled
22     oneshot

这样hostapd进程就运行起来。

退回到SoftApManager类的Idle状态,setupInterfaceForSoftApMode()启动wifi hal层和hostapd后,执行startSoftAp()方法。

@SoftApManager.java
private int startSoftAp(WifiConfiguration config) {
    WifiConfiguration localConfig = new WifiConfiguration(config);
    
    int result = ApConfigUtil.updateApChannelConfig(
                mWifiNative, mCountryCode,
                mWifiApConfigStore.getAllowed2GChannel(), localConfig);
    
    mWifiNative.startSoftAp(mApInterfaceName, localConfig, mSoftApListener);
}

@WifiNative.java
public boolean startSoftAp(
            @NonNull String ifaceName, WifiConfiguration config, SoftApListener listener) {
    // 注册回调处理方法
    mWificondControl.registerApListener(ifaceName, listener);
    // 启动热点
    mHostapdHal.addVendorAccessPoint(ifaceName, config, listener);
    // 设置WIFI版本
    WifiInjector.getInstance().getWifiApConfigStore().setWifiGeneration(wifiGeneration);
}

我们看addVendorAccessPoint的实现方法:

@HostapdHal.java
public boolean addVendorAccessPoint(@NonNull String ifaceName, @NonNull WifiConfiguration config, SoftApListener listener) {
    // ap配置信息,包括信道信息,ssid,加密方式信息,密码,是否隐藏
    
    // vendorIfaceParams1_1Z在hidl定义,将java中的配置信息设置到hidl结构中
    vendorIfaceParams1_1.VendorV1_0 = vendorIfaceParams;
    vendorIfaceParams1_1.vendorChannelParams.channelParams = ifaceParams.channelParams;
    vendorIfaceParams1_1.vendorEncryptionType = getVendorEncryptionType(config);
    vendorIfaceParams1_1.oweTransIfaceName = (config.oweTransIfaceName != null) ? config.oweTransIfaceName : "";
    // 根据是否打开acs选择信道
    if (mEnableAcs) {
        vendorIfaceParams1_1.vendorChannelParams.acsChannelRanges.addAll(mVendorAcsChannelRanges);
    }
    // 进入到hal中,在hal中将通过打开hostap打开热点,同事将配置信息通过高通sdk设置到驱动
    HostapdStatus status =
            iHostapdVendorV1_1.addVendorAccessPoint_1_1(vendorIfaceParams1_1, nwParams);
}

addVendorAccessPoint_1_1()函数在hidl中实现,进入到external/wpa_supplicant_8/hostapd/hidl/vendor/1.1/hostapd_vendor.cpp查看其实现。

@hostapd_vendor.cpp
HostapdStatus HostapdVendor::__addVendorAccessPointInternal_1_1(
    const VendorIfaceParams& v_iface_params, const NetworkParams& nw_params)
{
    // 通过qsap,也就是高通sdk设置参数
    const auto conf_file_path =
	    AddOrUpdateHostapdConfig(v_iface_params, nw_params);
    // 通过hostapd来打开热点
    hostapd_add_iface(interfaces_, add_iface_param_vec.data());
    hostapd_enable_iface(iface_hapd->iface);
}

AddOrUpdateHostapdConfig()通过qsap这个高通sdk进行操作,其主要工作有两个:

  • 把配置信息比如ssid,信道,加密方式等写入到/data/vendor/wifi/hostapd/hostapd.conf这个配置文件中。在hostapd中,打开热点时,将通过external/wpa_supplicant_8/hostapd/config_file.c 读取文件信息作为热点设置信息。
  • 一些操作指令,将通过io指令下发到驱动,直接指导驱动执行,比如断开sta操作代码:
void qsap_disassociate_sta(s8 *pVal, s8 *presp, u32 *plen)
{
    sock = socket(AF_INET, SOCK_DGRAM, 0);
    strlcpy(wrq.ifr_name, pif, sizeof(wrq.ifr_name));
    ret = ioctl(sock, QCSAP_IOCTL_DISASSOC_STA, &wrq);
    close(sock);
}

我们回到AddOrUpdateHostapdConfig()方法实现如下:

@hostapd_vendor.cpp
constexpr char kQsapSetFmt[] = "softap qccmd set%s %s=%s";
std::string AddOrUpdateHostapdConfig(
    const IHostapdVendor::VendorIfaceParams& v_iface_params,
    const IHostapd::NetworkParams& nw_params)
{
    const std::string ssid_as_string = ss.str();
    qsap_cmd(StringPrintf(kQsapSetFmt, dual_mode_str, "ssid2", ssid_as_string.c_str()));
    
    qsap_cmd(StringPrintf(kQsapSetFmt, dual_mode_str, "channel", std::to_string(channelParams.channel).c_str()));
	}
	...
}

qsap_cmd()在qsap中实现,用来设置指令。

// 将字符串指令拆分
int qsap_cmd(std::string cmd)
{
    for(auto& s: tokens) {
		if (argc >= max_arg_size) {
			wpa_printf(MSG_ERROR, "Command too long");
			return -1;
		}
		data[argc] = strdup(s.c_str());
		argc++;
	}
	run_qsap_cmd(argc, argv);
}

int run_qsap_cmd(int argc, char** argv) {
	int ret = 0;

	if (argc < 3)
		return -1;

	if (!strcmp(argv[1], "qccmd")) {
		ret = qsap_hostd_exec(argc, argv);
	} else if (!strcmp(argv[1], "create") &&
		qsap_add_or_remove_interface(argv[2], 1)) {
	} else if (!strcmp(argv[1], "remove") &&
		qsap_add_or_remove_interface(argv[2], 0)) {
	} else if (!strcmp(argv[1], "bridge")) {
		ret = qsap_control_bridge(argc, argv);
	} else if (!strcmp(argv[1], "setsoftap")) {
		ret = qsapsetSoftap(argc, argv);
	} else {
		ret = -1;
	}

	return ret;
}
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值