当前位置: 移动技术网 > IT编程>移动开发>Android > Android开发中Wifi连接流程分析

Android开发中Wifi连接流程分析

2019年04月18日  | 移动技术网IT编程  | 我要评论

蓝八色鸫,天气预报石家庄,贴身医王 夜独醉 小说

当我们在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的人来说,是比较痛苦的。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网