展会信息港展会大全

Android Wifi work station Framework and Architecture
来源:互联网   发布日期:2015-09-28 16:07:08   浏览:1485次  

导读:Android Wifi work station Framework and Architecturewith wpa_supplicant 0.8.X, BCM4329.转载请注明出处...

Android Wifi work station Framework and Architecture

with wpa_supplicant 0.8.X, BCM4329.

转载请注明出处。

Settings/Wifi UI part structure

WifiSettings是主对话框

167

168@Override

169public void onActivityCreated(Bundle savedInstanceState) {

170// We don't call super.onActivityCreated() here, since it assumes we already set up

171// Preference (probably in onCreate()), while WifiSettings exceptionally set it up in

172// this method.

173

174mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);

175mWifiManager.asyncConnect(getActivity(), new WifiServiceHandler());

176if (savedInstanceState != null

177&& savedInstanceState.containsKey(SAVE_DIALOG_ACCESS_POINT_STATE)) {

178mDlgEdit = savedInstanceState.getBoolean(SAVE_DIALOG_EDIT_MODE);

179mAccessPointSavedState = savedInstanceState.getBundle(SAVE_DIALOG_ACCESS_POINT_STATE);

180}

1101public void asyncConnect(Context srcContext, Handler srcHandler) {

1102mAsyncChannel.connect(srcContext, srcHandler, getMessenger());

1103}

establish a half connect between WifiManager and WifiService.

1117public void connectNetwork(WifiConfiguration config) {

1118if (config == null) {

1119return;

1120}

1121mAsyncChannel.sendMessage(CMD_CONNECT_NETWORK, config);

1122}

Activity创建的时候会建立和WifiService的AsyncChannel的连接,WifiService同样会建立一个AsyncChannelHandler来处理来自这个Channel的命令消息。AsyncChannel的所谓异步主要用来传递比较耗时的操作并把结果返回给原请求者。AsyncChannel两端分别有一个MessageHandler,srcHandler请求destHandler,destHandler把结果发回给srcHandler,主要是用于处理比较耗时的操作且在WifiManager中处理返回结果。

严格来说,在WifiService的Interface方法之外再做出一个通道提供额外的方法并不是一个什么好的设计。命令是可以通过同步接口发送给WifiService的,但是WifiService的处理结果如果通过broadcast或intent给WifiManager,则又解耦的过度;如果WifiManager实现一个binder做event sink,又有点小题大做,所以这儿引入这么个AsyncChannel实在是不得以而为之。

WifiSettings界面使能Wifi时会使用定时器请求扫描,获取扫描结果,列出AP列表。Scanner使用定时器,周期性向WifiService请求主动扫描,定时原理是发出本次扫描请求后延迟1s发送下次请求。相关代码如下:

private class Scanner extends Handler {

private int mRetry = 0;

void resume() {

if (!hasMessages(0)) {

sendEmptyMessage(0);

}

}

void forceScan() {

removeMessages(0);

sendEmptyMessage(0);

}

void pause() {

mRetry = 0;

removeMessages(0);

}

@Override

public void handleMessage(Message message) {

if (mWifiManager.startScanActive()) {

mRetry = 0;

} else if (++mRetry >= 3) {

mRetry = 0;

Toast.makeText(getActivity(), R.string.wifi_fail_to_scan,

Toast.LENGTH_LONG).show();

return;

}

sendEmptyMessageDelayed(0, WIFI_RESCAN_INTERVAL_MS);

}

}

列出AP列表的代码如下:

In WifiSettings.java

final List<ScanResult> results = mWifiManager.getScanResults(); //同步操作

if (results != null) {

for (ScanResult result : results) {

// Ignore hidden and ad-hoc networks.

if (result.SSID == null || result.SSID.length() == 0 || result.capabilities.contains("[IBSS]")) {

continue;

}

boolean found = false;

for (AccessPoint accessPoint : apMap.getAll(result.SSID)) {

if (accessPoint.update(result))

found = true;

}

if (!found) {

AccessPoint accessPoint = new AccessPoint(getActivity(), result);

accessPoints.add(accessPoint);

apMap.put(accessPoint.ssid, accessPoint);

}

}

}

private void updateAccessPoints() {

final int wifiState = mWifiManager.getWifiState();

switch (wifiState) {

case WifiManager.WIFI_STATE_ENABLED:

// AccessPoints are automatically sorted with TreeSet.

final Collection<AccessPoint> accessPoints = constructAccessPoints();

getPreferenceScreen().removeAll();

if (mInXlSetupWizard) {

((WifiSettingsForSetupWizardXL)getActivity()).onAccessPointsUpdated(

getPreferenceScreen(), accessPoints);

} else {

for (AccessPoint accessPoint : accessPoints) {

// When WAPI is not customized to be on all

// WAPI APs will be invisible

if (accessPoint.isVisible()) {

getPreferenceScreen().addPreference(accessPoint);

}

}

}

break;

case WifiManager.WIFI_STATE_ENABLING:

getPreferenceScreen().removeAll();

break;

case WifiManager.WIFI_STATE_DISABLING:

addMessagePreference(R.string.wifi_stopping);

break;

case WifiManager.WIFI_STATE_DISABLED:

addMessagePreference(R.string.wifi_empty_list_wifi_off);

break;

}

}

可以看出对ADHOC的AP,隐藏AP(无SSID的)做了过滤处理。

当在AP列表上,长按某个AP时弹出三菜单Menu - ContextMenu。

这个Menu主要是连接该AP,修改该AP,忘记该AP,其处理代码如下:

@Override

public boolean onContextItemSelected(MenuItem item) {

if (mSelectedAccessPoint == null) {

return super.onContextItemSelected(item);

}

switch (item.getItemId()) {

case MENU_ID_CONNECT: {

if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {

if (!requireKeyStore(mSelectedAccessPoint.getConfig())) {

mWifiManager.connectNetwork(mSelectedAccessPoint.networkId);

}

} else if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE) {

/** Bypass dialog for unsecured networks */

mSelectedAccessPoint.generateOpenNetworkConfig();

mWifiManager.connectNetwork(mSelectedAccessPoint.getConfig());

} else {

showConfigUi(mSelectedAccessPoint, true);

}

return true;

}

case MENU_ID_FORGET: {

mWifiManager.forgetNetwork(mSelectedAccessPoint.networkId);

return true;

}

case MENU_ID_MODIFY: {

showConfigUi(mSelectedAccessPoint, true);

return true;

}

}

return super.onContextItemSelected(item);

}

可以看出如果该AP已经经过配置,那么直接连接,如果没有经过配置且该AP没有密码,那么直接连接,否则则弹出配置对话框先进行配置(选择加密类型和输入密码)。

当点击AP列表中的某个AP时,直接根据该AP的情况进行处理,代码如下:

387@Override

388public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {

389if (preference instanceof AccessPoint) {

390mSelectedAccessPoint = (AccessPoint) preference;

391/** Bypass dialog for unsecured, unsaved networks */

392if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE &&

393mSelectedAccessPoint.networkId == INVALID_NETWORK_ID) {

394mSelectedAccessPoint.generateOpenNetworkConfig();

395mWifiManager.connectNetwork(mSelectedAccessPoint.getConfig());

396} else {

397showConfigUi(mSelectedAccessPoint, false);

398}

399} else {

400return super.onPreferenceTreeClick(screen, preference);

401}

402return true;

403}

可以看出和长按菜单的处理逻辑相似。

当使用Setttings主界面或Settings/Wifi界面的Switcher开关Wifi时,处理代码会调用到mWifiEnabler的setSwitch方法,然后会通知其listener,涉及方法如下:

88public void setSwitch(Switch switch_) {

89if (mSwitch == switch_) return;

90mSwitch.setOnCheckedChangeListener(null);

91mSwitch = switch_;

92mSwitch.setOnCheckedChangeListener(this);

93

94final int wifiState = mWifiManager.getWifiState();

95boolean isEnabled = wifiState == WifiManager.WIFI_STATE_ENABLED;

96boolean isDisabled = wifiState == WifiManager.WIFI_STATE_DISABLED;

97mSwitch.setChecked(isEnabled);

98mSwitch.setEnabled(isEnabled || isDisabled);

99}

100

101public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

102//Do nothing if called as a result of a state machine event

103if (mStateMachineEvent) {

104return;

105}

106// Show toast message if Wi-Fi is not allowed in airplane mode

107if (isChecked && !WirelessSettings.isRadioAllowed(mContext, Settings.System.RADIO_WIFI)) {

108Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();

109// Reset switch to off. No infinite check/listenenr loop.

110buttonView.setChecked(false);

111}

112

113// Disable tethering if enabling Wifi

114int wifiApState = mWifiManager.getWifiApState();

115if (isChecked && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||

116(wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {

117mWifiManager.setWifiApEnabled(null, false);

118}

119

120if (mWifiManager.setWifiEnabled(isChecked)) {

121// Intent has been taken into account, disable until new state is active

122mSwitch.setEnabled(false);

123} else {

124// Error

125Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();

126}

127}

可以看出当不是AP时,是使能Wifi,默认行为是根据配置挑选出AP进行连接。

另外的两个类的解释:

WifiConfigController是MVC中的Controller

WifiDialog是单击的config对话框

连接和DHCP过程中显示的字符串xml文件如下:

In /packages/apps/Settings/res/values/arrays.xml

223<!-- Wi-Fi settings -->

224

225<!-- Match this with the order of NetworkInfo.DetailedState. --> <skip />

226<!-- Wi-Fi settings. The status messages when the network is unknown. -->

227<string-array name="wifi_status">

228<!-- Status message of Wi-Fi when it is idle. -->

229<item></item>

230<!-- Status message of Wi-Fi when it is scanning. -->

231<item>Scanning\u2026</item>

232<!-- Status message of Wi-Fi when it is connecting. -->

233<item>Connecting\u2026</item>

234<!-- Status message of Wi-Fi when it is authenticating. -->

235<item>Authenticating\u2026</item>

236<!-- Status message of Wi-Fi when it is obtaining IP address. -->

237<item>Obtaining IP address\u2026</item>

238<!-- Status message of Wi-Fi when it is connected. -->

239<item>Connected</item>

240<!-- Status message of Wi-Fi when it is suspended. -->

241<item>Suspended</item>

242<!-- Status message of Wi-Fi when it is disconnecting. -->

243<item>Disconnecting\u2026</item>

244<!-- Status message of Wi-Fi when it is disconnected. -->

245<item>Disconnected</item>

246<!-- Status message of Wi-Fi when it is a failure. -->

247<item>Unsuccessful</item>

248</string-array>

至此UI界面响应部分介绍完毕,下面看WifiManager.

WifiManager是WifiService的客户端接口的封装类,WifiService是服务实现,接口是IWifiManager。

In IWifiManager.aidl

32interface IWifiManager {};

In WifiService.java

public class WifiService extends IWifiManager.Stub {};

In WifiManager.java, NOT the intermmediate file of IWifiManager.aidl

485public WifiManager(IWifiManager service, Handler handler) {

486mService = service;

487mHandler = handler;

488}

In ContextImpl.java每个Activity关联的Contect会得到WIFI_SERVICE,然后构造WifiManager封装类。代码如下:

449registerService(WIFI_SERVICE, new ServiceFetcher() {

450public Object createService(ContextImpl ctx) {

451IBinder b = ServiceManager.getService(WIFI_SERVICE);

452IWifiManager service = IWifiManager.Stub.asInterface(b);

453returnnew WifiManager(service, ctx.mMainThread.getHandler());

454}});

几个同步操作的控制流示例:

WifiSettings=>WifiManager::reconnect(…)()||||

=>WifiService:: reconnect ()=>WifiStateMachine :: reconnectCommand()

Scanner=>WifiManager::startScanActive()||||=>WifiService::startScan(active)=>WifiStateMachine ::startScan(active)

WifiEnabler=> WifiManager::setWifiEnabled() ||||=>WifiService::setWifiEnabled()=>WifiStateMachine ::setWifiEnabled()

WifiManager中大部分同步命令都是这么个流程;耗时的异步命令则是通过AsyncChannel发送给WifiService.

WifiService Part structure

In WifiService.java

public class WifiService extends IWifiManager.Stub {};

WifiService线程的启动如下

In SystemServer.java

384try {

385Slog.i(TAG, "Wi-Fi P2pService");

386wifiP2p = new WifiP2pService(context);

387ServiceManager.addService(Context.WIFI_P2P_SERVICE, wifiP2p);

388} catch (Throwable e) {

389reportWtf("starting Wi-Fi P2pService", e);

390}

391

392try {

393Slog.i(TAG, "Wi-Fi Service");

394wifi = new WifiService(context);

395ServiceManager.addService(Context.WIFI_SERVICE, wifi);

396} catch (Throwable e) {

397reportWtf("starting Wi-Fi Service", e);

398}

WifiService的构造函数本质是启动了一个带有消息队列的线程做WifiService,两个Handler attach到该消息队列上。

428HandlerThread wifiThread = new HandlerThread("WifiService");

429wifiThread.start();

430mAsyncServiceHandler = new AsyncServiceHandler(wifiThread.getLooper());

431mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());

AsyncServiceHandler做为destHandler用于处理下行的来自WifiManager客户端的命令消息,而WifiStateMachineHandler做为srcHandler用于向WifiStateMachine.mSmhandler发送异步命令。现在的WifiStatemachine实现是和WifiService使用同一个looper,在同一个线程中,所以mAsyncServiceHandler、mWifiStateMachineHandler、WifiStateMachine.mSmhandler是使用同一个looper,运行在wifiThread中。WifiStateMachine籍由StateMachine具备有单独looper在单独线程运行的能力。

WifiSerivce作为一个service,WifiService.java在frameworks/base/services/java/com/android/server/目录下。但其实现使用的WifiStateMachine在frameworks/base/wifi/java/android/net/wifi/目录下。

WifiStateMachine状态机使用WifiNative wpa_ctrl和wpa_supplicant通讯, WifiMonitor监听wpa_supplicant的异步消息。因为WifiStateMachine的核心是状态机,所以其接口都是转换成命令投入状态机消息队列。WifiService传来的命令和WifiMonitor监听到的响应汇入WifiStateMachine的消息队列,驱动WifiStateMachine转动起来。

WifiStateMachine继承自StateMachine,是一个hierarchical state machine which processes messages and can have states arranged hierarchically,其细节参见StateMachine.java. WifiStateMachine的hierarchy如下图所示:

下面考察初始状态到Wifi使能扫描AP连接AP查询AP过程的状态机运转。

In WifiStateMachine.java

状态机会启动,进入InitialState状态。然后UI打开WifiEnabler最终WifiService:: setWifiEnabled会被执行到。相关代码如下:

553public WifiStateMachine(Context context, String wlanInterface) {

649if (DBG) setDbg(true);

650

651//start the state machine

652start();

653}

680public void setWifiEnabled(boolean enable) {

681mLastEnableUid.set(Binder.getCallingUid());

682if (enable) {

683/* Argument is the state that is entered prior to load */

684sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0));

685sendMessage(CMD_START_SUPPLICANT);

686} else {

687sendMessage(CMD_STOP_SUPPLICANT);

688/* Argument is the state that is entered upon success */

689sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED, 0));

690}

691}

在InitialState.enter()中,初始情况下WifiDriver是没有加载的,所以进入DriverUnloadedState状态;

然后setWifiEnabled向状态机发出CMD_LOAD_DRIVER with WIFI_STATE_ENABLING和CMD_START_SUPPLICANT两个命令。

在DriverUnloadedState状态下,处理CMD_LOAD_DRIVER命令,向WifiP2pService发送WIFI_ENABLE_PENDING命令,也就是说通知WifiP2pService需要退出要启用Wifi了,因为WifiService和WifiP2pService同一时刻只能使用一个,然后转到WaitForP2pDisableState状态等待WifiP2pService的响应。

在WaitForP2pDisableState状态下收到WifiP2pService的响应WIFI_ENABLE_PROCEED,转到DriverLoadingState状态加载Wifi driver;对于其它请求会deferMessage到以后状态处理。

在DriverLoadingState状态启用线程异步加载Wifi driver,当加载成功时,向状态机自身发送消息CMD_LOAD_DRIVER_SUCCESS驱动状态机转换到DriverLoadedState,加载失败则发送消息CMD_LOAD_DRIVER_FAILED驱动状态机转换到DriverFailedState状态(会经由DriverUnloadedState)。

在DriverLoadedState状态下处理setWifiEnabled发出的defer到此的第二个命令CMD_START_SUPPLICANT,加载网卡芯片固件,启动wpa_supplicant,启动WifiMonitor接收wpa_supplicant的消息,转换状态到SupplicantStartingState等待WifiMonitor的事件(wpa_supplicant接入成功事件)。

在SupplicantStartingState状态下收到WifiMonitor. SUP_CONNECTION_EVENT表接入wpa_supplicant成功,regulate国家代号,初始化一些表征wpa_s的字段,转换状态至DriverStartedState;对于其它命令,defer处理。

经SupplicantStartedState.enter()和DriverStartedState.enter()中使用CMD_SET_COUNTRY_CODE和CMD_SET_FREQUENCY_BAND设置国家代号和频段,在本状态处理这两个命令;这两个命令是要发送给芯片的,所以在固件和驱动加载好后发送。设置好频段后,就向自身发送消息CMD_START_SCAN启动一次active scan。然后经由状态ConnectModeState转换状态至DisconnectedState。

在DisconnectedState下收到扫描结果WifiMonitor.SCAN_RESULTS_EVENT,消息路由给父状态SupplicantStartedState的processMessage进行处理,获取扫描结果并保存。在此状态下SupplicantStartedState处理与AP配置相关的命令,ConnectModeState处理与AP连接相关的命令。例如可以配置某个AP,然后请求connectNetwork,对于CMD_CONNECT_NETWORK,会使用Connect相关状态ConnectModeState.processMessage()处理,启动AP关联,然后转换状态到DisconnectingState与旧AP断开连接与新AP建立连接。

在DisconnectingState状态收到关联到新AP成功消息WifiMonitor.NETWORK_CONNECTION_EVENT后,使用ConnectModeState.processMessage处理,记录关联上的SSID,BSSID,获取AP信号强度和速度,广播消息,转换状态至ConnectingState进行IP获龋

在ConnectingState.enter()中使用静态IP或DHCP获取IP,配置IP,成功则转入ConnectedState状态。

在ConnectedState状态下,可以处理配置AP、连接新的AP、断开连接等,还有扫描请求,另外还要查询当前连接AP的信号强度和网络流量信息,在状态栏显示Wifi状态图标。这时通过CMD_RSSI_POLL命令实现的,当WifiService构造时,允许enableRssiPolling,一次CMD_ENABLE_RSSI_POLL会引发定时的CMD_RSSI_POLL,当屏幕未关闭时,CMD_RSSI_POLL就会定时向自身状态机发送;然后ConnectedState.processMessage调用fetchRssiAndLinkSpeedNative()处理CMD_RSSI_POLL。

赞助本站

人工智能实验室

相关热词: android开发 教程

AiLab云推荐
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港