前言:

本文介绍wifi framework层的扫描处理流程,所介绍的流程的代码

全部在下面的文件中:
(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,在进入

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 resultsmWifiNative.bssFlush();// Fetch the latest scan results when frequency band is setstartScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null);

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

函数决定,当supplicant当前正在扫描、或正在调度扫描,或正在
处理连接ap的状态时,这次发起的scan就会被拒绝,上层
mWifiNative.scan的返回值就是flase,若允许这次发起的scan,
mWifiNative.scan的返回值为true。

三、没连接过ap的扫描

在之前没有连接ap的情况下,进入DisconnectedState时,在亮屏

的情况下,在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)

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);

只要没有连接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));

这个扫描暗屏时启动,亮屏时停止。
在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,则不会发起

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时,大部分情况下都是处理连接

ap(L2ConnectedState状态),或没连接
ap(DisconnectedState状态),上面介绍的也只是这两种状态,
其它中间连接状态,ap切换状态等等的情况,请自行分析。

更多相关文章

  1. 条码扫描二维码扫描——ZXing android 源码简化
  2. Android进程间通信--消息机制及IPC机制实现
  3. Android应用程序消息处理机制(Looper、Handler)分析(1)
  4. Android面试系列文章2018之Android部分之自定义View篇
  5. Android全屏,隐藏状态栏和标题栏
  6. Handler的运行机制
  7. delphi XE开发微信支付Android获取手机存储权限、Android获取短
  8. Android(安卓)的网络编程
  9. Android核心分析 之十一-------Android(安卓)GWES之消息系统

随机推荐

  1. android edittext 输入手机号码格式变化
  2. android 用代码编写linearlayout布局
  3. android猜数字游戏
  4. Android(安卓)IntentService源码分析
  5. 自定义按钮实现android 返回按钮 事件
  6. Android 添加桌面快捷方式操作
  7. android 界面 滑入 效果
  8. Android 文件下载工具类
  9. android 的popwindow弹窗
  10. android 应用异常可以引起android系统崩