Android的联接部分
Wifi部分
Wifi的基本架构
自上而下包括的一些内容:
Linux内核的标准wifi驱动程序和协议
Wap_supplicant可执行程序(WAP应用层认证客户端)
Wifi的HAL
WIFI的JNI接口
Wifi的java框架
Wifi的相关应用
Wifi的结构图如下:
Wifi的本地实现(主要包括wap_supplicant和wap_supplicant适配层)
WAP是wifiprotectedAccess
Wap_supplicant是WAP应用层认证客户端,负责认证完成相关的登陆和加密工作,他是一个开源的
代码路径为:\external\wpa_supplicant文件名为:wpq_ctrl.c
部分代码如下:
最终生成动态库libwap_client.so
Wap_supplicant是一个独立的守护进程,其通信是通过socket协议定完成
Wap_supplicant和wext驱动接口的联系
在driver.h头文件中,部分代码如下:
//该结构体是扫描结果的通用格式
structwpa_scan_result{
u8bssid[ETH_ALEN];
u8ssid[32];
size_tssid_len;
u8wpa_ie[SSID_MAX_WPA_IE_LEN];
size_twpa_ie_len;
u8rsn_ie[SSID_MAX_WPA_IE_LEN];
size_trsn_ie_len;
intfreq;
u16caps;
intqual;
intnoise;
intlevel;
intmaxrate;
};
//操作函数集合,所有驱动类型的一个接口封装包
structwpa_driver_ops{
constchar*name;
constchar*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结构
//根据UDPUNIX和命名管道三种domain类型来定义通信实体
structwpa_ctrl*wpa_ctrl_open(constchar*ctrl_path)
{
structwpa_ctrl*ctrl;
staticintcounter=0;
ctrl=os_malloc(sizeof(*ctrl));
if(ctrl==NULL)
returnNULL;
os_memset(ctrl,0,sizeof(*ctrl));
ctrl->s=socket(PF_UNIX,SOCK_DGRAM,0);
if(ctrl->s<0){
os_free(ctrl);
returnNULL;
}
ctrl->local.sun_family=AF_UNIX;
os_snprintf(ctrl->local.sun_path,sizeof(ctrl->local.sun_path),
#ifdefANDROID
"%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,(structsockaddr*)&ctrl->local,
sizeof(ctrl->local))<0){
close(ctrl->s);
os_free(ctrl);
returnNULL;
}
Wpa_supplicant.h:
部分代码如下:
//wpa的事件类型
typedefenumwpa_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事件,并以字符串的形式返回
intwifi_wait_for_event(char*buf,size_tlen);
//将命令发送到wifi系统下层的功能,
intwifi_command(constchar*command,char*reply,size_t*reply_len);
实现文件路径为:\hardware\libhardware_legacy\wifi
在实现文件中
//
intwifi_wait_for_event(char*buf,size_tbuflen)
{
size_tnread=buflen-1;
intfd;
fd_setrfds;
intresult;
structtimevaltval;
structtimeval*tptr;
if(monitor_conn==NULL){
LOGD("Connectionclosed\n");
strncpy(buf,WPA_EVENT_TERMINATING"-connectionclosed",buflen-1);
buf[buflen-1]='\0';
returnstrlen(buf);
}
//调用此方法来接收一次wpa_supplication
result=wpa_ctrl_recv(monitor_conn,buf,&nread);
if(result<0){
LOGD("wpa_ctrl_recvfailed:%s\n",strerror(errno));
strncpy(buf,WPA_EVENT_TERMINATING"-recverror",buflen-1);
buf[buflen-1]='\0';
returnstrlen(buf);
}
buf[nread]='\0';
/*LOGD("wait_for_event:result=%dnread=%dstring=\"%s\"\n",result,nread,buf);*/
/*CheckforEOFonthesocket*/
if(result==0&&nread==0){
/*Fabricateaneventtopassup*/
LOGD("ReceivedEOFonsupplicantsocket\n");
strncpy(buf,WPA_EVENT_TERMINATING"-signal0received",buflen-1);
buf[buflen-1]='\0';
returnstrlen(buf);
}
/*
*Eventsstringsareintheformat
*
*<N>CTRL-EVENT-XXX
*
*whereNisthemessagelevelinnumericalform(0=VERBOSE,1=DEBUG,
*etc.)andXXXistheeventname.Thelevelinformationisnotuseful
*tous,sostripitoff.
*/
if(buf[0]=='<'){
char*match=strchr(buf,'>');
if(match!=NULL){
nread-=(match+1-buf);
memmove(buf,match+1,nread+1);
}
}
returnnread;
}
//wifi_command是wifi_send_command的封装
intwifi_send_command(structwpa_ctrl*ctrl,constchar*cmd,char*reply,size_t*reply_len)
{
intret;
if(ctrl_conn==NULL){
LOGV("Notconnectedtowpa_supplicant-\"%s\"commanddropped.\n",cmd);
return-1;
}
//通过此方法发送命令给wpa_supplicant
ret=wpa_ctrl_request(ctrl,cmd,strlen(cmd),reply,reply_len,NULL);
if(ret==-2){
LOGD("'%s'commandtimedout.\n",cmd);
return-2;
}elseif(ret<0||strncmp(reply,"FAIL",4)==0){
return-1;
}
if(strncmp(cmd,"PING",4)==0){
reply[*reply_len]='\0';
}
return0;
}
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启动的服务,它的作用是监控同一网络内的接入点(AccessPoint),如果当前接入点的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
部分代码如下:
privatebooleansetWifiEnabledBlocking(booleanenable,booleanpersist,intuid){
finalinteventualWifiState=enable?WIFI_STATE_ENABLED:WIFI_STATE_DISABLED;
finalintwifiState=mWifiStateTracker.getWifiState();
if(wifiState==eventualWifiState){
returntrue;
}
if(enable&&isAirplaneModeOn()&&!mAirplaneModeOverwridden){
returnfalse;
}
/**
*MultiplecallstounregisterReceiver()causeexceptionandasystemcrash.
*Thiscanhappenifasupplicantislost(orfirmwarecrashoccurs)anduserindicates
*disablewifiatthesametime.
*AvoiddoingadisablewhenthecurrentWifistateisUNKNOWN
*TODO:Handledriverloadfailandsupplicantlostasseperatestates
*/
if((wifiState==WIFI_STATE_UNKNOWN)&&!enable){
returnfalse;
}
/**
*FailWifiifAPisenabled
*TODO:DeprecateWIFI_STATE_UNKNOWNandrenameit
*WIFI_STATE_FAILED
*/
if((mWifiApState==WIFI_AP_STATE_ENABLED)&&enable){
setWifiEnabledState(WIFI_STATE_UNKNOWN,uid);
returnfalse;
}
setWifiEnabledState(enable?WIFI_STATE_ENABLING:WIFI_STATE_DISABLING,uid);
if(enable){
//调用JNI层,加载wifi驱动
if(!mWifiStateTracker.loadDriver()){
Slog.e(TAG,"FailedtoloadWi-Fidriver.");
setWifiEnabledState(WIFI_STATE_UNKNOWN,uid);
returnfalse;
}
//调用JNI层开启supplicant
if(!mWifiStateTracker.startSupplicant()){
mWifiStateTracker.unloadDriver();
Slog.e(TAG,"Failedtostartsupplicantdaemon.");
setWifiEnabledState(WIFI_STATE_UNKNOWN,uid);
returnfalse;
}
registerForBroadcasts();
mWifiStateTracker.startEventLoop();
}else{
mContext.unregisterReceiver(mReceiver);
//Removenotification(itwillno-opifitisn'tvisible)
mWifiStateTracker.setNotificationVisible(false,0,false,0);
booleanfailedToStopSupplicantOrUnloadDriver=false;
if(!mWifiStateTracker.stopSupplicant()){
Slog.e(TAG,"Failedtostopsupplicantdaemon.");
setWifiEnabledState(WIFI_STATE_UNKNOWN,uid);
failedToStopSupplicantOrUnloadDriver=true;
}
/**
*Resetconnectionsanddisableinterface
*beforeweunloadthedriver
*/
mWifiStateTracker.resetConnections(true);
if(!mWifiStateTracker.unloadDriver()){
Slog.e(TAG,"FailedtounloadWi-Fidriver.");
if(!failedToStopSupplicantOrUnloadDriver){
setWifiEnabledState(WIFI_STATE_UNKNOWN,uid);
failedToStopSupplicantOrUnloadDriver=true;
}
}
if(failedToStopSupplicantOrUnloadDriver){
returnfalse;
}
}
//Success!
if(persist){
persistWifiEnabled(enable);
}
setWifiEnabledState(eventualWifiState,uid);
returntrue;
}
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(newIntent(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);