android系统学习八
来源:互联网 发布:如何打开usb端口 编辑:程序博客网 时间:2024/05/17 04:19
Android的联接部分
Wifi部分
Wifi的基本架构
自上而下包括的一些内容:
Linux 内核的标准wifi驱动程序和协议
Wap_supplicant可执行程序(WAP应用层认证客户端)
Wifi的HAL
WIFI的JNI接口
Wifi的java框架
Wifi的相关应用
Wifi的结构图如下:
Wifi的本地实现 (主要包括wap_supplicant和wap_supplicant适配层)
WAP是wifi protected Access
Wap_supplicant是WAP 应用层认证客户端, 负责认证完成相关的登陆和加密工作,他是一个开源的
代码路径为: \external\wpa_supplicant 文件名为:wpq_ctrl.c
部分代码如下:
最终生成动态库libwap_client.so
Wap_supplicant是一个独立的守护进程 ,其通信是通过socket协议定完成
Wap_supplicant和wext驱动接口的联系
在driver.h头文件中,部分代码如下:
//该结构体是扫描结果的通用格式
struct wpa_scan_result {
u8 bssid[ETH_ALEN];
u8 ssid[32];
size_t ssid_len;
u8 wpa_ie[SSID_MAX_WPA_IE_LEN];
size_t wpa_ie_len;
u8 rsn_ie[SSID_MAX_WPA_IE_LEN];
size_t rsn_ie_len;
int freq;
u16 caps;
int qual;
int noise;
int level;
int maxrate;
};
//操作函数集合,所有驱动类型的一个接口封装包
struct wpa_driver_ops {
const char *name;
const char *desc;
int (*get_bssid)(void *priv, u8 *bssid);
}
Driver_wext.h : 声明了该驱动的一些对应驱动API接口的函数
Driver_wext.c: 最后 初始化了一个wpa_drv_pos 变量
Drivers.c 文件 : 主要定义了不同驱动操作接口的集合
Driver_xxx.h: 是不同驱动接口头文件 声明了操作接口
Driver_xxx.c: 实现操作接口
Wpq_supplicant守护进程是为不同驱动和操作系统具有更好的移植性而设计的,以便在wpa_supplicant层不用实现驱动的具体接口就可以添加新的驱动程序
Wpa_supplicant_xxx函数传递wpa_supplicant实例指针wpa_s参数给wpa_drv_xxx来调用他,
Wpa_drv_xx会通过wpa_s->driver->xxx()来调用通用驱动接口
Wpa_ctrl.h: 声明了几个用于socket通信的函数接口
Wpq_ctrl.c: 定义了一个wpa_ctrl结构
//根据UDP UNIX和命名管道三种domain类型来定义通信实体
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
{
struct wpa_ctrl *ctrl;
static int counter = 0;
ctrl = os_malloc(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
os_memset(ctrl, 0, sizeof(*ctrl));
ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
if (ctrl->s < 0) {
os_free(ctrl);
return NULL;
}
ctrl->local.sun_family = AF_UNIX;
os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
#ifdef ANDROID
"%s/%s%d-%d", local_socket_dir, local_socket_prefix,
getpid(), counter++);
#else /* ANDROID */
"/tmp/wpa_ctrl_%d-%d", getpid(), counter++);
#endif
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local)) < 0) {
close(ctrl->s);
os_free(ctrl);
return NULL;
}
Wpa_supplicant.h :
部分代码如下:
//wpa 的事件类型
typedef enum wpa_event_type {}
Wpa_supplicant_i.h:
Wpq_suppliant.c文件中定义的很多函数是在该头文件中声明的,而不是在wpa_supplicant.h中
Wap_supplicant的结构如下:
Wpa-_supplicant 适配层
在android 中作为wifi部分的硬件抽像层来使用,主要用于封装与wpa_supplicant守护进程的通信(加载、控制、消息监控)
Wpa_supplicant适配层的头文件路径为:
\hardware\libhardware_legacy\include\hardware_legacy\wifi.h
头文件中定义了以下几个重要的方法:
//事件的进入通道,这个函数被阻塞,直到收到一个wifi事件,并以字符串的形式返回
int wifi_wait_for_event(char *buf, size_t len);
//将命令发送到wifi系统下层的功能,
int wifi_command(const char *command, char *reply, size_t *reply_len);
实现文件路径为:\hardware\libhardware_legacy\wifi
在实现文件中
//
int wifi_wait_for_event(char *buf, size_t buflen)
{
size_t nread = buflen - 1;
int fd;
fd_set rfds;
int result;
struct timeval tval;
struct timeval *tptr;
if (monitor_conn == NULL) {
LOGD("Connection closed\n");
strncpy(buf, WPA_EVENT_TERMINATING " - connection closed", buflen-1);
buf[buflen-1] = '\0';
return strlen(buf);
}
//调用此方法来接收一次wpa_supplication
result = wpa_ctrl_recv(monitor_conn, buf, &nread);
if (result < 0) {
LOGD("wpa_ctrl_recv failed: %s\n", strerror(errno));
strncpy(buf, WPA_EVENT_TERMINATING " - recv error", buflen-1);
buf[buflen-1] = '\0';
return strlen(buf);
}
buf[nread] = '\0';
/* LOGD("wait_for_event: result=%d nread=%d string=\"%s\"\n", result, nread, buf); */
/* Check for EOF on the socket */
if (result == 0 && nread == 0) {
/* Fabricate an event to pass up */
LOGD("Received EOF on supplicant socket\n");
strncpy(buf, WPA_EVENT_TERMINATING " - signal 0 received", buflen-1);
buf[buflen-1] = '\0';
return strlen(buf);
}
/*
* Events strings are in the format
*
* <N>CTRL-EVENT-XXX
*
* where N is the message level in numerical form (0=VERBOSE, 1=DEBUG,
* etc.) and XXX is the event name. The level information is not useful
* to us, so strip it off.
*/
if (buf[0] == '<') {
char *match = strchr(buf, '>');
if (match != NULL) {
nread -= (match+1-buf);
memmove(buf, match+1, nread+1);
}
}
return nread;
}
//wifi_command是wifi_send_command的封装
int wifi_send_command(struct wpa_ctrl *ctrl, const char *cmd, char *reply, size_t *reply_len)
{
int ret;
if (ctrl_conn == NULL) {
LOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
return -1;
}
// 通过此方法发送命令给wpa_supplicant
ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), reply, reply_len, NULL);
if (ret == -2) {
LOGD("'%s' command timed out.\n", cmd);
return -2;
} else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
return -1;
}
if (strncmp(cmd, "PING", 4) == 0) {
reply[*reply_len] = '\0';
}
return 0;
}
WIFI的适配层是libhardware_legacy.so的一部分
Wifi的java部分jni部分
JNI部分的源程代码路径为下:
\frameworks\base\core\jni\android_net_wifi_wifi.cpp
在这里实现的本地函数,都是通过调用wpa_supplicant适配层的接口实现的
Java部分实现代码路径为:
\frameworks\base\services\java\com\android\server //wifi服务层的内容
\frameworks\base\wifi\java\android\net\wifi //wifi服务的接口
由上图可以看出: wifiNative.java 类提供 wifiService类、wifiStateTracker类和wifiMonitor类的底层操作支持
Wifi系统的核心部分是根据IWifiManager接口所创建的Binder服务器端(wifiService)和客户端(wifiManager)
IWifiManager.aidl编译后生成IWifiManager.java 。并生成IWifiManager.Stub( 服务器端抽象类)和IWifiManager.Stub.Proxy(客户端代理类)
wifiService通过继承IWifiManager.Stub实现,
客户端通过getService()取得IWifiManager.Stub.Proxy ,将其作为参数传递给wifiManager
wifiManager 是wifi部分与外界的接口 wifiwatchDogService也是使用wifiManager来进行具体操作
wifiService 是服务器端的实现,处理实际的驱动加载\、扫描,连接,断开
根据客户端的不同命令,调用相应的nativeWifi底层实现 当接收到客户端消息命令后,转换成对应的自身消息加入消息队列,方便客户端调用,在wifiHandler的handlerMessage中来处理对应的消息
对于底层上报的事件 ,wifiService一般调用wifiStateTracker
wifiStateTracker负责电源控制,设置电源管理模式,其核心是wifiMonitor所实现的事件轮询机制( 关键函数是wifiNative..waitForEvent阻塞式函数),该 类也是与外部的接口, 通过发送广播来完成消息的传递
wifiMontor的通知机制是将底层事件转换成wifistateTracker能识别的消息
wifiWatchDogService 是connectivityService启动的服务, 它的作用是监控同一网络内的接入点(Access Point),如果当前接入点的DNS无法 ping通,就自动切入到下一个接入点
在初始化时,通过registerForWifiBroadcasts注册广播接收,捕获wifiStateTracker发出的通知,
开启一个wifiWatchdogThread线程来处理消息
Settings 中的wifi设置
原代码的路径为:\packages\apps\Settings\src\com\android\settings\wifi
网络设置的实际功能还是调用wifiManager来实现的, 同样注册一个广播接收者来接收wifistateTracker发出的消息
wifiEnable是用来设置 wifi的开关
Wifi工作流程实例
例; 一个AP的联接流程
1 开启wifi
在wifiEnable中调用wifiManager。setwifiEnagled(null, true);
wifimanager.setwifiEnable()通过Binder机制调用wifiService.setWifiEnabled
wifiService.setWifiService.setWifiEnabled将MESSAGE_ENABLE_WIFI消息发送到自已的消息队列
wifiService 通过wifHandler的handleMessage处理MESSAGE_ENABLE_WIFI,
调用setWifiEnableBlocking
setWifiEnableBlocking调用setWifiEnabledState,向外发送WIFI_STATE_CHANGED_ACTIONT通知消息
另外一些初始化工作
设置当前状态、加载wifi驱动、开启wpa_supplicant、开启wifiStateTracker、注册广播接收者 接收wifiStateTracker的消息
wifiService.java的代码路径为:\frameworks\base\services\java\com\android\server
部分代码如下:
private boolean setWifiEnabledBlocking(boolean enable, boolean persist, int uid) {
final int eventualWifiState = enable ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED;
final int wifiState = mWifiStateTracker.getWifiState();
if (wifiState == eventualWifiState) {
return true;
}
if (enable && isAirplaneModeOn() && !mAirplaneModeOverwridden) {
return false;
}
/**
* Multiple calls to unregisterReceiver() cause exception and a system crash.
* This can happen if a supplicant is lost (or firmware crash occurs) and user indicates
* disable wifi at the same time.
* Avoid doing a disable when the current Wifi state is UNKNOWN
* TODO: Handle driver load fail and supplicant lost as seperate states
*/
if ((wifiState == WIFI_STATE_UNKNOWN) && !enable) {
return false;
}
/**
* Fail Wifi if AP is enabled
* TODO: Deprecate WIFI_STATE_UNKNOWN and rename it
* WIFI_STATE_FAILED
*/
if ((mWifiApState == WIFI_AP_STATE_ENABLED) && enable) {
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
return false;
}
setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid);
if (enable) {
//调用JNI层,加载wifi驱动
if (!mWifiStateTracker.loadDriver()) {
Slog.e(TAG, "Failed to load Wi-Fi driver.");
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
return false;
}
//调用JNI层开启supplicant
if (!mWifiStateTracker.startSupplicant()) {
mWifiStateTracker.unloadDriver();
Slog.e(TAG, "Failed to start supplicant daemon.");
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
return false;
}
registerForBroadcasts();
mWifiStateTracker.startEventLoop();
} else {
mContext.unregisterReceiver(mReceiver);
// Remove notification (it will no-op if it isn't visible)
mWifiStateTracker.setNotificationVisible(false, 0, false, 0);
boolean failedToStopSupplicantOrUnloadDriver = false;
if (!mWifiStateTracker.stopSupplicant()) {
Slog.e(TAG, "Failed to stop supplicant daemon.");
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
failedToStopSupplicantOrUnloadDriver = true;
}
/**
* Reset connections and disable interface
* before we unload the driver
*/
mWifiStateTracker.resetConnections(true);
if (!mWifiStateTracker.unloadDriver()) {
Slog.e(TAG, "Failed to unload Wi-Fi driver.");
if (!failedToStopSupplicantOrUnloadDriver) {
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
failedToStopSupplicantOrUnloadDriver = true;
}
}
if (failedToStopSupplicantOrUnloadDriver) {
return false;
}
}
// Success!
if (persist) {
persistWifiEnabled(enable);
}
setWifiEnabledState(eventualWifiState, uid);
return true;
}
2 在wifi开启完成后,接下就是搜索AP
启动supplient守护进程, 启动MonitorThread开始监听supplient的事件。
**** Setting中wifiLayer.attemptScan()调用 wifiManager.startScan();*****
在wifi2.3之后就没有wifiLayer类了,取而代之的是wifiSetting 在wifiSetting中有一个扫描类,Scanner, 用于扫搜索AP
wifimanager.startScan()通过 Binder机制调用wifiService.starScan();
首先 MonitorThread会收到DRIVER_STATE事件, wifiNative.scanCommand()向supplient发送搜索AP的命令给wpa_supplicant, 中间经过JNI实现的doCommand,最终调用wap_supplicant适配层的wifiCommand 来完成发送过程
命令的最终响应由wpa_supplicant上报"SCAN-RESULT"消息,wifiStateTracker开启的wifiMonitor的monitorThread可以获取此消息,
handlerEvent 的处理方式是调用wifiStateTracker.notifyScanResultsAvailable;
发送广播:mContext.sendBroadcast(new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
wifiSetting中会得到这个消息.作相关的处理操作
连接AP
在supplient搜索AP结束时,monitorThread会收到SCAN_RESULTS
接下来会调用wifiNative.setScanResultHandlingCommand(normalMode)来让supplient自行去连接哪个AP,首先会去挑选信号强并没有密码的AP进行联接
wifiSettings会收到wifiManager.SCAN_RESULTE_AVAILABLE_ACTION广播
当supplient联接到一个AP时,monitorThread会收到CONNECTED事件,配置IP地址,
如果配置成功会发送EVENT_STATE_CHANGED, ConnectivityService就会根据网络优先级决定关掉以太网,android 为了省电会将之前的网络设为desable
mWifiManager.enableNetwork(networkId, false);
- android系统学习八
- android学习(八) 使用系统权限
- android系统开发(八)-SDCARD
- android系统开发(八)-SDCARD .
- android系统开发(八)-SDCARD
- android系统开发(八)-SDCARD
- android学习笔记(八)
- Android学习笔记の八
- Android学习笔记(八)
- Android学习笔记(八)
- Android学习八 Service服务
- html系统学习之八 <学习体会>
- cocos2d学习记录(八)-粒子系统
- 系统学习JavaWeb之八Session篇
- unity_NGUI系统学习(八)_Tween动画
- android 学习八 android selector的使用
- 系统学习机器学习之神经网络(八) --ADALINE网络
- 系统学习深度学习(八)--损失函数
- java 日期处理工具类 DateUtil 2
- android系统学习笔记七
- UNIX环境高级编程---标准I/O库
- 解决Eclipse+Pydev使用tornado框架应无法正确import tornado包错误
- 开启android手机的wifi热点 .
- android系统学习八
- kernel 编译选择不同的cpu
- DateUtil
- 为DataSnap系统服务程序添加描述
- 如何让Log shipping成功的备份信息不出现在SQL Server error log
- jquery 常用的N多插件
- redis数据库(zf)
- HDU——3664(递推公式)
- BSM与ITSM