前言:

本文介绍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解决:
android的wifi扫描流程及管理(framework层的wifi扫描分析)_第1张图片

    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. C语言函数以及函数的使用
  2. Android应用程序消息处理机制(Looper、Handler)分析(1)
  3. Android全屏,隐藏状态栏和标题栏
  4. [Android面试系列]一句话讲清楚Android消息机制
  5. Android开发艺术探索——第十章:Android的消息机制
  6. Android沉浸式状态栏、导航栏

随机推荐

  1. 在Android中利用iText生成PDF
  2. android应用基础--由官方帮助文件翻译
  3. camp
  4. 9.1、Android中得到新打开Activity 关闭
  5. Android修炼之道——GreenDroid 架构工具
  6. Android程序的签名保护及绕过方法
  7. Android(安卓)IPC机制之 Android的各种IP
  8. Vue.js实战——开发Android(安卓)Hybird
  9. 编译 go 源码为 android 动态库(so)
  10. Android(安卓)手机上安装并运行 Ubuntu 1