Android WIFI 详解
public class WifiEnabler implementsPreference.OnPreferenceChangeListener {
……
public boolean onPreferenceChange(Preference preference,Object value) {
booleanenable = (Boolean) value;
……
if (mWifiManager.setWifiEnabled(enable)) {
mCheckBox.setEnabled(false);
……
}
……
}
我们都知道Wifimanager只是个服务代理,所以它会调用WifiService的setWifiEnabled()函数,而这个函数会调用 sendEnableMessage()函数,了解android消息处理机制的都知道,这个函数最终会给自己发送一个 MESSAGE_ENABLE_WIFI的消息,被WifiService里面定义的handlermessage()函数处理,会调用 setWifiEnabledBlocking()函数。下面是调用流程:
mWifiEnabler.onpreferencechange()=>mWifiManage.setWifienabled()=>mWifiService.setWifiEnabled()=>mWifiService.sendEnableMessage()=>mWifiService.handleMessage()=>mWifiService.setWifiEnabledBlocking().
在setWifiEnabledBlocking()函数中主要做如下工作:加载Wifi驱动,启动wpa_supplicant,注册广播接收器,启动WifiThread监听线程。代码如下:
……
if (enable) {
if (!mWifiStateTracker.loadDriver()) {
Slog.e(TAG, Failed toload Wi-Fi driver.);
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
return false;
}
if (!mWifiStateTracker.startSupplicant()) {
mWifiStateTracker.unloadDriver();
Slog.e(TAG, Failed tostart supplicant daemon.);
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
return false;
}
registerForBroadcasts();
mWifiStateTracker.startEventLoop();
……
至此,Wifi使能结束,自动进入扫描阶段。
(2) 扫描AP
当驱动加载成功后,如果配置文件的AP_SCAN = 1,扫描会自动开始,WifiMonitor将会从supplicant收到一个消息EVENT_DRIVER_STATE_CHANGED,调用 handleDriverEvent(),然后调用mWifiStateTracker.notifyDriverStarted(),该函数向消息队列 添加EVENT_DRIVER_STATE_CHANGED,handlermessage()函数处理消息时调用scan()函数,并通过 WifiNative将扫描命令发送到wpa_supplicant。
Frameworks/base/wifi/java/android/net/wifi/WifiMonitor.java
private void handleDriverEvent(Stringstate) {
if (state == null) {
return;
}
if (state.equals(STOPPED)) {
mWifiStateTracker.notifyDriverStopped();
} else if (state.equals(STARTED)) {
mWifiStateTracker.notifyDriverStarted();
} else if (state.equals(HANGED)) {
mWifiStateTracker.notifyDriverHung();
}
}
Frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java
case EVENT_DRIVER_STATE_CHANGED:
switch(msg.arg1) {
case DRIVER_STARTED:
/**
*Set the number of allowed radio channels according
*to the system setting, since it gets reset by the
*driver upon changing to the STARTED state.
*/
setNumAllowedChannels();
synchronized (this) {
if (mRunState == RUN_STATE_STARTING) {
mRunState = RUN_STATE_RUNNING;
if (!mIsScanOnly) {
reconnectCommand();
} else {
// In somesituations, supplicant needs to be kickstarted to
// start thebackground scanning
scan(true);
}
}
}
break;
上面是启动Wifi时,自动进行的AP的扫描,用户当然也可以手动扫描AP,这部分实现在WifiService里面,WifiService通过startScan()接口函数发送扫描命令到supplicant。
Frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java
public boolean startScan(booleanforceActive) {
enforceChangePermission();
switch (mWifiStateTracker.getSupplicantState()) {
case DISCONNECTED:
case INACTIVE:
case SCANNING:
case DORMANT:
break;
default:
mWifiStateTracker.setScanResultHandling(
WifiStateTracker.SUPPL_SCAN_HANDLING_LIST_ONLY);
break;
}
return mWifiStateTracker.scan(forceActive);
}
然后下面的流程同上面的自动扫描,我们来分析一下手动扫描从哪里开始的。我们应该知道手动扫描是通过菜单键的扫描键来响应的,而响应该动作的应该是 WifiSettings类中Scanner类的handlerMessage()函数,它调用WifiManager的 startScanActive(),这才调用WifiService的startScan()。
packages/apps/Settings/src/com/android/settings/wifiwifisettings.java
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(Menu.NONE, MENU_ID_SCAN, 0, R.string.wifi_menu_scan)
.setIcon(R.drawable.ic_menu_scan_network);
menu.add(Menu.NONE, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced)
.setIcon(android.R.drawable.ic_menu_manage);
return super.onCreateOptionsMenu(menu);
}
当按下菜单键时,WifiSettings就会调用这个函数绘制菜单。如果选择扫描按钮,WifiSettings会调用onOptionsItemSelected()。
packages/apps/Settings/src/com/android/settings/wifiwifisettings.java
评论