欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android开发中Wifi连接流程分析

程序员文章站 2022-05-31 08:20:54
当我们在android手机上通过settings连接一个ap时,间接调用wifimanager的connect()方法: /** *connecttoanetworkwitht...

当我们在android手机上通过settings连接一个ap时,间接调用wifimanager的connect()方法:

/**

*connecttoanetworkwiththegivenconfiguration.thenetworkalso

*getsaddedtothesupplicantconfiguration.

*

*foranewnetwork,thisfunctionisusedinsteadofa

*sequenceofaddnetwork(),enablenetwork(),saveconfiguration()and

*reconnect()

*

*@paramconfigthesetofvariablesthatdescribetheconfiguration,

*containedina{@linkwificonfiguration}object.

*@paramlistenerforcallbacksonsuccessorfailure.canbenull.

*@throwsillegalstateexceptionifthewifimanagerinstanceneedstobe

*initializedagain

*

*@hide

*/

publicvoidconnect(wificonfigurationconfig,actionlistenerlistener){

if(config==null)thrownewillegalargumentexception("configcannotbenull");

validatechannel();

//useinvalid_network_idforarg1whenpassingaconfigobject

//arg1isusedtopassnetworkidwhenthenetworkalreadyexists

sasyncchannel.sendmessage(connect_network,wificonfiguration.invalid_network_id,

putlistener(listener),config);

}

/**

*connecttoanetworkwiththegivennetworkid.

*

*thisfunctionisusedinsteadofaenablenetwork(),saveconfiguration()and

*reconnect()

*

*@paramnetworkidthenetworkididentifiyingthenetworkinthe

*supplicantconfigurationlist

*@paramlistenerforcallbacksonsuccessorfailure.canbenull.

*@throwsillegalstateexceptionifthewifimanagerinstanceneedstobe

*initializedagain

*@hide

*/

publicvoidconnect(intnetworkid,actionlistenerlistener){

if(networkid<0)thrownewillegalargumentexception("networkidcannotbenegative");

validatechannel();

sasyncchannel.sendmessage(connect_network,networkid,putlistener(listener));

} connect()方法有两种形式,一种接受wificonfiguration对象,一种接受某个ap的networkid。wificonfiguration描述了一个wifi连接的所有配置信息。

wifimanager的servicehandler和wifiservice的clienthandler通过异步通道进行通信。所以这里通过asyncchannel机制,向wifiserviceimpl发送connect_network消息,可知在wifiserviceimpl::clienthandler中被处理:

/*clientcommandsareforwardedtostatemachine*/

casewifimanager.connect_network:

casewifimanager.save_network:{

wificonfigurationconfig=(wificonfiguration)msg.obj;

intnetworkid=msg.arg1;

if(msg.what==wifimanager.save_network){

slog.e("wifiserviceimpl","save"

+"nid="+integer.tostring(networkid)

+"uid="+msg.sendinguid

+"name="

+mcontext.getpackagemanager().getnameforuid(msg.sendinguid));

}

if(msg.what==wifimanager.connect_network){

slog.e("wifiserviceimpl","connect"

+"nid="+integer.tostring(networkid)

+"uid="+msg.sendinguid

+"name="

+mcontext.getpackagemanager().getnameforuid(msg.sendinguid));

}

if(config!=null&&isvalid(config)){

if(dbg)slog.d(tag,"connectwithconfig"+config);

mwifistatemachine.sendmessage(message.obtain(msg));

}elseif(config==null

&&networkid!=wificonfiguration.invalid_network_id){

if(dbg)slog.d(tag,"connectwithnetworkid"+networkid);

mwifistatemachine.sendmessage(message.obtain(msg));

}else{

slog.e(tag,"clienthandler.handlemessageignoringinvalidmsg="+msg);

if(msg.what==wifimanager.connect_network){

replyfailed(msg,wifimanager.connect_network_failed,

wifimanager.invalid_args);

}else{

replyfailed(msg,wifimanager.save_network_failed,

wifimanager.invalid_args);

}

}

break;

} clienthandler中并不做具体的连接动作,主要将connect_network消息被转发到wifistatemachine中,通过wifi状态机来驱动连接和dhcp过程 。connectmodestate处理:

casewifimanager.connect_network:

/**

*theconnectmessagecancontainanetworkidpassedasarg1onmessageor

*oraconfigpassedasobjonmessage.

*foranewnetwork,aconfigispassedtocreateandconnect.

*foranexistingnetwork,anetworkidispassed

*/

netid=message.arg1;

config=(wificonfiguration)message.obj;

mwificonnectionstatistics.numwifimanagerjoinattempt++;

booleanupdatedexisting=false;

/*savethenetworkconfig*/

if(config!=null){

//whenconnectingtoanaccesspoint,wifistatemachinewantstoupdatethe

//relevantconfigwithadministrativedata.thisupdateshouldnotbe

//considereda'real'update,thereforelockdownbydeviceownermustbe

//disregarded.

if(!recorduidifauthorized(config,message.sendinguid,

/*onlyannotate*/true)){

logw("notauthorizedtoupdatenetwork"

+"config="+config.ssid

+"cnid="+config.networkid

+"uid="+message.sendinguid);

replytomessage(message,wifimanager.connect_network_failed,

wifimanager.not_authorized);

break;

}

stringconfigkey=config.configkey(true/*allowcached*/);

wificonfigurationsavedconfig=

mwificonfigstore.getwificonfiguration(configkey);

if(savedconfig!=null){

//thereisanexistingconfigwiththisnetid,butitwasn'texposed

//(eitherauto_join_deletedorephemeral;seewificonfigstore#

//getconfigurednetworks).removethosebitsandupdatetheconfig.

config=savedconfig;

logd("connect_networkupdatingexistingconfigwithid="+

config.networkid+"configkey="+configkey);

config.ephemeral=false;

config.autojoinstatus=wificonfiguration.auto_join_enabled;

updatedexisting=true;

}

result=mwificonfigstore.savenetwork(config,message.sendinguid);

netid=result.getnetworkid();

}

config=mwificonfigstore.getwificonfiguration(netid);

if(config==null){

logd("connect_networknoconfigforid="+integer.tostring(netid)+""

+msupplicantstatetracker.getsupplicantstatename()+"mystate"

+getcurrentstate().getname());

replytomessage(message,wifimanager.connect_network_failed,

wifimanager.error);

break;

}else{

stringwasskipped=config.autojoinbailedduetolowrssi?"skipped":"";

logd("connect_networkid="+integer.tostring(netid)

+"config="+config.ssid

+"cnid="+config.networkid

+"supstate="+msupplicantstatetracker.getsupplicantstatename()

+"mystate"+getcurrentstate().getname()

+"uid="+message.sendinguid

+wasskipped);

}

autoroamsetbssid(netid,"any");

if(message.sendinguid==process.wifi_uid

||message.sendinguid==process.system_uid){

//asasanitymeasure,clearthebssidinthesupplicantnetworkblock.

//ifsystemorwifisettingswanttoconnect,theywillnot

//specifythebssid.

//ifanapphoweverhadaddedabssidtothisconfiguration,andthebssid

//waswrong,thenwewouldforeverfailtoconnectuntilthatbssid

//iscleanedup.

clearconfigbssid(config,"connect_network");

}

if(deferforuserinput(message,netid,true)){

break;

}elseif(mwificonfigstore.getwificonfiguration(netid).userapproved==

wificonfiguration.user_banned){

replytomessage(message,wifimanager.connect_network_failed,

wifimanager.not_authorized);

break;

}

mautoroaming=wifiautojoincontroller.auto_join_idle;

/*tellautojointheuserdidtrytoconnecttothatnetworkiffromsettings*/

booleanpersist=

mwificonfigstore.checkconfigoverridepermission(message.sendinguid);

mwifiautojoincontroller.updateconfigurationhistory(netid,true,persist);

mwificonfigstore.setlastselectedconfiguration(netid);

diddisconnect=false;

if(mlastnetworkid!=wificonfiguration.invalid_network_id

&&mlastnetworkid!=netid){

/**supplicantwillignorethereconnectifwearecurrentlyassociated,

*hencetriggeradisconnect

*/

diddisconnect=true;

mwifinative.disconnect();

}

//makesurethenetworkisenabled,sincesupplicantwillnotreenableit

mwificonfigstore.enablenetworkwithoutbroadcast(netid,false);

if(mwificonfigstore.selectnetwork(config,/*updatepriorities=*/true,

message.sendinguid)&&mwifinative.reconnect()){

lastconnectattempttimestamp=system.currenttimemillis();

targetwificonfiguration=mwificonfigstore.getwificonfiguration(netid);

/*thestatetrackerhandlesenablingnetworksuponcompletion/failure*/

msupplicantstatetracker.sendmessage(wifimanager.connect_network);

replytomessage(message,wifimanager.connect_network_succeeded);

if(diddisconnect){

/*expectadisconnectionfromtheoldconnection*/

transitionto(mdisconnectingstate);

}elseif(updatedexisting&&getcurrentstate()==mconnectedstate&&

getcurrentwificonfiguration().networkid==netid){

//updatethecurrentsetofnetworkcapabilities,butstayinthe

//currentstate.

updatecapabilities(config);

}else{

/**

*directlygotodisconnectedstatewherewe

*processtheconnectioneventsfromsupplicant

**/

transitionto(mdisconnectedstate);

}

}else{

loge("failedtoconnectconfig:"+config+"netid:"+netid);

replytomessage(message,wifimanager.connect_network_failed,

wifimanager.error);

break;

}

break; 通过代码,可知主要的处理动作如下:

将connect()传过来的ap信息保存到wificonfigstore对象中

通过wificonfigstore::selectnetwork()函数更新wificonfigstore和config的priority优先级属性,最后更新到wpa_s配置文件中;enable当前要连接的ap,disable其他的ap

通过wifinative::reconnect()函数向wpa_s发送连接指令,连接选定的ap

连接选定的ap是通过调用wifinative方法向wpa_supplicant发送connect指令,wpa_s通知驱动进行连接;当底层无线连接成功后,framework就能通过wifimonitor接受到wpa_s上报的event消息:

/**

*handleallsupplicanteventsexceptstate-change

*@parameventtheeventtype

*@paramremaindertherestofthestringfollowingthe

*eventnameand"?—?"

*/

voidhandleevent(intevent,stringremainder){

if(dbg){

logdbg("handleevent"+integer.tostring(event)+""+remainder);

}

switch(event){

casedisconnected:

handlenetworkstatechange(networkinfo.detailedstate.disconnected,remainder);

break;

caseconnected:

handlenetworkstatechange(networkinfo.detailedstate.connected,remainder);

break;

casescan_results:

mstatemachine.sendmessage(scan_results_event);

break;

casescan_failed:

mstatemachine.sendmessage(scan_failed_event);

break;

caseunknown:

if(dbg){

logdbg("handleeventunknown:"+integer.tostring(event)+""+remainder);

}

break;

default:

break;

}

}

privatevoidhandlenetworkstatechange(networkinfo.detailedstatenewstate,stringdata){

stringbssid=null;

intnetworkid=-1;

intreason=0;

intind=-1;

intlocal=0;

matchermatch;

if(newstate==networkinfo.detailedstate.connected){

match=mconnectedeventpattern.matcher(data);

if(!match.find()){

if(dbg)log.d(tag,"handlenetworkstatechange:couldntfindbssidineventstring");

}else{

bssid=match.group(1);

try{

networkid=integer.parseint(match.group(2));

}catch(numberformatexceptione){

networkid=-1;

}

}

notifynetworkstatechange(newstate,bssid,networkid,reason);

}elseif(newstate==networkinfo.detailedstate.disconnected){

match=mdisconnectedeventpattern.matcher(data);

if(!match.find()){

if(dbg)log.d(tag,"handlenetworkstatechange:couldnotparsedisconnectstring");

}else{

bssid=match.group(1);

try{

reason=integer.parseint(match.group(2));

}catch(numberformatexceptione){

reason=-1;

}

try{

local=integer.parseint(match.group(3));

}catch(numberformatexceptione){

local=-1;

}

}

notifynetworkstatechange(newstate,bssid,local,reason);

}

}

/**

*sendthestatemachineanotificationthatthestateofwificonnectivity

*haschanged.

*@paramnewstatethenewnetworkstate

*@parambssidwhenthenewstateis{@linknetworkinfo.detailedstate#connected},

*thisisthemacaddressoftheaccesspoint.otherwise,it

*is{@codenull}.

*@paramnetidtheconfigurednetworkonwhichthestatechangeoccurred

*/

voidnotifynetworkstatechange(networkinfo.detailedstatenewstate,

stringbssid,intnetid,intreason){

if(newstate==networkinfo.detailedstate.connected){

messagem=mstatemachine.obtainmessage(network_connection_event,

netid,reason,bssid);

mstatemachine.sendmessage(m);

}else{

messagem=mstatemachine.obtainmessage(network_disconnection_event,

netid,reason,bssid);

if(dbg)logdbg("wifimonitornotifynetworkdisconnect:"

+bssid

+"reason="+integer.tostring(reason));

mstatemachine.sendmessage(m);

}

} wifimonitor与wpa_s之间的通信是通过socket建立的,如前几篇博客所介绍的那样:wifimonitor通过建立socket连接与wpa_s通信;每当wpa_s有事件要上报时,wifimonitor会解析该event,并转发到wifi状态机中。

wifimonitor接收到wpa_s的连接事件时,向wifistatemachine发送network_connection_event消息,通知状态机底层无线已经连接成功,下一步可以获取ip了。

转到wifistatemachine中,connectmodestate进行处理:

casewifimonitor.network_connection_event:

if(dbg)log("networkconnectionestablished");

mlastnetworkid=message.arg1;//成功加入到某无线网络中的ap的networkid

mlastbssid=(string)message.obj;

mwifiinfo.setbssid(mlastbssid);

mwifiinfo.setnetworkid(mlastnetworkid);

sendnetworkstatechangebroadcast(mlastbssid);

transitionto(mobtainingipstate);

break; 这里会将这次连接的ap的networkid保存下来,并进入到obtainingipstate状态去真正触发dhcp动作。l2connectedstate是obtainingipstate的父状态,看它的enter()函数:

publicvoidenter(){

mrssipolltoken++;

if(menablerssipolling){

sendmessage(cmd_rssi_poll,mrssipolltoken,0);

}

if(mnetworkagent!=null){

loge("havenetworkagentwhenenteringl2connected");

setnetworkdetailedstate(detailedstate.disconnected);

}

setnetworkdetailedstate(detailedstate.connecting);//更新当前的网络连接状态

if(!textutils.isempty(mtcpbuffersizes)){

mlinkproperties.settcpbuffersizes(mtcpbuffersizes);

}

mnetworkagent=newwifinetworkagent(gethandler().getlooper(),mcontext,

"wifinetworkagent",mnetworkinfo,mnetworkcapabilitiesfilter,

mlinkproperties,60);//此处创建一个networkagent对象用于向connectivityservice通知相应的网络配置更新操作

//wemustcleartheconfigbssid,asthewifichipsetmaydecidetoroam

//fromthispointonandhavingthebssidspecifiedinthenetworkblockwould

//causetheroamtofaileandthedevicetodisconnect

clearcurrentconfigbssid("l2connectedstate");

try{

mipreachabilitymonitor=newipreachabilitymonitor(

minterfacename,

newipreachabilitymonitor.callback(){

@override

publicvoidnotifylost(inetaddressip,stringlogmsg){

sendmessage(cmd_ip_reachability_lost,logmsg);

}

});

}catch(illegalargumentexceptione){

log.wtf("failedtocreateipreachabilitymonitor",e);

}

} 我们再看obtainingipstate::enter()方法看如何获取获取ip地址: [java]view plaincopy

print?

@override

publicvoidenter(){

if(dbg){

stringkey="";

if(getcurrentwificonfiguration()!=null){

key=getcurrentwificonfiguration().configkey();

}

log("enterobtainingipstatenetid="+integer.tostring(mlastnetworkid)

+""+key+""

+"roam="+mautoroaming

+"static="+mwificonfigstore.isusingstaticip(mlastnetworkid)

+"watchdog="+obtainingipwatchdogcount);

}

//resetlinkdebouncing,indicatingwehavesuccessfullyre-connectedtotheap

//wemightstillberoaming

linkdebouncing=false;

//sendeventtocm&networkchangebroadcast

setnetworkdetailedstate(detailedstate.obtaining_ipaddr);

//wemustcleartheconfigbssid,asthewifichipsetmaydecidetoroam

//fromthispointonandhavingthebssidspecifiedinthenetworkblockwould

//causetheroamtofaileandthedevicetodisconnect

clearcurrentconfigbssid("obtainingipaddress");

try{

mnwservice.enableipv6(minterfacename);

}catch(remoteexceptionre){

loge("failedtoenableipv6:"+re);

}catch(illegalstateexceptione){

loge("failedtoenableipv6:"+e);

}

if(!mwificonfigstore.isusingstaticip(mlastnetworkid)){

if(isroaming()){

renewdhcp();

}else{

//removeanyipaddressontheinterfaceincasewe'reswitchingfromstatic

//ipconfigurationtodhcp.thisissafebecauseifwegetherewhennot

//roaming,wedon'thaveausableaddress.

clearipv4address(minterfacename);

startdhcp();//dhcp过程启动

}

obtainingipwatchdogcount++;

logd("startdhcpwatchdog"+obtainingipwatchdogcount);

//getlinklayerstatssoaswegetfreshtxpacketcounters

getwifilinklayerstats(true);

sendmessagedelayed(obtainmessage(cmd_obtaining_ip_address_watchdog_timer,

obtainingipwatchdogcount,0),obtaining_ip_address_guard_timer_msec);

}else{

//stopanyrunningdhcpbeforeassigningstaticip

stopdhcp();

staticipconfigurationconfig=mwificonfigstore.getstaticipconfiguration(

mlastnetworkid);

if(config.ipaddress==null){

logd("staticiplacksaddress");

sendmessage(cmd_static_ip_failure);

}else{

interfaceconfigurationifcg=newinterfaceconfiguration();

ifcg.setlinkaddress(config.ipaddress);

ifcg.setinterfaceup();

try{

mnwservice.setinterfaceconfig(minterfacename,ifcg);

if(dbg)log("staticipconfigurationsucceeded");

dhcpresultsdhcpresults=newdhcpresults(config);

sendmessage(cmd_static_ip_success,dhcpresults);

}catch(remoteexceptionre){

loge("staticipconfigurationfailed:"+re);

sendmessage(cmd_static_ip_failure);

}catch(illegalstateexceptione){

loge("staticipconfigurationfailed:"+e);

sendmessage(cmd_static_ip_failure);

}

}

}

} 这里wifi分了两种连接方式,static ip和dhcp。这里区分静态和dhcp是通过wificonfiguration对象来处理的。wificonfiguration代表一个配置过的ap连接,主要包含ipassignment(标识上层的连接方式是静态还是dhcp)、ap的networkid、ap的名字等等。

我们主要看动态获取ip的过程。进入dhcp流程之前,会先清除当前的ip地址信息。着重看startdhcp()函数处理:

voidstartdhcp(){

maybeinitdhcpstatemachine();//确保初始化wifistatemachine持有的mdhcpstatemachine对象,会传入当前的wifistatemachine对象,用来回发消息

mdhcpstatemachine.registerforpredhcpnotification();//注册mregisteredforpredhcpnotification字段为true,表明我们在发送dhcp包之前需要做一些准备工作

mdhcpstatemachine.sendmessage(dhcpstatemachine.cmd_start_dhcp);//发送开始dhcp的消息

} dhcpstatemachine是一个小状态机,它主要处理dhcp下的ip地址获取过程,并将获取到的dhcp结果告知wifistatemachine。看dhcpstatemachine处理该消息的过程:

casecmd_start_dhcp:

if(mregisteredforpredhcpnotification){

/*notifycontrollerbeforestartingdhcp*/

mcontroller.sendmessage(cmd_pre_dhcp_action);

transitionto(mwaitbeforestartstate);

}else{

if(rundhcpstart()){

transitionto(mrunningstate);

}

}

break; 由于我们之前设置了mregisteredforpredhcpnotification为true,这里会向wifistatemachine发送cmd_pre_dhcp_action消息,告知wifi状态机做一些dhcp之前的预处理工作。l2connectedstate处理该消息:

casedhcpstatemachine.cmd_pre_dhcp_action:

handlepredhcpsetup();

break;

voidhandlepredhcpsetup(){

mdhcpactive=true;

if(!mbluetoothconnectionactive){

/*

*thereareproblemssettingthewi-fidriver'spower

*modetoactivewhenbluetoothcoexistencemodeis

*enabledorsense.

*

*wesetwi-fitoactivemodewhen

*obtaininganipaddressbecausewe'vefound

*compatibilityissueswithsomerouterswithlowpower

*mode.

*

*inorderforthisactivepowermodetoproperlybeset,

*wedisablecoexistencemodeuntilwe'redonewith

*obtaininganipaddress.oneexceptionisifwe

*arecurrentlyconnectedtoaheadset,sincedisabling

*coexistencewouldinterruptthatconnection.

*/

//disablethecoexistencemode

mwifinative.setbluetoothcoexistencemode(

mwifinative.bluetooth_coexistence_mode_disabled);

}

//disablepowersaveandsuspendoptimizationsduringdhcp

//note:theorderhereisimportantfornow.brcmdriverchanges

//powersettingswhenwecontrolsuspendmodeoptimizations.

//todo:removethiscommentwhenthedriverisfixed.

setsuspendoptimizationsnative(suspend_due_to_dhcp,false);

mwifinative.setpowersave(false);

//updatelinklayerstats

getwifilinklayerstats(false);

/*p2pdiscoverybreaksdhcp,shutitdowninordertogetthroughthis*/

messagemsg=newmessage();

msg.what=wifip2pserviceimpl.block_discovery;

msg.arg1=wifip2pserviceimpl.enabled;

msg.arg2=dhcpstatemachine.cmd_pre_dhcp_action_complete;

msg.obj=mdhcpstatemachine;

mwifip2pchannel.sendmessage(msg);

} 从注释可知,为了保证wifi dhcp过程的顺利进行,对bluetooth、power和p2p都做了处理工作,其中:蓝牙会disable the coexistence mode;停止p2p的discovery过程,防止影响dhcp流程。md_pre_dhcp_action_complete消息会在wifip2pserviceimpl设置完p2p部分后,被转发到dhcpstatemachine,告知预处理工作已经结束,可以进行dhcp了。看dhcpstatemachine中的消息处理:

casecmd_pre_dhcp_action_complete:

if(rundhcpstart()){

transitionto(mrunningstate);

}else{

transitionto(mpollingstate);

}

break;

privatebooleanrundhcpstart(){

/*stopanyexistingdhcpdaemonbeforestartingnew*/

networkutils.stopdhcp(minterfacename);//在启动新的dhcp流程之前,停止当前正在进行的dhcp过程

mdhcpresults=null;

if(dbg)log.d(tag,"dhcprequeston"+minterfacename);

if(!networkutils.startdhcp(minterfacename)||!dhcpsucceeded()){

log.e(tag,"dhcprequestfailedon"+minterfacename+":"+

networkutils.getdhcperror());

mcontroller.obtainmessage(cmd_post_dhcp_action,dhcp_failure,0)

.sendtotarget();

returnfalse;

}

returntrue;

} 调用networkutils.startdhcp()方法启动dhcp流程去获取ip地址,调用dhcpsucceeded()方法获取该次dhcp的dhcpresults对象,它包含了ip地址、网关、dns等等地址信息。

privatebooleandhcpsucceeded(){

dhcpresultsdhcpresults=newdhcpresults();

if(!networkutils.getdhcpresults(minterfacename,dhcpresults)){

returnfalse;

}

if(dbg)log.d(tag,"dhcpresultsfoundfor"+minterfacename);

longleaseduration=dhcpresults.leaseduration;//inttolongconversion

//sanitycheckforrenewal

if(leaseduration>=0){

//todo:wouldbegoodtonotifytheuserthathisnetworkconfigurationis

//badandthatthedevicecannotrenewbelowmin_renewal_time_secs

if(leaseduration leaseduration=min_renewal_time_secs;

}

//doitabitearlierthanhalftheleasedurationtime

//tobeatthenativedhcpclientandavoidextrapackets

//48%foronehourleasetime=29minutes

malarmmanager.setexact(alarmmanager.elapsed_realtime_wakeup,

systemclock.elapsedrealtime()+

leaseduration*480,//inmilliseconds

mdhcprenewalintent);

}else{

//infiniteleasetime,norenewalneeded

}

//fillinanymissingfieldsindhcpresultsfromthepreviousresults.

//ifmdhcpresultsisnull(i.e.thisisthefirstserverresponse),

//thisisanoop.

dhcpresults.updatefromdhcprequest(mdhcpresults);

mdhcpresults=dhcpresults;

mcontroller.obtainmessage(cmd_post_dhcp_action,dhcp_success,0,dhcpresults)

.sendtotarget();

returntrue;

} 如果getdhcpresults()函数执行成功,dhcpstatemachine就会发送cmd_post_dhcp_action消息给wifistatemachine,状态位是dhcp_success,并附加rundhcp()获取到的dhcpresult对象;失败时则附加dhcp_failure。l2connectedstate处理cmd_post_dhcp_action消息: [java]view plaincopy

print?

casedhcpstatemachine.cmd_post_dhcp_action:

handlepostdhcpsetup();

if(message.arg1==dhcpstatemachine.dhcp_success){

if(dbg)log("dhcpsuccessful");

handleipv4success((dhcpresults)message.obj,dhcpstatemachine.dhcp_success);

//weadvancetomconnectedstatebecausehandleipv4successwillcall

//updatelinkproperties,whichthensendscmd_ip_configuration_successful.

}elseif(message.arg1==dhcpstatemachine.dhcp_failure){

mwifilogger.capturebugreportdata(wifilogger.report_reason_dhcp_failure);

if(dbg){

intcount=-1;

wificonfigurationconfig=getcurrentwificonfiguration();

if(config!=null){

count=config.numconnectionfailures;

}

log("dhcpfailurecount="+count);

}

handleipv4failure(dhcpstatemachine.dhcp_failure);

//asabove,wetransitiontomdisconnectingstateviaupdatelinkproperties.

}

break; 首先调用handlepostdhcpsetup()重置之前所做的预处理动作;再处理附加的状态位,成功则调用handleipv4success()更新网络的配置信息:

privatevoidhandleipv4success(dhcpresultsdhcpresults,intreason){

if(pdbg){

logd("handleipv4success<"+dhcpresults.tostring()+">");

logd("linkaddress"+dhcpresults.ipaddress);

}

inet4addressaddr;

synchronized(mdhcpresultslock){

mdhcpresults=dhcpresults;//保存当前的dhcp结果

addr=(inet4address)dhcpresults.ipaddress.getaddress();

}

if(isroaming()){

intpreviousaddress=mwifiinfo.getipaddress();

intnewaddress=networkutils.inetaddresstoint(addr);

if(previousaddress!=newaddress){

logd("handleipv4success,roamingandaddresschanged"+

mwifiinfo+"got:"+addr);

}

}

mwifiinfo.setinetaddress(addr);

mwifiinfo.setmeteredhint(dhcpresults.hasmeteredhint());

updatelinkproperties(reason);//更新网络配置信息

} updatelinkproperties()更新当前的网络配置信息:

privatevoidupdatelinkproperties(intreason){

linkpropertiesnewlp=makelinkproperties();//根据dhcp的结果创建新的linkproperties对象,用于对比dhcp前后的网络配置是否已经改变

finalbooleanlinkchanged=!newlp.equals(mlinkproperties);

finalbooleanwasprovisioned=isprovisioned(mlinkproperties);

finalbooleanisprovisioned=isprovisioned(newlp);

//todo:teachlinkpropertieshowtounderstandstaticassignment

//andsimplifyallthisprovisioningchangedetectionlogicby

//unifyingitunderlinkproperties.compareprovisioning().

finalbooleanlostprovisioning=

(wasprovisioned&&!isprovisioned)||

(mlinkproperties.hasipv4address()&&!newlp.hasipv4address())||

(mlinkproperties.isipv6provisioned()&&!newlp.isipv6provisioned());

finaldetailedstatedetailedstate=getnetworkdetailedstate();

if(linkchanged){//网络配置信息改变

if(dbg){

log("linkconfigurationchangedfornetid:"+mlastnetworkid

+"old:"+mlinkproperties+"new:"+newlp);

}

mlinkproperties=newlp;//将新的配置信息保存到该字段中

if(mipreachabilitymonitor!=null){

mipreachabilitymonitor.updatelinkproperties(mlinkproperties);

}

if(mnetworkagent!=null)mnetworkagent.sendlinkproperties(mlinkproperties);//通过networkagent对象通知connectifyservice更新网络配置信息

}

if(lostprovisioning){

log("lostiplayerprovisioning!"+

"was:"+mlinkproperties+

"now:"+newlp);

}

//ifwejustconfiguredorlostipconfiguration,dotheneedful.

//wedon'tjustcallhandlesuccessfulipconfiguration()orhandleipconfigurationlost()

//herebecausethoseshouldonlybecalledifwe'reattemptingtoconnectoralready

//connected,whereasupdatelinkpropertiescanbecalledatanytime.

switch(reason){

casedhcpstatemachine.dhcp_success:

casecmd_static_ip_success:

//ipv4provisioningsucceded.advancetoconnectedstate.

sendmessage(cmd_ip_configuration_successful);

if(!isprovisioned){

//canneverhappenunlessdhcpreportssuccessbutisprovisionedthinksthe

//resultingconfigurationisinvalid(e.g.,noipv4address,orthestatein

//mlinkpropertiesisoutofsyncwithreality,orthere'sabuginthiscode).

//todo:disconnecthereinstead.ifourconfigurationisnotusable,there'sno

//pointinstayingconnected,andifmlinkpropertiesisoutofsyncwith

//reality,thatwillcauseproblemsinthefuture.

logd("ipv4configsucceeded,butnotprovisioned");

}

break;

casedhcpstatemachine.dhcp_failure:

//dhcpfailed.ifwe'renotalreadyprovisioned,orwehadipv4andnowlostit,

//giveupanddisconnect.

//ifwe'realreadyprovisioned(e.g.,ipv6-onlynetwork),stayconnected.

if(!isprovisioned||lostprovisioning){

sendmessage(cmd_ip_configuration_lost);

}else{

//dhcpfailed,butwe'reprovisioned(e.g.,ifwe'reonanipv6-onlynetwork).

sendmessage(cmd_ip_configuration_successful);

//tobesurewedon'tgetstuckwithanon-workingnetworkifallwehadis

//ipv4,removetheipv4addressfromtheinterface(sincewe'reusingdhcp,

//anddhcpfailed).ifwehadanipv4addressbefore,thedeletionofthe

//addresswillcauseacmd_update_linkproperties.iftheipv4addresswas

//necessaryforprovisioning,itsdeletionwillcauseustodisconnect.

//

//thisshouldn'tbeneeded,becaunanipv4-onlynetworkadhcpfailurewill

//haveemptydhcpresultsandthusemptylinkproperties,andisprovisionedwill

//notreturntrueifwe'reusingdhcpanddon'thaveanipv4defaultroute.so

//fornowit'sonlyhereforextraredundancy.however,itwillincrease

//robustnessifwemovetogettingipv4routesfromnetlinkaswell.

loge("dhcpfailure:provisioned,clearingipv4address.");

if(!clearipv4address(minterfacename)){

sendmessage(cmd_ip_configuration_lost);

}

}

break;

casecmd_static_ip_failure:

//staticconfigurationwasinvalid,oranerroroccurredinapplyingit.giveup.

sendmessage(cmd_ip_configuration_lost);

break;

casecmd_update_linkproperties:

//ipaddresses,dnsservers,etc.changed.actaccordingly.

if(lostprovisioning){

//wenolongerhaveausablenetworkconfiguration.disconnect.

sendmessage(cmd_ip_configuration_lost);

}elseif(!wasprovisioned&&isprovisioned){

//wehaveausableipv6-onlyconfig.advancetoconnectedstate.

sendmessage(cmd_ip_configuration_successful);

}

if(linkchanged&&getnetworkdetailedstate()==detailedstate.connected){

//ifanythinghaschangedandwe'realreadyconnected,sendoutanotification.

sendlinkconfigurationchangedbroadcast();

}

break;

}

} 最后会根据dhcp是否成功发送cmd_ip_configuration_successful消息表明ip的配置已经完成(因为我们已经告知了connectifyservice去更新网络配置,并附加了新的mlinkproperties对象),l2connectedstate处理cmd_ip_configuration_successful消息:

casecmd_ip_configuration_successful:

handlesuccessfulipconfiguration();

sendconnectedstate();

transitionto(mconnectedstate); handlesuccessfulipconfiguration()函数处理:

privatevoidhandlesuccessfulipconfiguration(){

mlastsignallevel=-1;//forceupdateofsignalstrength

wificonfigurationc=getcurrentwificonfiguration();//获取代表当前连接的网络的wificonfiguration对象

if(c!=null){

//resetipfailuretracking

c.numconnectionfailures=0;

//重置numconnectionfailures字段,因为在wificonfigstore中,会根据numconnectionfailures字段判断当前网络的连接失败次数,默认失败10次时,会终止重连操作

//telltheframeworkwhetherthenewlyconnectednetworkistrustedoruntrusted.

updatecapabilities(c);

}

if(c!=null){

scanresultresult=getcurrentscanresult();

if(result==null){

logd("wifistatemachine:handlesuccessfulipconfigurationandnoscanresults"+

c.configkey());

}else{

//cleartheperbssidfailurecount

result.numipconfigfailures=0;

//clearthewholebssidblacklist,whichmeanssupplicantisfreetoretry

//anybssid,eventhoughitmayalreadyhaveanonzeroipfailurecount,

//thiswilltypicallyhappeniftheuserwalksawayandcomebacktohisarrea

//todo:implementblacklistingbasedonatimer,i.e.keepbssidblacklisted

//insupplicantforacoupleofhoursoraday

mwificonfigstore.clearbssidblacklist();

}

}

} sendconnectedstate()主要做一些网络状态的更新操作,发送network_state_changed_action通知当前的网络状态已经变化。此广播会附加wifistatemachine中三个常用的字段值:

/**

*thelinkpropertiesofthewifiinterface.

*donotmodifythisdirectly;useupdatelinkpropertiesinstead.

*/

privatelinkpropertiesmlinkproperties;//保存当前网络连接的配置信息,包括ip地址集、dns地址集、路由地址集等。

//note:donotreturntoclients-use#getwifiinfoforuid(int)

privatewifiinfomwifiinfo;//描述了一个wifi连接的状态,通过该对象我们可以得知当前wifi连接的ssid、netid、ip地址、mac地址等信息

privatenetworkinfomnetworkinfo;//表示一个网络接口(wlan0/eth0)的连接状态,通过该对象可以得知当前wifi连接处于哪一步、是否连接等状态 最后切换到connectedstate,至此ap已经连接、ip也已获取到,并且网络状态也已更新。后续的过程貌似没什么大用了。一个wifi的连接流程到这里就分析完了。

ps:

4.4之后android加入了ap评分机制。这个机制根据某个ap的很多配置信息一通处理,最后得出一个score,来表明某个ap的可连接性。它评判的属性有点多,后面在研究,现在本渣还是没有搞明白,囧....

在framework里面,其实屏蔽了很多复杂的操作,比如wifinative里面的大多数方法都是要通过jni调用wifi.c,再调到wpa_s。这些中间过程其实比framework的处理要复杂的多,代码也更晦涩。例如rundhcp()动作,有个专门的dhcpcd守护进程进行处理;它的实现跟wpa_s一样,都是很复杂的。即使了解dhcp协议的工作流程,要看懂它的代码实现也很痛苦。android里还有的pppoe拨号方式,它的守护进程pppd的实现也很复杂......;要做这方面的定制,对于偏向framework的人来说,是比较痛苦的。