wifi相关的文件位置
WIFI Settings应用程序位于
packages/apps/Settings/src/com/android/settings/wifi/
涉及到的文件
WifiSettings.java
frameworks部分
frameworks/base/services/java/com/android/server/
frameworks/base/wifi/java/android/net/wifi/
涉及到的文件有
SystemServer.java
WifiManager.java
WifiService.java
WifiStateMachine.java
Wifinative.java
JNI部分
frameworks/base/core/jni/android_net_wifi_Wifi.cpp
wifi管理库。
hardware/libhardware_legary/wifi/
涉及到的文件
Wifi.c
wifi用户空间的程序和库:
external/wpa_supplicant_8/
生成守护进程wpa_supplicant
一Framesworks层相应的类以及处理流程的介绍
1注册service
Android系统起来后SystemServer进程的名字实际上是system_server是由Zygote
进程创建的SystemServer进程创建后会调用SystemServer.java中的main函数main函数
回调SystemServer中的init2函数启动android services,在init2函数中启动一个ServerThread
线程在该线程的run函数中会创建一系列的Android Services,将与网络以及wifi相关的
service在systemserver.java里面的线程systemthread里面注册也就是把网络与wifi相关的
service的实例用ServiceManager.addService(String name, IBinder service)进行注册与wifi相
关的就是wifiservice类相关代码如下
try {
Slog.i(TAG, "Wi-Fi Service");
wifi = new WifiService(context);
ServiceManager.addService(Context.WIFI_SERVICE, wifi);
} catch (Throwable e) { reportWtf("starting Wi-Fi Service", e);
}
try {
Slog.i(TAG, "Connectivity Service");
connectivity = new ConnectivityService(
context, networkManagement, networkStats, networkPolicy);
ServiceManager.addService(Context.CONNECTIVITY_SERVICE,
connectivity);
networkStats.bindConnectivityManager(connectivity);
networkPolicy.bindConnectivityManager(connectivity);
wifi.checkAndStartWifi();
wifiP2p.connectivityServiceReady();
} catch (Throwable e) {
reportWtf("starting Connectivity Service", e);
}
上面的代码告诉我们将与网络相关的service实例networkStats与networkPolicy与
connectivityservice相关联所谓相关联我的理解是在networkStats与networkPolicy这
两个实例对应的service类中定义一个ConnectivityService类的父类的实例
2 Wifiservice简介
wifiservice是整个框架的核心部分application层触发事件后会调用这个service里
面的方法来处理事件包括加载驱动开启wpa_supplicant扫描AP都是调用这个service
里面的方法实现的实际上这些方法最终调用的是wifistatemachine里面的方法去发送消息。
由wifistatemachine里面的描述wifi事件的内部类去处理这些消息。
在这个类的构造函数中主要就是实例化了一个描述wifi状态机的类wifistatumachine 重写
了广播事件的onReceive函数。
3Wifistatusmachine简介以及android wifi信息传递机制与流程简介。
上面已经提到wifiservice中的方法最终是调用这个service里面的方法来实现的主要
就是对sendmessage()的封装。在这个service中需要传递到wpa_supplicant来实现wifi功
能的命令都在这个service中做了定义。针对每一个wifi状态都声明了一个内部类去描
述比如描述加载驱动开启wpa_supplicant等每一个状态类都有三个函数构成enter
statue().processmessage(),只不过不同类的这三个函数里面的程序不同而已。
Wifistatusmachine的构造函数里面主要的工作是实例化了wifi的监视器mWifiMonitor =
new WifiMonitor(this)这个监视器的作用下面再做解释简单地讲就是通过这个监视器
阻塞监听wpa_supplicant传递上来的信息对信息进行处理后通知上层采取相应的形式去实
现。在这个构造函数中对每一个描述wifi状态的内部类的实例都使用add()函数把这些
内部类的实例添加到状态机中这两项主要工作对应的代码如下
mWifiMonitor = new WifiMonitor(this);
addState(mDefaultState);
addState(mInitialState, mDefaultState);
addState(mDriverUnloadingState, mDefaultState);
addState(mDriverUnloadedState, mDefaultState); addState(mDriverFailedState, mDriverUnloadedState);
addState(mDriverLoadingState, mDefaultState);
addState(mDriverLoadedState, mDefaultState);
addState(mSupplicantStartingState, mDefaultState);
addState(mSupplicantStartedState, mDefaultState);
addState(mDriverStartingState, mSupplicantStartedState);
addState(mDriverStartedState, mSupplicantStartedState);
addState(mScanModeState, mDriverStartedState);
addState(mConnectModeState, mDriverStartedState);
addState(mConnectingState, mConnectModeState);
addState(mConnectedState, mConnectModeState);
addState(mDisconnectingState, mConnectModeState);
addState(mDisconnectedState, mConnectModeState);
addState(mWaitForWpsCompletionState,
mConnectModeState);
addState(mDriverStoppingState, mSupplicantStartedState);
addState(mDriverStoppedState, mSupplicantStartedState);
addState(mSupplicantStoppingState, mDefaultState);
addState(mSoftApStartingState, mDefaultState);
addState(mSoftApStartedState, mDefaultState);
addState(mTetheringState, mSoftApStartedState);
addState(mTetheredState, mSoftApStartedState);
addState(mSoftApStoppingState, mDefaultState);
addState(mWaitForP2pDisableState, mDefaultState);
之后使用setInitialState(mInitialState)使wifi状态机进入初始化状态并通过函数start()开
启状态机。通过把各种wifi状态类的实例添加到wifi状态机以后通过sendmessage(Message
message)方法发送消息参数message会写进消息队列汇总wifi状态机会根据相应的
message调用相应的wifi状态类里面的函数对消息进行处理。例如wifi驱动的加载。
sendmessage(CMD_LOAD_DRIVER)发送加载驱动的消息到消息队列后会触发wifi状态机
的里面的状态类DriverLoadingState调用里面的方法去加载驱动。
4Wifimonitor
前面已经简单介绍过这个类主要功能就是阻塞等待wpa_supplicant传上来的命令后根
据命令来进行相应的处理。那么这个监视器是什么时候打开的呢我们来分析它的打开流程。
在系统起来之后把wifiservice 和connectivity的实例添加到android的service管理器这
前面已经介绍过之后调用wifiservice的方法wifi.checkAndStartWifi();实际上调用了
wifimachine的方法setWifiEnabled(wifiEnabled)在这个方法里面加载驱动开启
wpa_supplicant,对应的代码如下
if (enable) {
/* Argument is the state that is entered prior to load */
sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING,
0));
sendMessage(CMD_START_SUPPLICANT);
} else { sendMessage(CMD_STOP_SUPPLICANT);
/* Argument is the state that is entered upon success */
sendMessage(obtainMessage(CMD_UNLOAD_DRIVER,
WIFI_STATE_DISABLED, 0));
}
}
之后wifi状态机就会进入DriverLoadedState 状态通过native层调用wifi.c开启
wpa_supplicant的函数后就开启wifimonitor,也就是说监视器的开启必须是在驱动加载成功
以及开启wpa_supplicant后才开启相应的代码如下
if(WifiNative.startSupplicant()) {
if (DBG) log("Supplicant start successful");
mWifiMonitor.startMonitoring();
transitionTo(mSupplicantStartingState);
} else {
loge("Failed to start supplicant!");
sendMessage(obtainMessage(CMD_UNLOAD_DRIVER,
WIFI_STATE_UNKNOWN, 0));
}
介绍下wifimonitor是如何阻塞监听wpasupplicant传过来的信息的在监视器开启之后
在监视线层的循环体里面调用wifi.c里面的waitForEvent()函数来监听接收wpa_supplicant
传过来的消息相应的代码如下
public void run() {
if (connectToSupplicant()) {
// Send a message indicating that it is now possible to send commands
// to the supplicant
mStateMachine.sendMessage(SUP_CONNECTION_EVENT);
} else {
mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
return;
}
//noinspection InfiniteLoopStatement
for (;;) {
String eventStr = WifiNative.waitForEvent();
根据字符串eventStr的不同值调用相应的处理流程来对事件进行不同的处理上层做出相应
的回应。
5Wifinative
这一个类里面是调用native层里面的对应函数的接口的集合当我们在frameswork层希望
与下层进行交互调用下层的函数的时候都是先调用这个类里面相应的接口比如开启
wpa_supplicant就是通过WifiNative.startSupplicant()这个方式来调用native层的
android_net_wifi_startSupplicant最终调用wifi.c里面的wifi_start_supplicant()来开启
wpa_supplicanat。
二JNI层
对应的文件是android_net_wifi_WiFi.cpp。这个文件里面是调用wifi.c里面对应函数的接
口的集合提供给frameswork层的类Wifinative里面的函数调用。
三wifi.c文件
简单地说这个文件主要是实现驱动的加载和卸载wpa_supplicant的开启。我们公司
为配合skyworth的平台对多个dongle的支持对wifi.c做了部分修改修改部分主要是驱
动的加载部分。
在本文件中重新定义了一个结构体dongle_info,结构体的成员是三个函数指针针对不
同 的wifi设 备 对每 一 个wifi设 备 都重 写 一 个文 件 文件 路 径 是
hardware\amlogic\wifi\dongle_info 在文件中主要是实 现三个函数分别 是
xxx_loaddriver,xxx_unloaddriver,xxx_search,三个函数同时定义一个存储vid和pid号的数
组这个数组的作用是通过判断插入的usb wifi设备的vid_pid号是否与该表中的某一组
vid_pid号相等来决定是否加载对应的驱动。在wifi.c中定义一个dongle_info 类型的数组
把各个wifi设备的xxx_loaddriver,xxx_unloaddriver,xxx_search赋值给数组成员。本文件主要
有以下几个函数比较重要重点介绍下分为三个部分
驱动的加载卸载
wifi_load_driver()驱动的加载。我们的wifi驱动都是编译成ko文件wifi.h开头定义
了ko文件储存的位置#define WIFI_DRIVER_MODULE_PATH "/system/lib" 。这个
函数会被上层调用驱动加载的原理就是通过判断插入usb wifi设备的vid_pid号是否与相
对应的vid_pid表的某一组vid_pid号相等来决定是否加载对应的驱动如果有一组相等
则加载驱动成功。
wpa_unload_driver()
Wpa_supplicant相关
wifi_start_supplicant()上层要开启wpa_supplicant直接调用的是这个函数这个函数
实际上是调用wifi_start_supplicant_common(const char *config_file)
wifi_start_supplicant_common(const char *config_file):这个函数实际上为wifi.c进程与
wpa_supplicant进程相连做一些准备工作。
wifi_connect_to_supplicant()wifi.c进程与wpa_supplicant进程进行通信他们之间采
用socket的方式来实现进程间通信计算机网络的客户端与服务器的用socket通信的实现
方法相信每一个人都很熟悉进程间用socket来进行通信的实现方法也是类似包括创建
套接口绑定连接具体就不详细介绍了。函数调用的是wpa_ctrl.c里面的
wpa_ctrl_open(const char *ctrl_path)函数来实现。
数据的传输
wifi_command(const char *command, char *reply, size_t *reply_len)这个函数被jni调用
主要是上层发送命令通过这个函数传递给wpa_supplicant。这个函数实际上是调用
wifi_send_command(ctrl_conn, command, reply, reply_len)函数。
wifi_send_command(struct wpa_ctrl *ctrl, const char *cmd, char *reply, size_t *reply_len)
发送上层传递过来的命令给wpa_supplicant
wifi_wait_for_event(char *buf, size_t buflen)上层调用这个函数阻塞等待wpa_supplicant
传递上来的信息主要是调用wifi_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
来实现。 wifi_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)调用wpa_ctrl.c中的
wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)来接收wpa_supplicant传递过
来的信息。
四wpasupplicant层
wpa_supplicant本是开源项目源码被谷歌修改后加入android平台它主要是用来支
持WEPWPA/WPA2和WAPI无线协议和加密认证的而实际上的工作内容是通过socket
不管是wpa_supplicant与上层还是wpa_supplicant与驱动都采用socket通讯与驱动交互
上报数据给用户而用户可以通过socket发送命令给wpa_supplicant调动驱动来对WiFi芯
片操作。 简单的说wpa_supplicant就是WiFi驱动和用户的中转站外加对协议和加密认证
的支持。
这里主要介绍的是wpa_supplicant与驱动接口的联系。在drivers.h中定义了一个
wpa_driver_ops结构体结构体成员是一个个函数指针这些指针在哪里赋值呢接着往下
看在driviers.c里面都是不同驱动操作接口的集合wpa_driver_XXX_ops变量然后就是定
义一个驱动操作接口集合的数组根据宏定义添加对应的驱动操作接口集合的变量。不同的
驱动接口采用不同的文件来实现如果wpa_supplicant使用的是wext接口与驱动进行通信
那么就在driver_wext.c文件里面对wpa_driver_ops结构体里面的成员赋值这些成员指
针指向的函数也在这个文件里面实现。代码如下
const struct wpa_driver_ops wpa_driver_wext_ops = {
.name = "wext",
.desc = "Linux wireless extensions (generic)",
.get_bssid = wpa_driver_wext_get_bssid,
.get_ssid = wpa_driver_wext_get_ssid,
.set_key = wpa_driver_wext_set_key,
.set_countermeasures = wpa_driver_wext_set_countermeasures,
.scan2 = wpa_driver_wext_scan,
.get_scan_results2 = wpa_driver_wext_get_scan_results,
.deauthenticate = wpa_driver_wext_deauthenticate,
.disassociate = wpa_driver_wext_disassociate,
.associate = wpa_driver_wext_associate,
.init = wpa_driver_wext_init,
.deinit = wpa_driver_wext_deinit,
.add_pmkid = wpa_driver_wext_add_pmkid,
.remove_pmkid = wpa_driver_wext_remove_pmkid,
.flush_pmkid = wpa_driver_wext_flush_pmkid,
.get_capa = wpa_driver_wext_get_capa,
.set_operstate = wpa_driver_wext_set_operstate,
.get_radio_name = wext_get_radio_name,
#ifdef ANDROID
.signal_poll = wpa_driver_signal_poll,
.driver_cmd = wpa_driver_wext_driver_cmd,
#endif
};
那么还有一个疑问wpa_supplicant怎么知道使用哪个驱动接口呢在wpa_supplicant中 的 在wpa_supplicant_init_iface(struct wpa_supplicant
*wpa_s,struct wpa_interface *iface)函数里面
driver = iface->driver;
之后调用wpa_supplicant_set_driver(wpa_s, driver)来设置wpa_supplicant使用哪个接
口与驱动进行通信。
wpa_supplicant是为不同驱动和操作系统具有更好移植性而被设计的以便
在wpa_supplicant层不用实现驱动的具体接口就可以添加新的驱动程序在
wpa_supplicant结构中有一个wpa_drv_ops类型的drvier成员在wpa_supplicant
进程中经常通过Wpa_supplicant_XXX函数传递wpa_supplicant实例指针wpa_s
参数给wpa_drv_XXX函数来调用它在wpa_drv_XX中会通过
wpa_s->driver->XXX()的流程来调用通用驱动接口。
WIFI Settings应用程序位于
packages/apps/Settings/src/com/android/settings/wifi/
涉及到的文件
WifiSettings.java
frameworks部分
frameworks/base/services/java/com/android/server/
frameworks/base/wifi/java/android/net/wifi/
涉及到的文件有
SystemServer.java
WifiManager.java
WifiService.java
WifiStateMachine.java
Wifinative.java
JNI部分
frameworks/base/core/jni/android_net_wifi_Wifi.cpp
wifi管理库。
hardware/libhardware_legary/wifi/
涉及到的文件
Wifi.c
wifi用户空间的程序和库:
external/wpa_supplicant_8/
生成守护进程wpa_supplicant
一Framesworks层相应的类以及处理流程的介绍
1注册service
Android系统起来后SystemServer进程的名字实际上是system_server是由Zygote
进程创建的SystemServer进程创建后会调用SystemServer.java中的main函数main函数
回调SystemServer中的init2函数启动android services,在init2函数中启动一个ServerThread
线程在该线程的run函数中会创建一系列的Android Services,将与网络以及wifi相关的
service在systemserver.java里面的线程systemthread里面注册也就是把网络与wifi相关的
service的实例用ServiceManager.addService(String name, IBinder service)进行注册与wifi相
关的就是wifiservice类相关代码如下
try {
Slog.i(TAG, "Wi-Fi Service");
wifi = new WifiService(context);
ServiceManager.addService(Context.WIFI_SERVICE, wifi);
} catch (Throwable e) { reportWtf("starting Wi-Fi Service", e);
}
try {
Slog.i(TAG, "Connectivity Service");
connectivity = new ConnectivityService(
context, networkManagement, networkStats, networkPolicy);
ServiceManager.addService(Context.CONNECTIVITY_SERVICE,
connectivity);
networkStats.bindConnectivityManager(connectivity);
networkPolicy.bindConnectivityManager(connectivity);
wifi.checkAndStartWifi();
wifiP2p.connectivityServiceReady();
} catch (Throwable e) {
reportWtf("starting Connectivity Service", e);
}
上面的代码告诉我们将与网络相关的service实例networkStats与networkPolicy与
connectivityservice相关联所谓相关联我的理解是在networkStats与networkPolicy这
两个实例对应的service类中定义一个ConnectivityService类的父类的实例
2 Wifiservice简介
wifiservice是整个框架的核心部分application层触发事件后会调用这个service里
面的方法来处理事件包括加载驱动开启wpa_supplicant扫描AP都是调用这个service
里面的方法实现的实际上这些方法最终调用的是wifistatemachine里面的方法去发送消息。
由wifistatemachine里面的描述wifi事件的内部类去处理这些消息。
在这个类的构造函数中主要就是实例化了一个描述wifi状态机的类wifistatumachine 重写
了广播事件的onReceive函数。
3Wifistatusmachine简介以及android wifi信息传递机制与流程简介。
上面已经提到wifiservice中的方法最终是调用这个service里面的方法来实现的主要
就是对sendmessage()的封装。在这个service中需要传递到wpa_supplicant来实现wifi功
能的命令都在这个service中做了定义。针对每一个wifi状态都声明了一个内部类去描
述比如描述加载驱动开启wpa_supplicant等每一个状态类都有三个函数构成enter
statue().processmessage(),只不过不同类的这三个函数里面的程序不同而已。
Wifistatusmachine的构造函数里面主要的工作是实例化了wifi的监视器mWifiMonitor =
new WifiMonitor(this)这个监视器的作用下面再做解释简单地讲就是通过这个监视器
阻塞监听wpa_supplicant传递上来的信息对信息进行处理后通知上层采取相应的形式去实
现。在这个构造函数中对每一个描述wifi状态的内部类的实例都使用add()函数把这些
内部类的实例添加到状态机中这两项主要工作对应的代码如下
mWifiMonitor = new WifiMonitor(this);
addState(mDefaultState);
addState(mInitialState, mDefaultState);
addState(mDriverUnloadingState, mDefaultState);
addState(mDriverUnloadedState, mDefaultState); addState(mDriverFailedState, mDriverUnloadedState);
addState(mDriverLoadingState, mDefaultState);
addState(mDriverLoadedState, mDefaultState);
addState(mSupplicantStartingState, mDefaultState);
addState(mSupplicantStartedState, mDefaultState);
addState(mDriverStartingState, mSupplicantStartedState);
addState(mDriverStartedState, mSupplicantStartedState);
addState(mScanModeState, mDriverStartedState);
addState(mConnectModeState, mDriverStartedState);
addState(mConnectingState, mConnectModeState);
addState(mConnectedState, mConnectModeState);
addState(mDisconnectingState, mConnectModeState);
addState(mDisconnectedState, mConnectModeState);
addState(mWaitForWpsCompletionState,
mConnectModeState);
addState(mDriverStoppingState, mSupplicantStartedState);
addState(mDriverStoppedState, mSupplicantStartedState);
addState(mSupplicantStoppingState, mDefaultState);
addState(mSoftApStartingState, mDefaultState);
addState(mSoftApStartedState, mDefaultState);
addState(mTetheringState, mSoftApStartedState);
addState(mTetheredState, mSoftApStartedState);
addState(mSoftApStoppingState, mDefaultState);
addState(mWaitForP2pDisableState, mDefaultState);
之后使用setInitialState(mInitialState)使wifi状态机进入初始化状态并通过函数start()开
启状态机。通过把各种wifi状态类的实例添加到wifi状态机以后通过sendmessage(Message
message)方法发送消息参数message会写进消息队列汇总wifi状态机会根据相应的
message调用相应的wifi状态类里面的函数对消息进行处理。例如wifi驱动的加载。
sendmessage(CMD_LOAD_DRIVER)发送加载驱动的消息到消息队列后会触发wifi状态机
的里面的状态类DriverLoadingState调用里面的方法去加载驱动。
4Wifimonitor
前面已经简单介绍过这个类主要功能就是阻塞等待wpa_supplicant传上来的命令后根
据命令来进行相应的处理。那么这个监视器是什么时候打开的呢我们来分析它的打开流程。
在系统起来之后把wifiservice 和connectivity的实例添加到android的service管理器这
前面已经介绍过之后调用wifiservice的方法wifi.checkAndStartWifi();实际上调用了
wifimachine的方法setWifiEnabled(wifiEnabled)在这个方法里面加载驱动开启
wpa_supplicant,对应的代码如下
if (enable) {
/* Argument is the state that is entered prior to load */
sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING,
0));
sendMessage(CMD_START_SUPPLICANT);
} else { sendMessage(CMD_STOP_SUPPLICANT);
/* Argument is the state that is entered upon success */
sendMessage(obtainMessage(CMD_UNLOAD_DRIVER,
WIFI_STATE_DISABLED, 0));
}
}
之后wifi状态机就会进入DriverLoadedState 状态通过native层调用wifi.c开启
wpa_supplicant的函数后就开启wifimonitor,也就是说监视器的开启必须是在驱动加载成功
以及开启wpa_supplicant后才开启相应的代码如下
if(WifiNative.startSupplicant()) {
if (DBG) log("Supplicant start successful");
mWifiMonitor.startMonitoring();
transitionTo(mSupplicantStartingState);
} else {
loge("Failed to start supplicant!");
sendMessage(obtainMessage(CMD_UNLOAD_DRIVER,
WIFI_STATE_UNKNOWN, 0));
}
介绍下wifimonitor是如何阻塞监听wpasupplicant传过来的信息的在监视器开启之后
在监视线层的循环体里面调用wifi.c里面的waitForEvent()函数来监听接收wpa_supplicant
传过来的消息相应的代码如下
public void run() {
if (connectToSupplicant()) {
// Send a message indicating that it is now possible to send commands
// to the supplicant
mStateMachine.sendMessage(SUP_CONNECTION_EVENT);
} else {
mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
return;
}
//noinspection InfiniteLoopStatement
for (;;) {
String eventStr = WifiNative.waitForEvent();
根据字符串eventStr的不同值调用相应的处理流程来对事件进行不同的处理上层做出相应
的回应。
5Wifinative
这一个类里面是调用native层里面的对应函数的接口的集合当我们在frameswork层希望
与下层进行交互调用下层的函数的时候都是先调用这个类里面相应的接口比如开启
wpa_supplicant就是通过WifiNative.startSupplicant()这个方式来调用native层的
android_net_wifi_startSupplicant最终调用wifi.c里面的wifi_start_supplicant()来开启
wpa_supplicanat。
二JNI层
对应的文件是android_net_wifi_WiFi.cpp。这个文件里面是调用wifi.c里面对应函数的接
口的集合提供给frameswork层的类Wifinative里面的函数调用。
三wifi.c文件
简单地说这个文件主要是实现驱动的加载和卸载wpa_supplicant的开启。我们公司
为配合skyworth的平台对多个dongle的支持对wifi.c做了部分修改修改部分主要是驱
动的加载部分。
在本文件中重新定义了一个结构体dongle_info,结构体的成员是三个函数指针针对不
同 的wifi设 备 对每 一 个wifi设 备 都重 写 一 个文 件 文件 路 径 是
hardware\amlogic\wifi\dongle_info 在文件中主要是实 现三个函数分别 是
xxx_loaddriver,xxx_unloaddriver,xxx_search,三个函数同时定义一个存储vid和pid号的数
组这个数组的作用是通过判断插入的usb wifi设备的vid_pid号是否与该表中的某一组
vid_pid号相等来决定是否加载对应的驱动。在wifi.c中定义一个dongle_info 类型的数组
把各个wifi设备的xxx_loaddriver,xxx_unloaddriver,xxx_search赋值给数组成员。本文件主要
有以下几个函数比较重要重点介绍下分为三个部分
驱动的加载卸载
wifi_load_driver()驱动的加载。我们的wifi驱动都是编译成ko文件wifi.h开头定义
了ko文件储存的位置#define WIFI_DRIVER_MODULE_PATH "/system/lib" 。这个
函数会被上层调用驱动加载的原理就是通过判断插入usb wifi设备的vid_pid号是否与相
对应的vid_pid表的某一组vid_pid号相等来决定是否加载对应的驱动如果有一组相等
则加载驱动成功。
wpa_unload_driver()
Wpa_supplicant相关
wifi_start_supplicant()上层要开启wpa_supplicant直接调用的是这个函数这个函数
实际上是调用wifi_start_supplicant_common(const char *config_file)
wifi_start_supplicant_common(const char *config_file):这个函数实际上为wifi.c进程与
wpa_supplicant进程相连做一些准备工作。
wifi_connect_to_supplicant()wifi.c进程与wpa_supplicant进程进行通信他们之间采
用socket的方式来实现进程间通信计算机网络的客户端与服务器的用socket通信的实现
方法相信每一个人都很熟悉进程间用socket来进行通信的实现方法也是类似包括创建
套接口绑定连接具体就不详细介绍了。函数调用的是wpa_ctrl.c里面的
wpa_ctrl_open(const char *ctrl_path)函数来实现。
数据的传输
wifi_command(const char *command, char *reply, size_t *reply_len)这个函数被jni调用
主要是上层发送命令通过这个函数传递给wpa_supplicant。这个函数实际上是调用
wifi_send_command(ctrl_conn, command, reply, reply_len)函数。
wifi_send_command(struct wpa_ctrl *ctrl, const char *cmd, char *reply, size_t *reply_len)
发送上层传递过来的命令给wpa_supplicant
wifi_wait_for_event(char *buf, size_t buflen)上层调用这个函数阻塞等待wpa_supplicant
传递上来的信息主要是调用wifi_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
来实现。 wifi_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)调用wpa_ctrl.c中的
wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)来接收wpa_supplicant传递过
来的信息。
四wpasupplicant层
wpa_supplicant本是开源项目源码被谷歌修改后加入android平台它主要是用来支
持WEPWPA/WPA2和WAPI无线协议和加密认证的而实际上的工作内容是通过socket
不管是wpa_supplicant与上层还是wpa_supplicant与驱动都采用socket通讯与驱动交互
上报数据给用户而用户可以通过socket发送命令给wpa_supplicant调动驱动来对WiFi芯
片操作。 简单的说wpa_supplicant就是WiFi驱动和用户的中转站外加对协议和加密认证
的支持。
这里主要介绍的是wpa_supplicant与驱动接口的联系。在drivers.h中定义了一个
wpa_driver_ops结构体结构体成员是一个个函数指针这些指针在哪里赋值呢接着往下
看在driviers.c里面都是不同驱动操作接口的集合wpa_driver_XXX_ops变量然后就是定
义一个驱动操作接口集合的数组根据宏定义添加对应的驱动操作接口集合的变量。不同的
驱动接口采用不同的文件来实现如果wpa_supplicant使用的是wext接口与驱动进行通信
那么就在driver_wext.c文件里面对wpa_driver_ops结构体里面的成员赋值这些成员指
针指向的函数也在这个文件里面实现。代码如下
const struct wpa_driver_ops wpa_driver_wext_ops = {
.name = "wext",
.desc = "Linux wireless extensions (generic)",
.get_bssid = wpa_driver_wext_get_bssid,
.get_ssid = wpa_driver_wext_get_ssid,
.set_key = wpa_driver_wext_set_key,
.set_countermeasures = wpa_driver_wext_set_countermeasures,
.scan2 = wpa_driver_wext_scan,
.get_scan_results2 = wpa_driver_wext_get_scan_results,
.deauthenticate = wpa_driver_wext_deauthenticate,
.disassociate = wpa_driver_wext_disassociate,
.associate = wpa_driver_wext_associate,
.init = wpa_driver_wext_init,
.deinit = wpa_driver_wext_deinit,
.add_pmkid = wpa_driver_wext_add_pmkid,
.remove_pmkid = wpa_driver_wext_remove_pmkid,
.flush_pmkid = wpa_driver_wext_flush_pmkid,
.get_capa = wpa_driver_wext_get_capa,
.set_operstate = wpa_driver_wext_set_operstate,
.get_radio_name = wext_get_radio_name,
#ifdef ANDROID
.signal_poll = wpa_driver_signal_poll,
.driver_cmd = wpa_driver_wext_driver_cmd,
#endif
};
那么还有一个疑问wpa_supplicant怎么知道使用哪个驱动接口呢在wpa_supplicant中 的 在wpa_supplicant_init_iface(struct wpa_supplicant
*wpa_s,struct wpa_interface *iface)函数里面
driver = iface->driver;
之后调用wpa_supplicant_set_driver(wpa_s, driver)来设置wpa_supplicant使用哪个接
口与驱动进行通信。
wpa_supplicant是为不同驱动和操作系统具有更好移植性而被设计的以便
在wpa_supplicant层不用实现驱动的具体接口就可以添加新的驱动程序在
wpa_supplicant结构中有一个wpa_drv_ops类型的drvier成员在wpa_supplicant
进程中经常通过Wpa_supplicant_XXX函数传递wpa_supplicant实例指针wpa_s
参数给wpa_drv_XXX函数来调用它在wpa_drv_XX中会通过
wpa_s->driver->XXX()的流程来调用通用驱动接口。