Android wifi Enable之后扫描流程

流程框架图

通常我们在设备开启wifi之后,等会会自动扫描出周围的热点。

下面看下自动扫描周围热点的流程

代码流程

1. ClientModeManager.ClientModeStateMachine

  • ClientModeStateMachine 由CMD_START 转换到StartedState
  • StartedState 状态机,在更新wifiState时,发送广播 WifiManager.WIFI_STATE_CHANGED_ACTION , 通知WifiTracker 开始进行Scan
java 复制代码
frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeManager.java
public boolean processMessage(Message message) {
    .... 
    mClientInterfaceName = mWifiNative.setupInterfaceForClientMode
    ....
    transitionTo(mStartedState); //跳转到 StartedState
}

private class StartedState extends State {
  ...
   private void onUpChanged(boolean isUp) {
   .... 
   sendScanAvailableBroadcast(true);
    mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE,
    // 发 WifiManager.WIFI_STATE_CHANGED_ACTION 广播通知 wifiTracker 启动startScan
     updateWifiState(WifiManager.WIFI_STATE_ENABLED,WifiManager.WIFI_STATE_ENABLING); 
   }
}

2. WifiTracker.BroadcastReceiver --> wifiManager.StartScan

  • WifiTracker 广播监听到WifiManager.WIFI_STATE_CHANGED_ACTION ,开启wifiManager.StartScan
java 复制代码
frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
public void onReceive(Context context, Intent intent) {
	if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action))
	{
	updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,WifiManager.WIFI_STATE_UNKNOWN));
}
}
private void updateWifiState(int state) {
	1. WifiManager.WIFI_STATE_ENABLED
		mScanner.resume();
	2.wifi 非enabled 则 mScanner.pause();
}
public void handleMessage(Message message) {
    .. 
    mWifiManager.startScan(); // 开启Wifi Scan 
}

3. wifiManager.StartScan --> WifiServiceImpl --> ScanRequestProxy.StartScan

  • 获取mWifiScanner 实例
  • 检查 调用者UID , apk package 是否有权限进行Scan,如无则直接放回
  • Create a worksource using the caller's UID.
  • Create the scan settings.
  • 初始化Scan 的band 为DFS,是否Scan 隐藏的AP
  • mWifiScanner 发起StartScan
java 复制代码
frameworks/opt/net/wifi/service/java/com/android/server/wifi/ScanRequestProxy.java
public boolean startScan(int callingUid, String packageName){
	retrieveWifiScannerIfNecessary();
	...
	// Create a worksource using the caller's UID.
        WorkSource workSource = new WorkSource(callingUid);
	   // Create the scan settings.
        WifiScanner.ScanSettings settings = new WifiScanner.ScanSettings();
          // always do full scans
        settings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
        settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
                | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
	mWifiScanner.startScan(settings, new ScanRequestProxyScanListener(), workSource);
}

4. WifiScanner.startScan --> WifiScaningServiceImpl.ClientHandler.handleMessage

  • 发送scan 请求[CMD_START_SINGLE_SCAN ] to WifiScaningServiceImpl 处理
java 复制代码
frameworks/base/wifi/java/android/net/wifi/WifiScanner.java
public void startScan(ScanSettings settings, ScanListener listener, WorkSource workSource) {
	scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
	scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
	mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
}

5. WifiScanner.startScan --> WifiScaningServiceImpl.ClientHandler.handleMessage

  • 先进行有效Scan检查
  • 当前正在Scanning,如为有效的(活)scaning,标志为ActiveScans,否则标志为PendingScans
  • 当前非Scanning,标志为PendingScans,开启一次新的Scan -- tryToStartNewScan()
  • 非有效Scan,上报错误Failed
java 复制代码
frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
 class DriverStartedState extends State {
 	case WifiScanner.CMD_START_SINGLE_SCAN:
 	    .... 一大堆code (其实就干了几件事情,见上面描述)
 	   ....
 	   tryToStartNewScan();
 }

6. WifiScaningServiceImpl.tryToStartNewScan -- WifiNative.scan

  • WifiScaningServiceImpl 到WifiScannerImpl
  • WifiScannerImpl 再到WificondScannerImpl
  • WificondScannerImpl最终到WifiNative , 可见与Android N 相比,O、P 的Scan变化太大,但是其套路还是不变,就是上面的环节无论是如何地进行封装,最后还是给到WifiNative 来处理
java 复制代码
frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
void tryToStartNewScan() {
	....
	mScannerImpl.startSingleScan(settings, this);
}

frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScannerImpl.java
public abstract boolean startSingleScan(WifiNative.ScanSettings settings,WifiNative.ScanEventHandler eventHandler);

frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
 public boolean startSingleScan(WifiNative.ScanSettings settings,    WifiNative.ScanEventHandler eventHandler) {
  ....
   freqs = allFreqs.getScanFreqs();
    success = mWifiNative.scan(mIfaceName, settings.scanType, freqs, hiddenNetworkSSIDSet);
 }

7. WifiNative.scan --> WificondControl

  • WifiNative 转到 WificondControl
  • WificondControl 通过binder 到wificond
  • wificond 开始初步的scan 任务 (scannerImpl.scan)
  • scannerImpl 传到scan_utils
  • scan_utils 通过netlink 将 NL80211_CMD_TRIGGER_SCAN传递wpa_supplicant(driver_nl80211_event.c)
  • driver_nl80211_event 将cmd下到wlan drv 里,开始了真正的干活 -- scanning
java 复制代码
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
public boolean scan( @NonNull String ifaceName, int scanType, Set<Integer> freqs, Set<String> hiddenNetworkSSIDs) {
mWificondControl.scan(ifaceName, scanType, freqs, hiddenNetworkSSIDs);
}

frameworks/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java
  public boolean scan(@NonNull String ifaceName, int scanType, Set<Integer> freqs,Set<String> hiddenNetworkSSIDs)
{
   ..  
   scannerImpl.scan(settings); 
}

system/connectivity/wificond/scanning/scanner_impl.cpp
Status ScannerImpl::scan(const SingleScanSettings& scan_settings, bool* out_success) {
	
	scan_utils_->Scan(interface_index_, request_random_mac, scan_type,ssids, freqs, &error_code); // 
}
system/connectivity/wificond/scanning/scan_utils.cpp
bool ScanUtils::Scan(uint32_t interface_index,
                     bool request_random_mac,
                     int scan_type,
                     const vector<vector<uint8_t>>& ssids,
                     const vector<uint32_t>& freqs,
                     int* error_code) {
  NL80211Packet trigger_scan(
      netlink_manager_->GetFamilyId(),
      NL80211_CMD_TRIGGER_SCAN,
      netlink_manager_->GetSequenceNumber(),
      getpid());
  
  if (scan_flags) {
    trigger_scan.AddAttribute(
        NL80211Attr<uint32_t>(NL80211_ATTR_SCAN_FLAGS,
                              scan_flags));
  }
  // We are receiving an ERROR/ACK message instead of the actual
  // scan results here, so it is OK to expect a timely response because
  // kernel is supposed to send the ERROR/ACK back before the scan starts.
  vector<unique_ptr<const NL80211Packet>> response;
  if (!netlink_manager_->SendMessageAndGetAckOrError(trigger_scan,
                                                     error_code)) {
    // Logging is done inside |SendMessageAndGetAckOrError|.
    return false;
  }
}

8. 扫描结果回传

  • 具体与scan 执行流恰为逆向,可参见上面的整体框架图
  • 这里简单说明下,当wlan drv 完成scan 之后
  • 由 wificond 直接给到WificondControl,
  • WificondControl.OnScanResultReady 上报 WifiMonitor
  • WifiMonitor -> WificondScannerImpl -> WifiScaningServiceImpl->
  • WifiScaningServiceImpl ->WifiService --> WifiTraker --> WifiSettings 刷新扫描结果
相关推荐
zh_xuan3 小时前
Android Looper源码阅读
android
用户02738518402614 小时前
[Android]RecycleView的item用法
android
前行的小黑炭14 小时前
Android :为APK注入“脂肪”,论Android垃圾代码在安全加固中的作用
android·kotlin
帅得不敢出门15 小时前
Docker安装Ubuntu搭建Android SDK编译环境
android·ubuntu·docker
tangweiguo0305198716 小时前
Android Kotlin 动态注册 Broadcast 的完整封装方案
android·kotlin
fatiaozhang952716 小时前
浪潮CD1000-移动云电脑-RK3528芯片-2+32G-安卓9-2种开启ADB ROOT刷机教程方法
android·网络·adb·电脑·电视盒子·刷机固件·机顶盒刷机
前行的小黑炭16 小时前
Android 不同构建模式下使用不同类的例子:如何在debug模式和release模式,让其使用不同的类呢?
android·kotlin·gradle
andyguo17 小时前
AI模型测评平台工程化实战十二讲(第一讲:从手工测试到系统化的觉醒)
android
2501_9159214317 小时前
小团队如何高效完成 uni-app iOS 上架,从分工到工具组合的实战经验
android·ios·小程序·uni-app·cocoa·iphone·webview
幂简集成17 小时前
通义灵码 AI 程序员低代码 API 课程实战教程
android·人工智能·深度学习·神经网络·低代码·rxjava