前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android P WiFi扫描流程详解

Android P WiFi扫描流程详解

作者头像
用户7557625
发布2020-07-15 10:48:41
1.9K0
发布2020-07-15 10:48:41
举报

从WiFi成功开启以后开始梳理:

1、ClientModeManager

  • ClientModeStateMachine 由CMD_START 转换到StartedState
  • StartedState 状态机,在更新wifiState时,发送广播 WifiManager.WIFI_STATE_CHANGED_ACTION , 通知WifiTracker 开始进行Scan
代码语言:javascript
复制
private class StartedState extends State {

         if (isUp) {
             Log.d(TAG, "Wifi is ready to use for client mode");
             sendScanAvailableBroadcast(true);
             mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE,
                                                  mClientInterfaceName);
             updateWifiState(WifiManager.WIFI_STATE_ENABLED,
                             WifiManager.WIFI_STATE_ENABLING);
         .............
     }

2、WifiTracker–>WifiManager WifiTracker 广播监听到WifiManager.WIFI_STATE_CHANGED_ACTION ,执行updateWifiState,确认WIFi开启以后,执行Scanner的resume函数。开启wifiManager.StartScan

代码语言:javascript
复制
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();

        if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
            updateWifiState(
                    intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
                            WifiManager.WIFI_STATE_UNKNOWN));
代码语言:javascript
复制
private void updateWifiState(int state) {
    if (state == WifiManager.WIFI_STATE_ENABLED) {
        if (mScanner != null) {
            // We only need to resume if mScanner isn't null because
            // that means we want to be scanning.
            mScanner.resume();
        }

resume函数会发送MSG_SCAN消息,MSG_SCAN消息的处理结果就是调用wifiManager.StartScan。

代码语言:javascript
复制
class Scanner extends Handler {
    static final int MSG_SCAN = 0;

    private int mRetry = 0;

    void resume() {
        if (!hasMessages(MSG_SCAN)) {
            sendEmptyMessage(MSG_SCAN);
        }
    }
代码语言:javascript
复制
public void handleMessage(Message message) {
    if (message.what != MSG_SCAN) return;
    if (mWifiManager.startScan()) {
        mRetry = 0;

3、WifiManager–>WifiServiceImpl

代码语言:javascript
复制
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
public boolean startScan(WorkSource workSource) {
    try {
        String packageName = mContext.getOpPackageName();
        return mService.startScan(packageName);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

4、WifiServiceImpl–>ScanRequestProxy

代码语言:javascript
复制
public boolean startScan(String packageName) {
    try {
        mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, callingUid);
        Mutable<Boolean> scanSuccess = new Mutable<>();
        boolean runWithScissorsSuccess = mWifiInjector.getWifiStateMachineHandler()
                .runWithScissors(() -> {
                    scanSuccess.value = mScanRequestProxy.startScan(callingUid, packageName);
                }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
    return true;
}

5、ScanRequestProxy–>WifiScanner 先获取扫描的设置,然后再开始扫描。

代码语言:javascript
复制
    public boolean startScan(int callingUid, String packageName) {
        // Create the scan settings.
        WifiScanner.ScanSettings settings = new WifiScanner.ScanSettings();
        // Scan requests from apps with network settings will be of high accuracy type.
        if (fromSettingsOrSetupWizard) {
            settings.type = WifiScanner.TYPE_HIGH_ACCURACY;
        }
        // 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;
        if (mScanningForHiddenNetworksEnabled) {
            // retrieve the list of hidden network SSIDs to scan for, if enabled.
            List<WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworkList =
                    mWifiConfigManager.retrieveHiddenNetworkList();
            settings.hiddenNetworks = hiddenNetworkList.toArray(
                    new WifiScanner.ScanSettings.HiddenNetwork[hiddenNetworkList.size()]);
        }
        mWifiScanner.startScan(settings, new ScanRequestProxyScanListener(), workSource);
        mIsScanProcessingComplete = false;
        return true;
    }

6、WifiScanner.–>WifiScanningServiceImpl 发送scan请求CMD_START_SINGLE_SCAN。

代码语言:javascript
复制
public void startScan(ScanSettings settings, ScanListener listener, WorkSource workSource) {
     Preconditions.checkNotNull(listener, "listener cannot be null");
     int key = addListener(listener);
     if (key == INVALID_KEY) return;
     validateChannel();
     Bundle scanParams = new Bundle();
     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);
 }

7、WifiScanningServiceImpl–>WifiScannerIm0l 先进行有效Scan检查 当前正在Scanning,如为有效的(活)scaning,标志为ActiveScans,否则标志为PendingScans 当前非Scanning,标志为PendingScans,开启一次新的Scan – tryToStartNewScan() 非有效Scan,上报错误Failed

代码语言:javascript
复制
        class DriverStartedState extends State {
            @Override
            public boolean processMessage(Message msg) {

                switch (msg.what) {
                    case CMD_DRIVER_LOADED:
                        // Ignore if we're already in driver loaded state.
                        return HANDLED;
                    case WifiScanner.CMD_START_SINGLE_SCAN:
                   ..............
                            } else {
                                mPendingScans.addRequest(ci, handler, workSource, scanSettings);
                                tryToStartNewScan();
                            }
                       
            }
        }
代码语言:javascript
复制
        void tryToStartNewScan() {
            .............
            if (mScannerImpl.startSingleScan(settings, this)) {
                mPendingScans.clear();
                transitionTo(mScanningState);
            } else {
                mWifiMetrics.incrementScanReturnEntry(
                        WifiMetricsProto.WifiLog.SCAN_UNKNOWN, mPendingScans.size());
                // notify and cancel failed scans
                sendOpFailedToAllAndClear(mPendingScans, WifiScanner.REASON_UNSPECIFIED,
                        "Failed to start single scan");
            }
        }

8、WifiScannerImpl–>WificondScannerImpl

代码语言:javascript
复制
public abstract boolean startSingleScan(WifiNative.ScanSettings settings,
        WifiNative.ScanEventHandler eventHandler);

9、WificondScannerImpl–>WifiNative

代码语言:javascript
复制
public boolean startSingleScan(WifiNative.ScanSettings settings,
        WifiNative.ScanEventHandler eventHandler) {
        if (!allFreqs.isEmpty()) {
            freqs = allFreqs.getScanFreqs();
            success = mWifiNative.scan(
                    mIfaceName, settings.scanType, freqs, hiddenNetworkSSIDSet);
            if (!success) {
                Log.e(TAG, "Failed to start scan, freqs=" + freqs);
            }

        return true;
    }
}

10、WifiNative–>WificondControl

代码语言:javascript
复制
public boolean scan(
        @NonNull String ifaceName, int scanType, Set<Integer> freqs,
        Set<String> hiddenNetworkSSIDs) {
    return mWificondControl.scan(ifaceName, scanType, freqs, hiddenNetworkSSIDs);
}

11、WificondControl–>scanner_impl.cpp

代码语言:javascript
复制
    public boolean scan(@NonNull String ifaceName,
                        int scanType,
                        Set<Integer> freqs,
                        Set<String> hiddenNetworkSSIDs) {
        ............
        try {
            return scannerImpl.scan(settings);
        } catch (RemoteException e1) {
            Log.e(TAG, "Failed to request scan due to remote exception");
        }
        return false;
    }

12、scanner_impl.cpp–>scan_utils.cpp

代码语言:javascript
复制
Status ScannerImpl::scan(const SingleScanSettings& scan_settings,
                         bool* out_success) {
  ................
  int error_code = 0;
  if (!scan_utils_->Scan(interface_index_, request_random_mac, scan_type,
                         ssids, freqs, &error_code)) {
    CHECK(error_code != ENODEV) << "Driver is in a bad state, restarting wificond";
    *out_success = false;
    return Status::ok();
  }
}

13、scan_utils.cpp scan_utils 通过netlink 将 NL80211_CMD_TRIGGER_SCAN传递wpa_supplicant(driver_nl80211_event.c)

代码语言:javascript
复制
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());
  trigger_scan.AddFlag(NLM_F_ACK);
  NL80211Attr<uint32_t> if_index_attr(NL80211_ATTR_IFINDEX, interface_index);

  NL80211NestedAttr ssids_attr(NL80211_ATTR_SCAN_SSIDS);
  for (size_t i = 0; i < ssids.size(); i++) {
    ssids_attr.AddAttribute(NL80211Attr<vector<uint8_t>>(i, ssids[i]));
  }
  NL80211NestedAttr freqs_attr(NL80211_ATTR_SCAN_FREQUENCIES);
  for (size_t i = 0; i < freqs.size(); i++) {
    freqs_attr.AddAttribute(NL80211Attr<uint32_t>(i, freqs[i]));
  }

  trigger_scan.AddAttribute(if_index_attr);
  trigger_scan.AddAttribute(ssids_attr);
  // An absence of NL80211_ATTR_SCAN_FREQUENCIES attribue informs kernel to
  // scan all supported frequencies.
  if (!freqs.empty()) {
    trigger_scan.AddAttribute(freqs_attr);
  }

  uint32_t scan_flags = 0;
  if (request_random_mac) {
    scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
  }
  switch (scan_type) {
    case IWifiScannerImpl::SCAN_TYPE_LOW_SPAN:
      scan_flags |= NL80211_SCAN_FLAG_LOW_SPAN;
      break;
    case IWifiScannerImpl::SCAN_TYPE_LOW_POWER:
      scan_flags |= NL80211_SCAN_FLAG_LOW_POWER;
      break;
    case IWifiScannerImpl::SCAN_TYPE_HIGH_ACCURACY:
      scan_flags |= NL80211_SCAN_FLAG_HIGH_ACCURACY;
      break;
    case IWifiScannerImpl::SCAN_TYPE_DEFAULT:
      break;
    default:
      CHECK(0) << "Invalid scan type received: " << scan_type;
  }
  if (scan_flags) {
    trigger_scan.AddAttribute(
        NL80211Attr<uint32_t>(NL80211_ATTR_SCAN_FLAGS,
                              scan_flags));
  }

  vector<unique_ptr<const NL80211Packet>> response;
  if (!netlink_manager_->SendMessageAndGetAckOrError(trigger_scan,
                                                     error_code)) {
    // Logging is done inside |SendMessageAndGetAckOrError|.
    return false;
  }
  return true;
}

14、扫描结果回传 WificondControl.OnScanResultReady 上报 WifiMonitor WifiMonitor -> WificondScannerImpl -> WifiScaningServiceImpl-> WifiScaningServiceImpl ->WifiService --> WifiTracker --> WifiSettings 刷新扫描结果

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-12-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
命令行工具
腾讯云命令行工具 TCCLI 是管理腾讯云资源的统一工具。使用腾讯云命令行工具,您可以快速调用腾讯云 API 来管理您的腾讯云资源。此外,您还可以基于腾讯云的命令行工具来做自动化和脚本处理,以更多样的方式进行组合和重用。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档