Android中的Wifi框架知识点

一. Android wifi框架图

Android WIFI系统引入了wpa_supplicant,它的整个WIFI系统以wpa_supplicant为核心来定义上层接口和下层驱动接口。Android WIFI主要分为六大层,分别是WiFi Settings层,Wifi Framework层,Wifi JNI 层, Wifi HardWare 层, Wpa_supplicant 层和 Wifi Kernel 层。

在这里插入图片描述
图1.1 Android WIFI 系统架构

Wifi Settings层 ------> Java应用层

Wifi Framework层 ------> Java框架层

Wifi JNI层 ------> C框架层

Wifi HardWare层 ------> C框架层

Wpa_supplicant层 ------> C框架层

Wifi Kernel层 ------> 内核空间

下面对上图的部分做出分析:

1.1 Wifi Service
由SystemServer启动的时候生成的ConnecttivityService创建,负责启动关闭wpa_supplicant,启动和关闭WifiMonitor线程,把命令下发给wpa_supplicant以及更新WIFI的状态。处理其它模块通过WifiManager接口发送过来的远端WiFi操作。

1.2 WifiMonitor
负责从wpa_supplicant接收事件通知。

1.3 wpa_supplicant
1)读取配置文件
2)初始化配置参数
3)让驱动scan当前所有的bssid
4)检查扫描的参数是否和用户设置的相符
5)如果相符,通知驱动进行权限和认证操作
6)连上AP

注意:
AP(Access Point),也就是无线接入点,是一个无线网络的创建者,是网络的中心节点,俗称“热点”。无线网络中的无线交换机,它是使用无线设备(手机等移动设备和笔记本电脑等无线设备)用户进入有线网络的接入点。大多数无线AP还带有接入点客户端模式(AP client),可以和其它AP进行无线连接,延展网络的覆盖范围。

在这里插入图片描述

1.4 Wifi 驱动模块
厂商提供的source,主要进行load firware和kernel的wireless进行通信

1.5 Wifi 电源管理模块
主要控制硬件的GPIO和上下电,让CPU和Wifi模组之间通过sdio接口或者USB接口通信。

1.6 Wifi 工作步骤
1)Wifi 启动
2)开始扫描
3)显示扫描的AP
4)配置AP
5)连接AP
6)获取IP地址
7)上网

二. Android Wifi 源码架构

1. Wifi Settings层

//代码目录
packages/apps/Settings/src/com/android/settings/wifi/

主要的类:
WifiSettings.java : 负责显示 Wifi 的设置界面
WifiEnabler.java : 负责 Wifi 的开关逻辑
WifiDialog.java : 负责Wifi的对话框
WifiDInfo.java : 表示Wifi 的相关配置信息

2. Wifi Framework 层

//代码目录
frameworks/base/wifi/Java/android/net/wifi/
frameworks/base/core/java/android/net/
frameworks/opt/net/wifi/service/java/com/android/server/wifi

主要的类:
WifiManager : 它是 Wifi 模块向外部应用透漏出来的接口,其它所有应用都可以通过WiFi Manager 来操作Wifi 的各项功能,当时WifiManager 本身不具备处理请求的能力,而是把所有的请求转发给WifiServicelmpl 来处理。

WifiService : Java Framework中 Wifi 功能的总入口,负责 Wifi 功能的核心业务。它是服务器端的实现,作为 Wifi 部分的核心,处理实际的驱动加载、扫描、链接、断开等命令,以及底层上报的事件。对于主动的命令控制,Wifi 是一个简单的封装,针对来自客户端的控制命令,调用相应的WifiNative底层实现。

WifiServicelmpl : 本身也不具备处理请求的能力,而是将请求分类后交给不同的处理者处理,比如WifiStateMachine。

WifiStateMachine : 它是一个复杂的状态机,维护了Wifi的启动、扫描、连接、断开等多个状态。它运行自己独有的线程中,拥有自己的消息队列。

WifiState Tracker : 除了负责Wifi 的电源管理模式等功能外,其核心是WifiMonitor所实现的事件轮询机制,以及消息处理函数handleMessage()。

WifiMonitor : 专门负责接收来自wpa_supplicant的事件,并将这些信息进行分类再交予StateMachine处理。

WifiNative :一个接口类,主要是提供一些native方法用于wifi framework层和 WPAS 通信。WifiNative 的主要实现都在 wifi.c 函数里,WifiNative 仅是将其封装,给framework层调用。

注意:WifiService 和 WifiMonitor 是整个模块的核心。WifiService 负责启动关闭wpa_supplicant,启动关闭WifiMonitor监视线程和把命令下发给wpa_supplicant,而WifiMonitor则负责从wpa_supplicant接收事件通知。
也就是说Wifiservice负责wifi整个流程的控制,而WifiMonitor负责监视底层的事件。

3. Wifi JNI 层

//代码目录
frameworks/base/core/jni/android_net_wifi_Wifi.cpp
android_net_wifi_Wifi.cpp就是典型jni接口,通过它可以直接调用Wifi的硬件抽象层。

4. Wifi Hardware 层(wifi管理库)

//代码目录
hardware/libhardware_legacy/wifi/wifi.c

Wifi Hardware 层也被称为wpa_supplicant适配层,是通用wpa_supplicant的封装。wpa_supplicant适配层起着承上启下的作用,主要用于和wpa_supplicant守护进程的通信,以供给Wifi框架层使用。

5. wpa_supplicant层(wifi tool)

//代码目录
external/wpa_supplicant/

wpa_supplicant是一个开源项目,已经移植到Linux、Windows以及其它嵌入式系统上。它是WPA(WiFi Protected Access,Wifi 网络安全存取)的应用层认证客户端,负责完成认证相关的登录、加密等工作。该层是Wifi Framework层的基石,也叫Wifi 服务层。

经过编译后主要结果是生成动态库libwpa_client.so和可执行程序wpa_supplicant。
1wpa_client (生成库libwpaclient.so)
external/wpa_supplicant_8/wpa_supplicant/src/common/wpa_ctrl.c
2) wpa_server (生成守护进程wpa_supplicant)
external/wpa_supplicant_8/wpa_supplicant/main.c

6. Wifi Kernel 层

//代码目录
kernel/drivers/net/wireless
kernel/drivers/wlan_sd8688
arch/arm/mach-pxa/wlan_pm.c

三. WifiService 和 wpa_supplicant启动流程

在这里插入图片描述
图 3.1 WifiService 和 wpa_supplicant启动流程

状态变化

加载wifi驱动的状态变化流程如下:

               mInitialState(初始状态)
                     |
             mDriverUnloadedState

                     |
           mWaitForP2pDisableState

                     |
 mDriverLoadingState(其enter中调用WifiNative.loadDriver)

启动wpa_supplicant的状态变化如下:

在DriverLoadedState状态的processMessage中调用WifiNative.startSupplicant

生产时自动打开Wifi

在生产时, 默认Wifi是关闭的,如果需要默认打开,可修改wifiservice.java中的如下代码:

    /**
     * Check if Wi-Fi needs to be enabled and start
     * if needed
     *
     * This function is used only at boot time
     */
    public void checkAndStartWifi() {
        mAirplaneModeOn.set(isAirplaneModeOn());
        mPersistWifiState.set(getPersistedWifiState());
        /* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
        boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
        Slog.i(TAG, "WifiService starting up with Wi-Fi " +
                (wifiEnabled ? "enabled" : "disabled"));
        setWifiEnabled(wifiEnabled); //强制设置为true
 
        mWifiWatchdogStateMachine = WifiWatchdogStateMachine.
               makeWifiWatchdogStateMachine(mContext);
 
    }

四. wpa_supplicant

wpa_supplicant是一个开源软件源项目,它实现了Station对无线网络进行管理和控制的功能。wpa_supplicant支持的功能非常多,下面列举几个重要的功能。

  1. 支持WPA和IEEE 802.11i定义的大部分功能。

1)支持WPA—PSK(WPA-Personal)和WPA-Enterprise(利用RAIDUS认证服务器来完成身份认证的情况)

2)数据加密方面支持CCMP,TKIP,WEP104和WER40。其中,WEP104和WEP40中的数字代表密钥的长度。

3)完全支持WPA和WPA2,包括PMKSA缓存,预认证(pre-authentication)等功能

4)完全支持IEEE 802.11r和802.11w,其中802.11r规范定义了快速基础服务转移功能,而802.11w新增对了对管理帧的安全保护机制。

5)支持WFA制定的WIFI protected Setup功能,P2P,TDLS等。

  1. 支持多种EAP Method。
    主要和802.1X中的Supplicant的功能有关,wpa_supplicant支持多达25种EAP Method,包括以下EAP-TLS,EAP-PEAP,EAP-TTLS和EAP-SIM、EAP-PSK、EAP-GPSK等其他认证方法。

  2. 对各种无线网卡和驱动的支持。

1)支持nl80211/cfg80211驱动和Linux Wireless Extension驱动。

2)支持Windows平台中的NDIS驱动。

wpa_supplicant包含三个主要子目录,如下:
1)hostapd:当手机进入Soft AP模式时,手机扮演AP的角色,需要hostapd来提供AP功能。

2)wpa_supplicant:Station模式,也叫Managed模式(重点)

3)src:hostapd和wpa_supplicant中都包含了一些通用的数据结构和处理方法,这些内容都放在src目录中。

wpa_supplicant是Android用户空间中无线网络部分的核心模块,所有Framework层中和WIFI相关的操作最终都由wpa_supplicant来完成。

五. wpa_supplicant架构

wpa_supplicant是比较庞大的开源软件项目,内部模块结构如图:

在这里插入图片描述
图 5.1 wpa_supplicant软件架构

1)WPAS所有工作都围绕事件(event loop模块)展开,它是基于事件驱动的。事件驱动和消息驱动类似,主线程等待事件的发生并处理它们。

2)位于event loop模块下方的driver interface接口模块用于隔离和底层驱动直接交互的那些driver控制模块(wext、ndiswrapper等,WPAS中称为driver wrapper)

3)dirver wrapper经常返回一些信息给上层。

六. wpa_supplicant命令和控制API

WPAS对外通过控制接口模块与客户端通信。在Android平台中,WPAS的客户端是位于Framework中的WifiService。用户在Settings界面进行WiFi相关的操作最终都会经由WifiService通过发送命令的方式转交给wpa_supplicant去执行。

1. 命令
WPAS定义了许多命令。

PING:心跳检测命令。客户端用它判断WPAS是否工作正常。WPAS收到"PING"命令后需要回复"PONG"。

MIB:客户端用该命令获取设备的MIB信息。

STATUS:客户端用该命令获取设备的MIB信息。

ADD_NETWORK:为WPAS添加一个新的无线网络。它将返回此新无线网络的ID

SET_NETWORK:network id是无线网络的ID。此命令用于设置指定无线网络的信息。其中variable为参数名,value为参数的值。

ENABLE_NETWORK: 使能某个无线网络。此命令最终将促使WPAS发起一系列操作以加入该无线网络。

除了接收来自client的命令外,WPAS也会主动给client发送命令。

2. 控制API
Android平台中wifiService是WPAS的客户端,它和WPAS交互时必须使用wpa_supplicant提供的API。这些API声明于wpa_ctrl.h中,用法如下:

//必须包含此头文件,链接时需要包含libwpa_client.so动态库。
#include "wpa_ctrl.h"

客户端使用wpa_ctrl时首先要分配控制对象。下面两个API用于创建和销毁控制对象wpa_ctrl。

//创建一个wpa控制端对象wpa_ctrl。Android平台中,参数ctrl——path代表unix域socket的位置
struct wpa_ctrl *wpa_ctrl_open(const char *ctrl_path);
//注销wpa_ctrl控制对象
void wpa_ctrl_close(struct wpa_ctrl *ctrl);

下面这个函数用于发送命令给WAPS。

//客户端发送命令给wpa_supplicant,回复的消息保存在reply中
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, char *reply, size_t *reply_len, void (*msg_cb)(char *msg, size_t len));

msg_cb是一个回调函数,该参数的设置和WPAS中C/S通信机制的设计有关。

打开通知事件监听功能相关的API如下所示。

//打开通知事件功能
int wpa_ctrl_attach(struct wpa_ctrl *ctrl);
//打开通知事件监听功能的wpa_ctrl对象能直接调用下面的函数来接收unsolicited event
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)

如果客户端并不发送命令,而只是想接收Unsolicited event,可通过wpa_ctrl_recv函数来此达到目的。

综上所述,单独使用wpa_ctrl_recv和wpa_ctrl_request都不方便。因此,常用的方法是:客户端创建两个wpa_ctrl对象来简化自己的逻辑处理。

1)一个打开了通知事件监听功能的wpa_ctrl对象将只通过wpa_ctrl_recv来接收通知事件。

2)另外一个wpa_ctrl专职用于发送命令和接收回复。由于没有调用wpa_ctrl_attach,所以它不会收到通知事件。

七. wpa_supplicant连接无线网络分析

通过命令行发送命令的方式触发wpa_supplicant进行相关工作,使手机加入一个利WPA_PSK进行认证的无线网络。

在这里插入图片描述

dhcpcd成功执行后,手机将从AP那边分配到一个IP地址。至此,手机就可以使用"Tes" 无线网络。

在这里插入图片描述

综上所述,所有来自客户端的命令都由wpa_supplicant_ctrl_iface_receive函数处理;绝大部分命令都由wpa_supplicant_ctrl_iface_process函数处理。

ENABLE_NETWORK命令处理
ENABLE_NETWORK命令由wpa_supplicant_ctrl_iface_enable_network进行处理,其代码如下:

在这里插入图片描述

在这里插入图片描述

  1. 无线网络扫描流程分析
    ENABLE_NETWORK将发起无线网络扫描请求,这是由wpa_supplicant_req_scan完成的,其代码如下:

在这里插入图片描述

wpa_supplicant_scan是无线网络扫描的核心函数,其代码比较复杂,分段来分析。
1)wpa_supplicant_scan分析之一
这一段的代码主要和scan请求的参数准备有关。
在这里插入图片描述

在这里插入图片描述
一个Probe Request要么指定wildcard ssid以扫描周围所有的无线网络,要么指定某个ssid以扫描指定无限网络。为了方便WPAS的使用,wlan driver新增一个功能,使得上层可通过一次scan请求来扫描多个不同ssid的无线网络。一个scan请求在代码中对应的数据结构就是wpa_driver_scan_params。而wpa_supplicant_scan最重要的工作就是准备好这个请求。

2)wpa_supplicant_scan分析之二
接着来看代码段二

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上诉wpa_supplicant_scan代码主要展示了如何填写扫描请求参数,复杂的点在于细节处理。

3)wpa_supplicant_scan分析三
当scan请求的参数准备好,wpa_supplicant_scan将直接向driver wrapper发起scan请求。

在这里插入图片描述
对driver_nl80211,对应的函数是wpa_driver_nl80211_scan,看下面代码。

在这里插入图片描述
在这里插入图片描述
本例来说,ENABLE_WORK命令处理的第一步就是要扫描周围的无线网络。至于目标无线网络是否存在,则属于扫描结果处理流程的工作了。

4)无线网络扫描流程总结
下图为触发扫描扫描功能的流程图。

 图 4.1 触发扫描的流程图
图 7.1 触发扫描的流程图

图中的函数,wpa_supplicant_scan的内容较丰富,其中有很多细节内容。初次学习,可先不考虑图中函数的细节,只需把握图中函数调用流程即可。

  • 23
    点赞
  • 91
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
要设置WiFi静态模式,您需要在Android 10的framework代码进行以下步骤: 1. 打开WifiManager.java文件并添加以下代码: ``` /** * Set the IP address, gateway, and subnet mask for a static IP configuration. * * @param ipAddress the IP address in integer form * @param gateway the gateway in integer form * @param subnetMask the subnet mask in integer form * @param dns the DNS server addresses in integer form * @return {@code true} if the operation succeeded, {@code false} otherwise * @hide */ public boolean setWifiStaticIpConfiguration(int ipAddress, int gateway, int subnetMask, int[] dns) { WifiConfiguration config = getCurrentWifiConfiguration(); if (config == null) { return false; } config.setIpAssignment(IpAssignment.STATIC); config.setIpAddress(InetAddress.getByAddress(intToByteArray(ipAddress)).getHostAddress()); config.setGateway(InetAddress.getByAddress(intToByteArray(gateway)).getHostAddress()); config.setNetmask(InetAddress.getByAddress(intToByteArray(subnetMask)).getHostAddress()); config.setDns(dns); return saveWifiConfiguration(config); } private byte[] intToByteArray(int value) { return new byte[] { (byte)(value >>> 24), (byte)(value >>> 16), (byte)(value >>> 8), (byte)value}; } ``` 2. 在WifiConfiguration.java文件,添加以下代码: ``` /** * Set the IP assignment mode. * * @param ipAssignment the IP assignment mode to set * @hide */ public void setIpAssignment(IpAssignment ipAssignment) { mIpAssignment = ipAssignment; } /** * Set the IP address. * * @param ipAddress the IP address to set * @hide */ public void setIpAddress(String ipAddress) { mIpAddress = ipAddress; } /** * Set the gateway. * * @param gateway the gateway to set * @hide */ public void setGateway(String gateway) { mGateway = gateway; } /** * Set the subnet mask. * * @param netmask the subnet mask to set * @hide */ public void setNetmask(String netmask) { mNetmask = netmask; } /** * Set the DNS server addresses. * * @param dns the DNS server addresses to set * @hide */ public void setDns(int[] dns) { mDnsServers.clear(); for (int i = 0; i < dns.length; i++) { mDnsServers.add(InetAddress.getByAddress(intToByteArray(dns[i]))); } } ``` 3. 最后,在Settings app添加WiFi的静态IP配置。打开WifiSettings.java文件并添加以下代码: ``` /** * Show the dialog for configuring a static IP address. * * @param config the WifiConfiguration to configure * @hide */ public void showWifiStaticIpConfigDialog(WifiConfiguration config) { StaticIpConfigDialogFragment fragment = StaticIpConfigDialogFragment.newInstance(config); fragment.show(getFragmentManager(), StaticIpConfigDialogFragment.TAG); } ``` 这些代码将允许您在Android 10设置WiFi的静态IP地址。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值