android的wifi扫描流程及管理(framework层的wifi扫描分析)

前言:

本文介绍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切换状态等等的情况,请自行分析。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zjli321/article/details/53746123
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值