专栏首页程序猿的那点事Android P WiFi扫描流程详解

Android P WiFi扫描流程详解

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

1、ClientModeManager

  • ClientModeStateMachine 由CMD_START 转换到StartedState
  • StartedState 状态机,在更新wifiState时,发送广播 WifiManager.WIFI_STATE_CHANGED_ACTION , 通知WifiTracker 开始进行Scan
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

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

class Scanner extends Handler {
    static final int MSG_SCAN = 0;

    private int mRetry = 0;

    void resume() {
        if (!hasMessages(MSG_SCAN)) {
            sendEmptyMessage(MSG_SCAN);
        }
    }
public void handleMessage(Message message) {
    if (message.what != MSG_SCAN) return;
    if (mWifiManager.startScan()) {
        mRetry = 0;

3、WifiManager–>WifiServiceImpl

@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

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 先获取扫描的设置,然后再开始扫描。

    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。

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

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

public abstract boolean startSingleScan(WifiNative.ScanSettings settings,
        WifiNative.ScanEventHandler eventHandler);

9、WificondScannerImpl–>WifiNative

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

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

    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

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)

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 刷新扫描结果

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 不打开Wifi获取Mac地址

    今天遇到一个问题,要求不打开Wifi的前提下获取Mac地址,所以针对Android上Mac地址的获取做了总结。 MAC地址:每个接入网络的设备都有一个专门的序...

    用户7557625
  • 识别Android按键的短按和长按以及长按时长的判断

    前言:最近在做一个关于硬按键的处理,大多数都可以转成Android的keycode,其中一个功能就是要针对按键的长按和短按来做出相应的动作,包括长按的时长不同,...

    用户7557625
  • Android Wi-Fi扫描机制(Android P)

    1、 亮屏情况下,在Wifi settings界面,固定扫描,时间间隔为10s。 2、 亮屏情况下,非Wifi settings界面,二进制指数退避扫描,退避...

    用户7557625
  • DL开源框架Caffe | 目标检测Faster-rcnn问题全解析

    一 工程目录 在github上clone下来的代码,可以看到根目录下有以下几个文件夹,其中output为训练完之后才会有的文件夹。 caffe-fast-rcn...

    深度学习思考者
  • 编程语言之间的百舸争流

    编程语言排行榜 TIOBE编程语言社区发布了2017年11月排行榜,Java、C、C ++三门编程语言依然占据前三。11月前5排名中,最值得注意的是:Pytho...

    企鹅号小编
  • Activiti7 zip部署,查询及其删除

    彼岸舞
  • 斯坦福项目NeutralTalk:让电脑像人一样看懂照片

    大数据文摘
  • 【BUG修复】TSINGSEE青犀视频云-边-端架构视频智能分析平台EasyNVR关闭云端录像计划为什么仍能录像?

    TSINGSEE青犀视频云边端架构视频智能分析平台已经全面支持录像计划的设置,配置方法大家可以参考此文:EasyNVR边缘计算网关录像计划功能操作介绍。

    EasyNVR
  • centos7-搭建FastDFS图片服务器

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

    suveng
  • Asp.net Ajax AlwaysVisibleControl使用方法

    这个控件非常好用……哈哈,有些时候,我们需要在系统中显示一些信息,又不希望这些信息通过页面滚动而不能在页面固定展示,例如广告……哈哈,所以就可以用这个控件了……

    thz

扫码关注云+社区

领取腾讯云代金券