Wi-Fi源码分析之WifiService操作Wi-Fi(二)
一. SupplicantStartingState中的的processMessage方法分析
public boolean processMessage(Message message) {
switch(message.what) {
case WifiMonitor.SUP_CONNECTION_EVENT:
if (DBG) log("Supplicant connection established");
setWifiState(WIFI_STATE_ENABLED);/*发送WIFI_STATE_CHANGED_ACTION广播*/
mSupplicantRestartCount = 0;
/* Reset the supplicant state to indicate the supplicant * state is not known at this time */
mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);/*发送消息给SupplicantStateTracker状态机*/
/* Initialize data structures */
mLastBssid = null;
mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
mLastSignalLevel = -1;
/*设置本机IP地址*/
mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
mWifiConfigStore.loadAndEnableAllNetworks();
initializeWpsDetails();
/*初始化WPS相关*/
/*发送SUPPLICANT_CONNECTION_CHANGE_ACTION广播*/
sendSupplicantConnectionChangedBroadcast(true);
transitionTo(mDriverStartedState);/*转到DriverStartedState*/
break;
case WifiMonitor.SUP_DISCONNECTION_EVENT:
if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
loge("Failed to setup control channel, restart supplicant");
mWifiMonitor.killSupplicant(mP2pSupported);
transitionTo(mInitialState);
sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
} else {
loge("Failed " + mSupplicantRestartCount +
" times to start supplicant, unload driver");
mSupplicantRestartCount = 0;
setWifiState(WIFI_STATE_UNKNOWN);
transitionTo(mInitialState);
}
break;
case CMD_START_SUPPLICANT:
case CMD_STOP_SUPPLICANT:
case CMD_START_AP:
case CMD_STOP_AP:
case CMD_START_DRIVER:
case CMD_STOP_DRIVER:
case CMD_SET_OPERATIONAL_MODE:
case CMD_SET_COUNTRY_CODE:
case CMD_SET_FREQUENCY_BAND:
case CMD_START_PACKET_FILTERING:
case CMD_STOP_PACKET_FILTERING:
deferMessage(message);
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
DriverStarted的父状态是SupplicantStarted(涉及到的HSM和各个状态层的关系以后再说), 所以transitionTo(mDriverStartedState)会导致DriverStarted和SupplicantStarted里的enter被调用.下面逐个分析.
二. SupplicantStartedState里的enter方法分析
class SupplicantStartedState extends State {
@Override
public void enter() {
/* Wifi is available as long as we have a connection to supplicant */
mNetworkInfo.setIsAvailable(true);
/*config_wifi_supplicant_scan_interval:控制扫描间隔,默认15000毫秒*/
int defaultInterval = mContext.getResources().getInteger(
R.integer.config_wifi_supplicant_scan_interval);
mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
defaultInterval);
/*向WPAS发送"SCAN_INTERVAL 扫描间隔时间"命令*/
mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000);
}
...
}
三. DriverStartedState里的enter方法分析
class DriverStartedState extends State {
@Override
public void enter() {
mIsRunning = true;
mInDelayedStop = false;
mDelayedStopCounter++;
updateBatteryWorkSource(null);
/** * Enable bluetooth coexistence scan mode when bluetooth connection is active. * When this mode is on, some of the low-level scan parameters used by the * driver are changed to reduce interference with bluetooth * 蓝牙是运行在2.4GHz频段上,所以为了避免wlan和蓝牙互相干扰,下面这个函数将告知 * wlan driver蓝牙是否启用. 如果是 wlan芯片会做适当调整*/
mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
/* 设置国家代码和频段 * 其内部是通过发送消息的方式来出发WifiNative * setCountryCode和setBand函数被调用.在WifiNative中,这个两个函数都会发送形如 * "DRIVER XXX"命令给WPAS. DRIVER命令是Android平台特有的, 用于给wlan driver发送一些定制的命令. * hardware\broadcom\wlan\bcmdhd\wpa_supplicant_8_lib\driver_cmd_nl80211.c中有wlan driver的"DRIVER XXX"命令 */
setCountryCode();
setFrequencyBand();
/* initialize network state */
setNetworkDetailedState(DetailedState.DISCONNECTED);
/*下面的三个函数都和WPAS中的"DRIVER XXX"命令有关*/
/* Remove any filtering on Multicast v6 at start */
mWifiNative.stopFilteringMulticastV6Packets();
/* Reset Multicast v4 filtering state */
if (mFilteringMulticastV4Packets.get()) {
mWifiNative.startFilteringMulticastV4Packets();
} else {
mWifiNative.stopFilteringMulticastV4Packets();
}
mDhcpActive = false;
startBatchedScan();
if (mOperationalMode != CONNECT_MODE) {
mWifiNative.disconnect();
mWifiConfigStore.disableAllNetworks();
if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
setWifiState(WIFI_STATE_DISABLED);
}
transitionTo(mScanModeState);
} else {
/* Driver stop may have disabled networks, enable right after start */
mWifiConfigStore.enableAllNetworks();
if (DBG) log("Attempting to reconnect to wifi network ..");
mWifiNative.reconnect();/*发送"RECONNECT"命令给wpas*/
// Status pulls in the current supplicant state and network connection state
// events over the monitor connection. This helps framework sync up with
// current supplicant state
mWifiNative.status();/*发送"STATUS"命令给WPAS*/
transitionTo(mDisconnectedState);/*进入mDisconnectedState*/
}
// We may have missed screen update at boot
if (mScreenBroadcastReceived.get() == false) {
PowerManager powerManager = (PowerManager)mContext.getSystemService(
Context.POWER_SERVICE);
handleScreenStateChanged(powerManager.isScreenOn());
} else {
// Set the right suspend mode settings
/*发送"DRIVER SETSUSPENDMODE"命令.该命令由Driver厂商提供的库来实现*/
mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0
&& mUserWantsSuspendOpt.get());
}
mWifiNative.setPowerSave(true);/*和P2P PowerSave有关*/
/*如果支持P2P,则通过mWifiP2pChannel向WifiP2p模块发送消息*/
if (mP2pSupported) {
if (mOperationalMode == CONNECT_MODE) {
mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P);
} else {
// P2P statemachine starts in disabled state, and is not enabled until
// CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to
// keep it disabled.
}
}
final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
@Override
public boolean processMessage(Message message) {
switch(message.what) {
case CMD_START_SCAN:
noteScanStart(message.arg1, (WorkSource) message.obj);
startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP);
break;
case CMD_SET_BATCHED_SCAN:
if (recordBatchedScanSettings(message.arg1, message.arg2,
(Bundle)message.obj)) {
startBatchedScan();
}
break;
case CMD_SET_COUNTRY_CODE:
String country = (String) message.obj;
if (DBG) log("set country code " + country);
if (country != null) {
country = country.toUpperCase(Locale.ROOT);
if (mLastSetCountryCode == null
|| country.equals(mLastSetCountryCode) == false) {
if (mWifiNative.setCountryCode(country)) {
mLastSetCountryCode = country;
} else {
loge("Failed to set country code " + country);
}
}
}
break;
case CMD_SET_FREQUENCY_BAND:
int band = message.arg1;
if (DBG) log("set frequency band " + band);
if (mWifiNative.setBand(band)) {
mFrequencyBand.set(band);
// flush old data - like scan results
mWifiNative.bssFlush();
//Fetch the latest scan results when frequency band is set
startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP);
} else {
loge("Failed to set frequency band " + band);
}
break;
case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
mBluetoothConnectionActive = (message.arg1 !=
BluetoothAdapter.STATE_DISCONNECTED);
mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
break;
case CMD_STOP_DRIVER:
int mode = message.arg1;
/* Already doing a delayed stop */
if (mInDelayedStop) {
if (DBG) log("Already in delayed stop");
break;
}
/* disconnect right now, but leave the driver running for a bit */
mWifiConfigStore.disableAllNetworks();
mInDelayedStop = true;
mDelayedStopCounter++;
if (DBG) log("Delayed stop message " + mDelayedStopCounter);
/* send regular delayed shut down */
Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null);
driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter);
mDriverStopIntent = PendingIntent.getBroadcast(mContext,
DRIVER_STOP_REQUEST, driverStopIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+ mDriverStopDelayMs, mDriverStopIntent);
break;
case CMD_START_DRIVER:
if (mInDelayedStop) {
mInDelayedStop = false;
mDelayedStopCounter++;
mAlarmManager.cancel(mDriverStopIntent);
if (DBG) log("Delayed stop ignored due to start");
if (mOperationalMode == CONNECT_MODE) {
mWifiConfigStore.enableAllNetworks();
}
}
break;
case CMD_DELAYED_STOP_DRIVER:
if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter);
if (message.arg1 != mDelayedStopCounter) break;
handleStopDriverCmd();
if (mP2pSupported) {
transitionTo(mWaitForP2pDisableState);
} else {
transitionTo(mDriverStoppingState);
}
break;
case CMD_START_PACKET_FILTERING:
if (message.arg1 == MULTICAST_V6) {
mWifiNative.startFilteringMulticastV6Packets();
} else if (message.arg1 == MULTICAST_V4) {
mWifiNative.startFilteringMulticastV4Packets();
} else {
loge("Illegal arugments to CMD_START_PACKET_FILTERING");
}
break;
case CMD_STOP_PACKET_FILTERING:
if (message.arg1 == MULTICAST_V6) {
mWifiNative.stopFilteringMulticastV6Packets();
} else if (message.arg1 == MULTICAST_V4) {
mWifiNative.stopFilteringMulticastV4Packets();
} else {
loge("Illegal arugments to CMD_STOP_PACKET_FILTERING");
}
break;
case CMD_SET_SUSPEND_OPT_ENABLED:
if (message.arg1 == 1) {
setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true);
mSuspendWakeLock.release();
} else {
setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false);
}
break;
case CMD_SET_HIGH_PERF_MODE:
if (message.arg1 == 1) {
setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false);
} else {
setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true);
}
break;
case CMD_ENABLE_TDLS:
if (message.obj != null) {
String remoteAddress = (String) message.obj;
boolean enable = (message.arg1 == 1);
mWifiNative.startTdls(remoteAddress, enable);
}
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
@Override
public void exit() {
mIsRunning = false;
updateBatteryWorkSource(null);
mScanResults = new ArrayList<ScanResult>();
stopBatchedScan();
final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
noteScanEnd(); // wrap up any pending request.
mLastSetCountryCode = null;
}
}
WifiStateMachine将转入DisconnectedState. 由于DisconnectedState的父状态是ConnectModeState, 所以它的enter函数没有做任何有意义的工作.
四. 分析DisconnectedState中的enter方法
public void enter() {
// We dont scan frequently if this is a temporary disconnect
// due to p2p
if (mTemporarilyDisconnectWifi) {
mWifiP2pChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_RESPONSE);
return;
}
mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS,
mDefaultFrameworkScanIntervalMs);
/*
* We initiate background scanning if it is enabled, otherwise we
* initiate an infrequent scan that wakes up the device to ensure
* a user connects to an access point on the move
* 当系统支持后台扫描时,如果手机屏幕关闭,则设置mEnableBackgroundScan为true启动后台扫描
*/
if (mEnableBackgroundScan) {
/* If a regular scan result is pending, do not initiate background
* scan until the scan results are returned. This is needed because
* initiating a background scan will cancel the regular scan and
* scan results will not be returned until background scanning is
* cleared
* mScanResultIsPending用于表示WifiService是否在等待普通扫描的结果.
* 因为启动后台扫描的时候会取消上一次扫描的请求,所以如果mScanResultIsPending
* 为ture的话,就先不启用后台扫描.
*/
if (!mScanResultIsPending) {
mWifiNative.enableBackgroundScan(true);
}
} else {
/*设置定时扫描任务.到时间后,AlarmManager将发送一个"ACTION_START_SCAN"Intent
* 而WifiStateMachine对Intent的处理就是调用startScan函数*/
setScanAlarm(true);
}
/**
* If we have no networks saved, the supplicant stops doing the periodic scan.
* The scans are useful to notify the user of the presence of an open network.
* Note that these are not wake up scans.
* 如果当前没有P2P连接,并且没有之前保存的AP信息,则发送CMD_NO_NETWORKS_PERIODIC_SCAN消息出发扫描
*/
if (!mP2pConnected.get() && mWifiConfigStore.getConfiguredNetworks().size() == 0) {
sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
}
}