Wifi模块—源码分析Wifi热点扫描2(Android P)

2023-11-12

一 前言

       这次接着讲Wifi工程流程中的Wifi热点扫描过程部分的获取扫描结果的过程,也是Wifi扫描过程的延续,可以先看前面Wifi扫描的分析过程。

                           Wifi模块—源码分析Wifi热点扫描(Android P)

                            

二 图示调用流程

      这次的调用流程比较简单就不画流程图了,而且流程是按三条不连贯的线路分析的。

三 代码具体流程

1 底层获取扫描结果

     在上一篇我们分析了Wifi扫描的过程。在底层完成扫描之后会通知框架层,由框架层的WifiMonitor监听该事件并发送消息SCAN_RESULTS_EVENT,通知WificondScannerImpl进行处理,再通过WifiNative从底层获取wifi扫描结果,最后再广播SCAN_RESULTS_AVAILABLE_ACTION通知扫描结果可获取。

1.1 framework/opt/net/wifi/service/java/com/android/server/wifi/WifiMonitor.java

/**
* Broadcast scan result event to all the handlers registered for this event.
* @param iface Name of iface on which this occurred.
*/
public void broadcastScanResultEvent(String iface) {
    sendMessage(iface, SCAN_RESULTS_EVENT);
}
 

1.2 framework/opt/net/wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java

@Override
public boolean handleMessage(Message msg) {
    switch(msg.what) {
        case WifiMonitor.SCAN_FAILED_EVENT:
            Log.w(TAG, "Scan failed");
            cancelScanTimeout();
            reportScanFailure();
            break;
        case WifiMonitor.PNO_SCAN_RESULTS_EVENT:
            pollLatestScanDataForPno();
            break;
        case WifiMonitor.SCAN_RESULTS_EVENT:
            cancelScanTimeout();
            pollLatestScanData();
            break;
        default:
            // ignore unknown event
    }
    return true;
}
继续看 pollLatestScanData。

private void pollLatestScanData() {
    synchronized (mSettingsLock) {
        if (mLastScanSettings == null) {
            // got a scan before we started scanning or after scan was canceled
            return;
        }
 
        mNativeScanResults = mWifiNative.getScanResults(mIfaceName);
        List<ScanResult> singleScanResults = new ArrayList<>();
        int numFilteredScanResults = 0;
        for (int i = 0; i < mNativeScanResults.size(); ++i) {
            ScanResult result = mNativeScanResults.get(i).getScanResult();
            long timestamp_ms = result.timestamp / 1000; // convert us -> ms
            if (timestamp_ms > mLastScanSettings.startTime) {
                if (mLastScanSettings.singleScanFreqs.containsChannel(
                                result.frequency)) {
                    singleScanResults.add(result);
                }
            } else {
                numFilteredScanResults++;
            }
        }
        ...
    }
}
 通过mWifiNative.getScanResults来从底层获取wifi热点扫描结果。

1.3 framework/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java

/**
* Fetch the latest scan result from kernel via wificond.
* @param ifaceName Name of the interface.
* @return Returns an ArrayList of ScanDetail.
* Returns an empty ArrayList on failure.
*/
public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName) {
    return mWificondControl.getScanResults(
            ifaceName, WificondControl.SCAN_TYPE_SINGLE_SCAN);
}
接着看mWificondControl.getScanResults。

1.4 framework/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java

/**
* Fetch the latest scan result from kernel via wificond.
* @param ifaceName Name of the interface.
* @return Returns an ArrayList of ScanDetail.
* Returns an empty ArrayList on failure.
*/
public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName, int scanType) {
    ArrayList<ScanDetail> results = new ArrayList<>();
    IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
    if (scannerImpl == null) {
        Log.e(TAG, "No valid wificond scanner interface handler");
        return results;
    }
    try {
        NativeScanResult[] nativeResults;
        if (scanType == SCAN_TYPE_SINGLE_SCAN) {
            nativeResults = scannerImpl.getScanResults();
        } else {
            nativeResults = scannerImpl.getPnoScanResults();
        }
        ...
    }
    ...
 
    return results;
}
看scannerImpl.getScanResults。

1.5 system/connectivity/wificond/aidl/android/net/wifi/IWifiScannerImpl.aidl

接下来就会调到C++层,暂时就不往下分析了。

 2 通知扫描结果可获取

接下来广播SCAN_RESULTS_AVAILABLE_ACTION通知扫描结果可获取。

2.1 frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java

 在这里会接收到扫描结果可获取的广播WifiManager.SCAN_RESULTS_AVAILABLE_ACTION。

/**
*  Receiver for handling broadcasts.
*
*  This receiver is registered on the WorkHandler.
*/
@VisibleForTesting
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));
        } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
            mStaleScanResults = false;
 
            fetchScansAndConfigsAndUpdateAccessPoints();
        } else if (WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action)
                || WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) {
            fetchScansAndConfigsAndUpdateAccessPoints();
        } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
            // TODO(sghuman): Refactor these methods so they cannot result in duplicate
            // onAccessPointsChanged updates being called from this intent.
            NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
            updateNetworkInfo(info);
            fetchScansAndConfigsAndUpdateAccessPoints();
        } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
            NetworkInfo info =
                    mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork());
            updateNetworkInfo(info);
        }
    }
};
WifiTracker接收到这个广播后,执行fetchScansAndConfigsAndUpdateAccessPoints。

/**
* Retrieves latest scan results and wifi configs, then calls
* {@link #updateAccessPoints(List, List)}.
*/
private void fetchScansAndConfigsAndUpdateAccessPoints() {
    final List<ScanResult> newScanResults = mWifiManager.getScanResults();
    if (isVerboseLoggingEnabled()) {
        Log.i(TAG, "Fetched scan results: " + newScanResults);
    }
 
    List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
    updateAccessPoints(newScanResults, configs);
}
走到mWifiManager.getScanResults。

2.2 framework/base/wifi/java/android/net/wifi/WifiManager.java

/**
* Return the results of the latest access point scan.
* @return the list of access points found in the most recent scan. An app must hold
* {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
* {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
* in order to get valid results.  If there is a remote exception (e.g., either a communication
* problem with the system service or an exception within the framework) an empty list will be
* returned.
*/
public List<ScanResult> getScanResults() {
    try {
        return mService.getScanResults(mContext.getOpPackageName());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}
又是通过aidl进行跨进程调用mService.getScanResults。

2.3 framework/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java

/**
* Return the results of the most recent access point scan, in the form of
* a list of {@link ScanResult} objects.
* @return the list of results
*/
@Override
public List<ScanResult> getScanResults(String callingPackage) {
    enforceAccessPermission();
    int uid = Binder.getCallingUid();
    long ident = Binder.clearCallingIdentity();
    if (mVerboseLoggingEnabled) {
        mLog.info("getScanResults uid=%").c(uid).flush();
    }
    try {
        mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, uid);
        final List<ScanResult> scanResults = new ArrayList<>();
        boolean success = mWifiInjector.getWifiStateMachineHandler().runWithScissors(() -> {
            scanResults.addAll(mScanRequestProxy.getScanResults());
        }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
        if (!success) {
            Log.e(TAG, "Failed to post runnable to fetch scan results");
        }
        return scanResults;
    } catch (SecurityException e) {
        return new ArrayList<ScanResult>();
    } finally {
        Binder.restoreCallingIdentity(ident);
    }
}
返回scanResults。

这里和android O还是有一些差别的。看mScanRequestProxy.getScanResults。

2.4 framework/opt/net/wifi/service/java/com/android/server/wifi/ScanRequestProxy.java

/**
* Return the results of the most recent access point scan, in the form of
* a list of {@link ScanResult} objects.
* @return the list of results
*/
public List<ScanResult> getScanResults() {
    return mLastScanResults;
}
看看mLastScanResults怎么来的。

// Common scan listener for scan requests.
private class ScanRequestProxyScanListener implements WifiScanner.ScanListener {
    ...
    @Override
    public void onResults(WifiScanner.ScanData[] scanDatas) {
        if (mVerboseLoggingEnabled) {
            Log.d(TAG, "Scan results received");
        }
        // For single scans, the array size should always be 1.
        if (scanDatas.length != 1) {
            Log.wtf(TAG, "Found more than 1 batch of scan results, Failing...");
            sendScanResultBroadcastIfScanProcessingNotComplete(false);
            return;
        }
        WifiScanner.ScanData scanData = scanDatas[0];
        ScanResult[] scanResults = scanData.getResults();
        if (mVerboseLoggingEnabled) {
            Log.d(TAG, "Received " + scanResults.length + " scan results");
        }
        // Store the last scan results & send out the scan completion broadcast.
        mLastScanResults.clear();
        mLastScanResults.addAll(Arrays.asList(scanResults));
        sendScanResultBroadcastIfScanProcessingNotComplete(true);
    }
    ...
};
将scanResults放进LastScanResults,看scanData.getResults。WifiScanner的服务端是WifiScanningServiceImpl。

2.5 framework/base/wifi/java/android/net/wifi//WifiScanner.java

/**
* all the information garnered from a single scan
*/
public static class ScanData implements Parcelable {
 
    ...
    public ScanResult[] getResults() {
        return mResults;
    }
    ...
}
返回mResults。

3 Settings应用层获取扫描结果

应用层

3.1 packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java

在生命周期函数里监听Wifi的状态。

@Override
public void onStart() {
    super.onStart();
 
    // On/off switch is hidden for Setup Wizard (returns null)
    mWifiEnabler = createWifiEnabler();
 
    if (mIsRestricted) {
        restrictUi();
        return;
    }
 
    onWifiStateChanged(mWifiManager.getWifiState());
}
当wifi状态改变时会有相应的操作。

/** Called when the state of Wifi has changed. */
@Override
public void onWifiStateChanged(int state) {
    if (mIsRestricted) {
        return;
    }
 
    final int wifiState = mWifiManager.getWifiState();
    switch (wifiState) {
        case WifiManager.WIFI_STATE_ENABLED:
            updateAccessPointPreferences();
            break;
 
        case WifiManager.WIFI_STATE_ENABLING:
            removeConnectedAccessPointPreference();
            mAccessPointsPreferenceCategory.removeAll();
            addMessagePreference(R.string.wifi_starting);
            setProgressBarVisible(true);
            break;
 
        case WifiManager.WIFI_STATE_DISABLING:
            removeConnectedAccessPointPreference();
            mAccessPointsPreferenceCategory.removeAll();
            addMessagePreference(R.string.wifi_stopping);
            break;
 
        case WifiManager.WIFI_STATE_DISABLED:
            setOffMessage();
            setAdditionalSettingsSummaries();
            setProgressBarVisible(false);
            break;
    }
}
监听到wifi状态已经开启,看updateAccessPointPreferences。

private void updateAccessPointPreferences() {
    // in case state has changed
    if (!mWifiManager.isWifiEnabled()) {
        return;
    }
    // AccessPoints are sorted by the WifiTracker
    final List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
    if (isVerboseLoggingEnabled()) {
        Log.i(TAG, "updateAccessPoints called for: " + accessPoints);
    }
    ...
}
看mWifiTracker.getAccessPoints。

 java框架层

3.2 frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java

/**
* Gets the current list of access points.
*
* <p>This method is can be called on an abitrary thread by clients, but is normally called on
* the UI Thread by the rendering App.
*/
@AnyThread
public List<AccessPoint> getAccessPoints() {
    synchronized (mLock) {
        return new ArrayList<>(mInternalAccessPoints);
    }
}
接下来的过程最终还是会走到WifiManager.getScanResults,WifiServiceImpl.getScanResults,细节上会有差异。

 
————————————————
版权声明:本文为CSDN博主「BrighterLi」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42093428/article/details/82834234

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Wifi模块—源码分析Wifi热点扫描2(Android P) 的相关文章

  • unity种四种光源

    unity 中的光 unity中一共有四种光源分别为 Directional light 方向光 类似太阳的日照效果 Point light 点光源 类似蜡烛 Spotlight 聚光灯 类似手电筒 Area Light 区域光 无法用作实

随机推荐

  • 【c++设计模式】——模板方法模式

    模板方法模式的定义 定义一个操作中的算法对象的骨架 稳定 而将一些步骤延迟到子类 定义一个虚函数 让子类去实现 template method使得子类可以不改变 复用 一个算法结构即可重定义该算法的某些步骤 在理解模板方法模式的时候 我们需
  • 深入 Docker:容器和镜像

    在本专栏往期的 Flux7 系列教程 里 我们已经简单地探讨了 Docker 的基本操作 而在那篇教程中 我们一直是简单地将容器当成是 正在运行的镜像 并没有深入地区分镜像和容器到底是什么 有什么区别 因此本次翻译 深入 Docker 容器
  • 服务器固态硬盘接口区别,s s d固态硬盘和服务器配件硬盘的区别

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 s s d固态硬盘 区别于机械硬盘 固态硬盘 Solid State Drives 简称固盘 固态硬盘 Solid State Drive 用固态电子存储芯片阵列而制成的硬盘 由控制单元 和存储
  • docker cgroups 资源限制

    cgroups资源限制技术 1 什么是cgroups cgroups是linux内核提供的一种机制 这种机制可以通过需求把一系列系统任务 及其子任务整合到按资源划分的不同组内 从而为系统资源管理提供统一的框架 通俗来说 cgroups可以限
  • nginx 301 Moved Permanently错误

    问题场景 今天在利用nginx的alias和index参数做实验时 问题描述 通过curl访问出现301错误 原因分析 起初我以为是路径写错了 然后把alias的路径更改 发现问题还是存在 我又以为是用户权限问题 我把运行nginx的用户修
  • ❤️DDOS攻击详解❤️——万物互联时代的巨大威胁!安全领域最棘手的问题之一

    DDOS全称Distributed Denial of Service 翻译成中文是 分布式拒绝服务 DDOS攻击是安全领域最难解决的问题之一 由于其攻击方式的特殊性 始终没有一个完美的解决方案 随着万物互联时代的临近 网络设备的数量呈指数
  • Hadoop(五)Yarn

    Hadoop 五 Yarn 一 Yarn基本理论 1 Yarn架构 2 Yarn工作机制 3 Yarn调度器 4 Yarn常用命令 5 Yarn参数配置 二 tool接口 一 Yarn基本理论 1 Yarn架构 Resource Manag
  • 坏掉的打字机 & 布尔零点计数

    坏掉的打字机 贝博士发明了一种能够自动输出数字并求和的打字机 但这台打字机出了一些故障 它除了输出数字以外还会随机地输出其他字符 艾小姐让贝博士不要着急 她写了一段程序 能够让这台打字机即使在这样的情况下也能输出正确答案 那么 你知道艾小姐
  • 好用到爆,GitHub 星标 32.5k+的命令行软件管理神器,功能真强大

    前言 废话 本来打算在公司偷偷摸摸给星球的用户写一篇编程喵整合 MongoDB 的文章 结果在通过 brew 安装 MongoDB 的时候竟然报错了 原因很简单 公司这台 Mac 上的 homebrew 环境没有配置好 刚好 Java 程序
  • 计算机的”性能“

    前言 性能这个词在很多领域都出现过 比如一个跑车的性能 一个家电的性能 一个电脑的性能 其实在我看来一个东西的性能 就是他在某一方法的能力 比如跑车最重要的就是速度 一个计算机则是他的运行速度 在计算机组成原理中理解计算机怎么运行 为什么要
  • selenium启动Chrome配置参数问题

    每次当selenium启动chrome浏览器的时候 chrome浏览器很干净 没有插件 没有收藏 没有历史记录 这是因为selenium在启动chrome时为了保证最快的运行效率 启动了一个裸浏览器 这就是为什么需要配置参数的原因 但是有些
  • JavaFX 滚动条

    使用ScrollBar可以创建滚动条 创建滚动条 使用如下的构造函数可以创建滚动条 ScrollBar scrollbar new ScorllBar 查看API帮助文档 我们可以看到几个常用的设置属性的方法 这里简单介绍几个比较常用的方法
  • 大数据(hadoop分布式搭建--尚硅谷)手把手教学

    二 Hadoop 运行环境搭建 1 创建虚拟机 创建名称为hadoop100 在这里插入图片描述 https img blog csdnimg cn e89556e0b9b54d9fa3f25dea18873db2 png 2 配置三处网络
  • chart模板文件简单语法使用

    参考网址 https docs helm sh chart template guide the chart template developer s guide helm 模板 helm模板语法嵌套在 和 之间 有三个常见的 Values
  • 通过反编译定制android ROM

    以下操作是基于接近原生Android 4 4的系统下进行 是白牌设备 1 copy system 整个目录的 apk copy 到本地 2 对里面的 apk 重新进行签名 3 放回设备里面 重新启动 如果运行正常 那么现在就拥有设备的系统签
  • 上海链节科技的介绍

    上海链节科技有限公司 诞生于产业加速重塑 数字化金融格局加速转型的浪潮中 立足于区块链 数字经济为实体经济赋能 为社会进步和经济发展提供高效率 低成本的数字化转型解决方案 通过与实体企业 人民大众的生产 生活消费产生直接 正向的链接 从真正
  • JavaFX 程序退出时结束子线程

    1 前言 在JavaFX的程序开发中 在调用子线程之后子线程还未结束时 我们点击应用程序右上角的关闭按钮的时候 我们会发现程序还没有真正的结束运行 这是因为我们的子线程没有在JavaFX的管理之下 2 如何关闭 在主方法中找到Stage类
  • 机器学习数据集_机器学习数据集的选择

    机器学习数据集 Before you is an article guide to open data sets for machine learning In it I for a start will collect a selecti
  • 会话列表

    java实现 题目描述 小云正在参与开发一个即时聊天工具 他负责其中的会话列表部分 会话列表为显示为一个从上到下的多行控件 其中每一行表示一个会话 每一个会话都可以以一个唯一正整数id表示 当用户在一个会话中发送或接收信息时 如果该会话已经
  • Wifi模块—源码分析Wifi热点扫描2(Android P)

    一 前言 这次接着讲Wifi工程流程中的Wifi热点扫描过程部分的获取扫描结果的过程 也是Wifi扫描过程的延续 可以先看前面Wifi扫描的分析过程 Wifi模块 源码分析Wifi热点扫描 Android P 二 图示调用流程 这次的调用流