android系统学习八

Android的联接部分

Wifi部分

Wifi的基本架构

自上而下包括的一些内容:

Linux内核的标准wifi驱动程序和协议

Wap_supplicant可执行程序(WAP应用层认证客户端)

WifiHAL

WIFIJNI接口

Wifijava框架

Wifi的相关应用

Wifi的结构图如下:

Wifi的本地实现(主要包括wap_supplicantwap_supplicant适配层)

WAPwifiprotectedAccess

Wap_supplicantWAP应用层认证客户端,负责认证完成相关的登陆和加密工作,他是一个开源的

代码路径为:\external\wpa_supplicant文件名为:wpq_ctrl.c

部分代码如下:

最终生成动态库libwap_client.so

Wap_supplicant是一个独立的守护进程,其通信是通过socket协议定完成

Wap_supplicantwext驱动接口的联系

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_commandwifi_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的一部分

Wifijava部分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

wifiManagerwifi部分与外界的接口wifiwatchDogService也是使用wifiManager来进行具体操作

wifiService是服务器端的实现,处理实际的驱动加载\、扫描,连接,断开

根据客户端的不同命令,调用相应的nativeWifi底层实现 当接收到客户端消息命令后,转换成对应的自身消息加入消息队列,方便客户端调用,在wifiHandlerhandlerMessage中来处理对应的消息

对于底层上报的事件,wifiService一般调用wifiStateTracker

wifiStateTracker负责电源控制,设置电源管理模式,其核心是wifiMonitor所实现的事件轮询机制(关键函数是wifiNative..waitForEvent阻塞式函数),该类也是与外部的接口,通过发送广播来完成消息的传递

wifiMontor的通知机制是将底层事件转换成wifistateTracker能识别的消息

wifiWatchDogServiceconnectivityService启动的服务,它的作用是监控同一网络内的接入点(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中调用wifiManagersetwifiEnagled(null,true);

wifimanager.setwifiEnable()通过Binder机制调用wifiService.setWifiEnabled

wifiService.setWifiService.setWifiEnabledMESSAGE_ENABLE_WIFI消息发送到自已的消息队列

wifiService通过wifHandlerhandleMessage处理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;

}

2wifi开启完成后,接下就是搜索AP

启动supplient守护进程,启动MonitorThread开始监听supplient的事件。

****SettingwifiLayer.attemptScan()调用wifiManager.startScan();*****

wifi2.3之后就没有wifiLayer类了,取而代之的是wifiSettingwifiSetting中有一个扫描类,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开启的wifiMonitormonitorThread可以获取此消息,

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);

猜你喜欢

转载自retacn-yue.iteye.com/blog/1708526