前言:
本文介绍wifi framework层的扫描处理流程,所介绍的流程的代码
- 1
- 2
全部在下面的文件中:
(android\frameworks\opt\net\wifi\service\java\com\android\server\wifi\WifiStateMachine.java)
一、wifi状态的转变
没连接ap时打开wifi的状态转变:
InitialState->SupplicantStartingState-> DriverStartedState->DisconnectedState
已连接过ap时打开wifi的状态转变:
InitialState->SupplicantStartingState->DriverStartedState->DisconnectedState-> ObtainingIpState-> ConnectedState
二、打开wifi首次扫描的触发
不管之前连接过ap,还是没连接过ap,在进入
- 1
- 2
DriverStartedState时,在enter函数内调用了
setFrequencyBand,最后发送了CMD_SET_FREQUENCY_BAND
消息。
setFrequencyBand()->setFrequencyBand(a,b)->sendMessage(CMD_SET_FREQUENCY_BAND, band, 0)
CMD_SET_FREQUENCY_BAND消息由DriverStartedState的
processMessage处理,调用下面函数:
mFrequencyBand.set(band);
// Flush old data - like scan results
mWifiNative.bssFlush();
// Fetch the latest scan results when frequency band is set
startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null);
- 1
- 2
- 3
- 4
- 5
startScanNative调用mWifiNative.scan进行最后扫描触发,一种返
回值情况如下:当之前没有连接过ap时,mWifiNative.scan返回
true,mIsFullScanOngoing就会被设置为true,最后扫描结果就会
发送sendScanResultsAvailableBroadcast广播,如果之前连接过
ap,由于这时还没连接上ap,mWifiNative.scan返回false,
mIsFullScanOngoing保持为false,最后扫描结果不会发送
sendScanResultsAvailableBroadcast广播。所以在之前连接过ap
的情况下,打开wifi后,ap还没连接上,这时应用层发起scan,由
于mWifiNative.scan返回false,这次应用层发起的scan结果不会发
送sendScanResultsAvailableBroadcast广播,应用层是监测不到
这次scan结果消息的。这种情况就会导致有时打开wifi,需要过很久
才能显示扫描到ap列表。可以在WifiStateMachine.java的
handleScanRequest函数加下面patch解决:
mWifiNative.scan的返回值由supplicant中的wpas_ctrl_scan
- 1
- 2
函数决定,当supplicant当前正在扫描、或正在调度扫描,或正在
处理连接ap的状态时,这次发起的scan就会被拒绝,上层
mWifiNative.scan的返回值就是flase,若允许这次发起的scan,
mWifiNative.scan的返回值为true。
三、没连接过ap的扫描
在之前没有连接ap的情况下,进入DisconnectedState时,在亮屏
- 1
- 2
的情况下,在DisconnectedState的enter函数中调用
startDelayedScan,发送一个10s后的CMD_START_SCAN消息,
消息源为SCAN_ALARM_SOURCE,该消息在DisconnectedState
的processMessage中处理,处理CMD_START_SCAN消息时,先
调用checkAndRestartDelayedScan检查
mDelayedScanCounter(后面有该机制的说明),判断是否执行
这次扫描,需要再执行这次扫描时,再发送一个10s后的
CMD_START_SCAN消息,然后执行扫描动作,扫描由函数
handleScanRequest调用startScanNative进行,不停反复这样扫
描过程。暗屏时这个扫描会停止,亮屏后会再启动。
同时在进入DisconnectedState状态时,检测到没有保存连接
过的ap信息,在enter时还会延后15s发送一个
CMD_NO_NETWORKS_PERIODIC_SCAN消息,
mSupplicantScanIntervalMs(15s)。
sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
- 1
- 2
- 3
CMD_NO_NETWORKS_PERIODIC_SCAN消息在
DisconnectedState状态的processMessage中处理,启动一次扫
描,延后15s发送下一个CMD_NO_NETWORKS_PERIODIC_SCAN
消息。
startScan(UNKNOWN_SCAN_SOURCE, -1, null, null);
sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
- 1
- 2
- 3
只要没有连接ap,并没有保存连接ap的信息,这个扫描每15s进行
一次。startScan函数中发送sendMessage(CMD_START_SCAN,
callingUid, scanCounter, bundle)。由于这次startScan 的消息源
为UNKNOWN_SCAN_SOURCE,这次的CMD_START_SCAN消息
不在DisconnectedState状态的processMessage中处理,而最后由
DriverStartedState状态的processMessage处理,最后调用
handleScanRequest及startScanNative进行扫描。
同时如果使用了后台wifi扫描,那在暗屏的状态下,由
mAlarmManager启动RTC_WAKEUP进行周期性扫描,时间到时会
广播(ACTION_START_SCAN, SCAN_REQUEST),由注册的一个消
息接收函数处理;
mContext.registerReceiver(
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
sScanAlarmIntentCount++; // Used for debug only
startScan(SCAN_ALARM_SOURCE, mDelayedScanCounter.incrementAndGet(), null, null);
if (VDBG)
loge("WiFiStateMachine SCAN ALARM -> " + mDelayedScanCounter.get());
}
}, new IntentFilter(ACTION_START_SCAN));
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
这个扫描暗屏时启动,亮屏时停止。
在DisconnectedState的状态下,当android 应用层发起一次扫
描时,首先调用到
android\frameworks\opt\net\wifi\service\java\com\android\server\wifi\WifiServiceImpl.java
下面的startScan,startScan函数中发送
sendMessage(CMD_START_SCAN, callingUid, scanCounter, bundle)。由于这次startScan 的消息源为应用的uid,这次的
CMD_START_SCAN消息不在DisconnectedState状态的
processMessage中处理,而最后由DriverStartedState状态的
processMessage处理,最后调用handleScanRequest及
startScanNative进行扫描。
由于亮屏、暗屏的扫描,都是利用sendMessageDelayed进
行,为了避免过多的sendMessageDelayed消息存在,频繁进行扫
描,在每个利用sendMessageDelayed发送消息的扫描类型中,都
有一个变量计算延后扫描的次数,如mDelayedScanCounter,在
每次startDelayedScan中,mDelayedScanCounter都会加1,然
后把该值作为消息的一部分发送。在一段时间后收到扫描消息后,
调用checkAndRestartDelayedScan比较消息当时发送过来的
mDelayedScanCounter与当前的mDelayedScanCounter值,两
个值相等时,才进行扫描,否则丢掉这一次扫描,这样,即使发送
了多个Delayed Scan还没有处理,也只有最后一个Delayed Scan
会真正进行扫描动作,前面的Delayed Scan会被丢掉。
三、接过过ap的扫描
若打开wifi之前连接过ap,则不会发起
- 1
- 2
CMD_NO_NETWORKS_PERIODIC_SCAN消息,也不会有
CMD_NO_NETWORKS_PERIODIC_SCAN扫描,后台扫描允许的
话,与没连接ap的情况是一样的。
而消息源为SCAN_ALARM_SOURCE的周期性扫描
CMD_START_SCAN,由没连接ap时的10s变成20s,并且
CMD_START_SCAN消息由L2ConnectedState状态的
processMessage处理,在处理CMD_START_SCAN,还会根据扫
描的时间间隔,分别进行全频段的扫描或所连接的ap所在信道的单
独扫描。实际执行扫描由handleScanRequest、startScanNative
进行,与没连接ap的情况一样。在全频段扫描的情况下,扫描结束
后会发送sendScanResultsAvailableBroadcast广播。而单信道的
扫描,扫描结束后不会发送sendScanResultsAvailableBroadcast
广播。
在L2ConnectedState的状态下,当android 应用层发起一次
扫描时,首先调用到
android\frameworks\opt\net\wifi\service\java\com\android\server\wifi\WifiServiceImpl.java
里面的startScan函数,由startScan再调用WifiStateMachine.java下面的startScan,startScan函数中发送
sendMessage(CMD_START_SCAN, callingUid, scanCounter, bundle)。由于这次startScan 的源为应用的uid,这次的
CMD_START_SCAN消息不在L2ConnectedState状态的
processMessage中处理,而最后由DriverStartedState状态的
processMessage处理,最后调用handleScanRequest及
startScanNative进行扫描。
暗屏、亮屏的Delayed Scan计数机制,与没连接ap的情况是一样的。
四、其它
Wifi作为station时,大部分情况下都是处理连接
- 1
- 2
ap(L2ConnectedState状态),或没连接
ap(DisconnectedState状态),上面介绍的也只是这两种状态,
其它中间连接状态,ap切换状态等等的情况,请自行分析。