WifiConnectivityManager 管理扫描

20 篇文章 5 订阅

通过 WifiScanner.java 中 WifiScanner 类的 registerScanListener 方法注册 Scan 结果的回调监听句柄,实际上内部通过 AsyncChannel 向 WifiScanningService 层发送了 CMD_REGISTER_SCAN_LISTENER 消息:

    /**
     * Register a listener that will receive results from all single scans.
     * Either the {@link ScanListener#onSuccess()} or  {@link ScanListener#onFailure(int, String)}
     * method will be called once when the listener is registered.
     * Afterwards (assuming onSuccess was called), all subsequent single scan results will be
     * delivered to the listener. It is possible that onFullResult will not be called for all
     * results of the first scan if the listener was registered during the scan.
     *
     * @param executor the Executor on which to run the callback.
     * @param listener specifies the object to report events to. This object is also treated as a
     *                 key for this request, and must also be specified to cancel the request.
     *                 Multiple requests should also not share this object.
     */
    @RequiresPermission(Manifest.permission.NETWORK_STACK)
    public void registerScanListener(@NonNull @CallbackExecutor Executor executor,
            @NonNull ScanListener listener) {
        Objects.requireNonNull(executor, "executor cannot be null");
        Objects.requireNonNull(listener, "listener cannot be null");
        int key = addListener(listener, executor);
        if (key == INVALID_KEY) return;
        validateChannel();
        mAsyncChannel.sendMessage(CMD_REGISTER_SCAN_LISTENER, 0, key);
    }

class WifiScanningService 定义在 WifiScanningService.java 文件中,其实际的实现在 WifiScanningServiceImpl 类中,向系统注册并提供 WIFI_SCANNING_SERVICE 服务:

/**
 * Service implementing Wi-Fi scanning functionality. Delegates actual interface
 * implementation to WifiScanningServiceImpl.
 */
public class WifiScanningService extends SystemService {

    static final String TAG = "WifiScanningService";
    private final WifiScanningServiceImpl mImpl;
    private final HandlerThread mHandlerThread;

    public WifiScanningService(Context contextBase) {
        super(new WifiContext(contextBase));
        Log.i(TAG, "Creating " + Context.WIFI_SCANNING_SERVICE);
        mHandlerThread = new HandlerThread("WifiScanningService");
        mHandlerThread.start();
        mImpl = new WifiScanningServiceImpl(getContext(), mHandlerThread.getLooper(),
                WifiScannerImpl.DEFAULT_FACTORY,
                getContext().getSystemService(BatteryStatsManager.class),
                WifiInjector.getInstance());
    }

    @Override
    public void onStart() {
        Log.i(TAG, "Publishing " + Context.WIFI_SCANNING_SERVICE);
        publishBinderService(Context.WIFI_SCANNING_SERVICE, mImpl);
    }

    @Override
    public void onBootPhase(int phase) {
        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
            Log.i(TAG, "Starting " + Context.WIFI_SCANNING_SERVICE);
            mImpl.startService();
        }
    }
}

服务的实际注册发生在 WifiFrameworkInitializer 中的 registerServiceWrappers 方法中,与 WIFI_SERVICE 等一起注册。客户端则在 WifiScanner 类中实现,在文件 WifiScanner.java 文件中。

接下来看在服务端 WifiScanningServiceImpl 中的处理过程:

1. 消息处理发生在 ClientHandler 内部类中,其 handleMessage 接口进行处理,实际上就是将对应的请求信息添加到 mSingleScanListeners 链中,其类型为 RequestList<>,添加方法为 addRequest,也是内部私有实现的类;

2. 消息回送发生在 reportFullScanResult 和 reportScanResults 接口中,通知消息有 CMD_SCAN_RESULT,CMD_SINGLE_SCAN_COMPLETED 和 CMD_FULL_SCAN_RESULT 三种;

WifiConnectivityManager 类中通过 retrieveWifiScanner 方法创建 WifiScanner 对象 mScanner,使其指向 WIFI_SCANNING_SERVICE 服务,同时向服务端注册 Scan 监听者:

    /**
     * Helper method to populate WifiScanner handle. This is done lazily because
     * WifiScanningService is started after WifiService.
     */
    private void retrieveWifiScanner() {
        if (mScanner != null) return;
        mScanner = mWifiInjector.getWifiScanner();
        checkNotNull(mScanner);
        // Register for all single scan results
        mScanner.registerScanListener(new HandlerExecutor(mEventHandler), mAllSingleScanListener);
    }

    /**
     * Start WifiConnectivityManager
     */
    private void start() {
        if (mRunning) return;
        retrieveWifiScanner();
        mConnectivityHelper.getFirmwareRoamingInfo();
        mBssidBlocklistMonitor.clearBssidBlocklist();
        mWifiChannelUtilization.init(mStateMachine.getWifiLinkLayerStats());

        if (mContext.getResources().getBoolean(R.bool.config_wifiEnablePartialInitialScan)) {
            setInitialScanState(INITIAL_SCAN_STATE_START);
        }

        mRunning = true;
        mLatestCandidates = null;
        mLatestCandidatesTimestampMs = 0;
    }

注册事件发生在 start 调用中,在 WifiConnectivityManager 启动的时候进行,mAllSingleScanListener 为 AllSingleScanListener 类对象,实现了 WifiScanner 的 ScanListener 接口类,在服务端进行 reportScanResults 等操作时对应的方法被调用用来处理回调事件。

实际的通知是调用了 ClientInfo 类的 reportEvent 方法,而 ClientInfo 又被分别继承了成为内部和外部,内部叫 InternalClientInfo,而外部叫 ExternalClientInfo,两者的消息机制有差异,External 使用了 AsyncChannel,其 sendMessage 方法被调用,而 Internal 则采用了 Messenger 的 send 方法进行发送,两者的差别和实现细节后面的文章再分析,在 WifiConnectivityManager 的 AllSingleScanListener 注册过程中在 ClientHandler 的 handleMessage 中处理,这里的 ClientInfo 为 ExternalClientInfo 对象,因此后面采用它的 reportEvent 发小消息上报。WifiScanner 的 ServiceHandler 中的 handleMessage 处理对应的消息,执行了 scanListener 的 onResults方法。

这里消息的处理还是在 Client 和 Server 之间通过 AsyncChannel 的双向通道,两者之间有 Handler 对象来处理对方发送过来的消息,从而进行相应的操作;在 Server 端实际上执行了 executor 线程来运行对应的处理过程,这里是 onResults 方法。

在 Client 端实际上是 ClientHandler 继承了 WifiHandler 进而继承了 Handler,其 handleMessage 方法在处理 CMD_REGISTER_SCAN_LISTENER 消息的时候将对应的 Request 加入到 mSingleScanListeners 中,而用于生成 RequestInfo 的 ClientInfo 对象由 mClients 的 get 方法从 msg 的 replyTo 对象(Messenger)获取到,mClients 则是 ArrayMap<Messenger, ClientInfo> 对象,每一个 AsyncChannel 在初始化过程中由 ClientInfo 的 register 方法进行注册,生成 Messenger 和 ClientInfo 对,在 ClientHandler 收到了 AsyncChannel.CMD_CHANNEL_FULL_CONNECTION 消息进行处理的时候进行的,对应的 ClientHandler 对象在 WifiScanningServiceImpl 的 startService 中创建,而 Client 端的 ServiceHandler 则是在 WifiScanner 构造函数中创建,在这里获取了一个 Service 对应的 Messenger 对象,创建了 AsyncChannel 对象并通过其 connectSync 方法将 ServiceHandler 对象 mInternalHandler 与 messenger 连接起来,并且发送了 AsyncChannel.CMD_CHANNEL_FULL_CONNECTION 消息:

    /**
     * Create a new WifiScanner instance.
     * Applications will almost always want to use
     * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
     * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
     *
     * @param context the application context
     * @param service the Binder interface for {@link Context#WIFI_SCANNING_SERVICE}
     * @param looper the Looper used to deliver callbacks
     *
     * @hide
     */
    public WifiScanner(@NonNull Context context, @NonNull IWifiScanner service,
            @NonNull Looper looper) {
        mContext = context;
        mService = service;

        Messenger messenger = null;
        try {
            messenger = mService.getMessenger();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }

        if (messenger == null) {
            throw new IllegalStateException("getMessenger() returned null!  This is invalid.");
        }

        mAsyncChannel = new AsyncChannel();

        mInternalHandler = new ServiceHandler(looper);
        mAsyncChannel.connectSync(mContext, mInternalHandler, messenger);
        // We cannot use fullyConnectSync because it sends the FULL_CONNECTION message
        // synchronously, which causes WifiScanningService to receive the wrong replyTo value.
        mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
    }

回到 WifiConnectivityManager 中的消息处理过程,假设是报告扫描结果,则 AllSingleScanListener 类中的 onResults 方法被调用,其处理过程如下:

        @Override
        public void onResults(WifiScanner.ScanData[] results) {
            if (!mWifiEnabled || !mAutoJoinEnabled) {
                clearScanDetails();
                mWaitForFullBandScanResults = false;
                return;
            }

            // We treat any full band scans (with DFS or not) as "full".
            boolean isFullBandScanResults = false;
            if (results != null && results.length > 0) {
                isFullBandScanResults =
                        WifiScanner.isFullBandScan(results[0].getBandScanned(), true);
            }
            // Full band scan results only.
            if (mWaitForFullBandScanResults) {
                if (!isFullBandScanResults) {
                    localLog("AllSingleScanListener waiting for full band scan results.");
                    clearScanDetails();
                    return;
                } else {
                    mWaitForFullBandScanResults = false;
                }
            }
            if (results != null && results.length > 0) {
                mWifiMetrics.incrementAvailableNetworksHistograms(mScanDetails,
                        isFullBandScanResults);
            }
            if (mNumScanResultsIgnoredDueToSingleRadioChain > 0) {
                Log.i(TAG, "Number of scan results ignored due to single radio chain scan: "
                        + mNumScanResultsIgnoredDueToSingleRadioChain);
            }
            boolean wasConnectAttempted = handleScanResults(mScanDetails,
                    ALL_SINGLE_SCAN_LISTENER, isFullBandScanResults);
            clearScanDetails();

            // Update metrics to see if a single scan detected a valid network
            // while PNO scan didn't.
            // Note: We don't update the background scan metrics any more as it is
            //       not in use.
            if (mPnoScanStarted) {
                if (wasConnectAttempted) {
                    mWifiMetrics.incrementNumConnectivityWatchdogPnoBad();
                } else {
                    mWifiMetrics.incrementNumConnectivityWatchdogPnoGood();
                }
            }

            // Check if we are in the middle of initial partial scan
            if (mInitialScanState == INITIAL_SCAN_STATE_AWAITING_RESPONSE) {
                // Done with initial scan
                setInitialScanState(INITIAL_SCAN_STATE_COMPLETE);

                if (wasConnectAttempted) {
                    Log.i(TAG, "Connection attempted with the reduced initial scans");
                    schedulePeriodicScanTimer(
                            getScheduledSingleScanIntervalMs(mCurrentSingleScanScheduleIndex));
                    mWifiMetrics.reportInitialPartialScan(mInitialPartialScanChannelCount, true);
                    mInitialPartialScanChannelCount = 0;
                } else {
                    Log.i(TAG, "Connection was not attempted, issuing a full scan");
                    startConnectivityScan(SCAN_IMMEDIATELY);
                    mFailedInitialPartialScan = true;
                }
            } else if (mInitialScanState == INITIAL_SCAN_STATE_COMPLETE) {
                if (mFailedInitialPartialScan && wasConnectAttempted) {
                    // Initial scan failed, but following full scan succeeded
                    mWifiMetrics.reportInitialPartialScan(mInitialPartialScanChannelCount, false);
                }
                mFailedInitialPartialScan = false;
                mInitialPartialScanChannelCount = 0;
            }
        }

具体的处理过程分析如下:

1. 判断 WiFi 开启(mWifiEnabled),并且打开了自动链接配置(mAutoJoinEnabled),否则退出;

2. 确定是否 FullBandScan 的结果(isFullBandScanResults);

3. 判断是否需要等带 FullBandScan 的结果,并根据第 2 步判断的结果来确定是否继续处理或者等待;

4. 更新 mWifiMetrics 的相关信息,关于 WifiMetrics 后面再分析;

5. 记录一些 Log 信息;

6. 最重要的 handleScanResults 登场,实际的扫描结果处理发生在该接口中,稍后详细分析该函数实现;

7. 处理之后清楚扫描的结果内容;

8. 继续更新 mWifiMetrics 相关的信息;

9. 查询当前的扫描状态,并进行相应的更新以及 mWifiMetrics 处理,如果链接过程并未进行,则触发 WiFi 的连接过程(startConnectivityScan,并且立即连接 SCAN_IMMEIDATELY);

下面分析 handleScanResults 方法

    /**
     * Handles 'onResult' callbacks for the Periodic, Single & Pno ScanListener.
     * Executes selection of potential network candidates, initiation of connection attempt to that
     * network.
     *
     * @return true - if a candidate is selected by WifiNetworkSelector
     *         false - if no candidate is selected by WifiNetworkSelector
     */
    private boolean handleScanResults(List<ScanDetail> scanDetails, String listenerName,
            boolean isFullScan) {
        mWifiChannelUtilization.refreshChannelStatsAndChannelUtilization(
                mStateMachine.getWifiLinkLayerStats(), WifiChannelUtilization.UNKNOWN_FREQ);

        updateUserDisabledList(scanDetails);

        // Check if any blocklisted BSSIDs can be freed.
        Set<String> bssidBlocklist = mBssidBlocklistMonitor.updateAndGetBssidBlocklist();

        if (mStateMachine.isSupplicantTransientState()) {
            localLog(listenerName
                    + " onResults: No network selection because supplicantTransientState is "
                    + mStateMachine.isSupplicantTransientState());
            return false;
        }

        localLog(listenerName + " onResults: start network selection");

        List<WifiCandidates.Candidate> candidates = mNetworkSelector.getCandidatesFromScan(
                scanDetails, bssidBlocklist, mWifiInfo, mStateMachine.isConnected(),
                mStateMachine.isDisconnected(), mUntrustedConnectionAllowed);
        mLatestCandidates = candidates;
        mLatestCandidatesTimestampMs = mClock.getElapsedSinceBootMillis();

        if (mDeviceMobilityState == WifiManager.DEVICE_MOBILITY_STATE_HIGH_MVMT
                && mContext.getResources().getBoolean(
                        R.bool.config_wifiHighMovementNetworkSelectionOptimizationEnabled)) {
            candidates = filterCandidatesHighMovement(candidates, listenerName, isFullScan);
        }

        WifiConfiguration candidate = mNetworkSelector.selectNetwork(candidates);
        mLastNetworkSelectionTimeStamp = mClock.getElapsedSinceBootMillis();
        mWifiLastResortWatchdog.updateAvailableNetworks(
                mNetworkSelector.getConnectableScanDetails());
        mWifiMetrics.countScanResults(scanDetails);
        if (candidate != null) {
            localLog(listenerName + ":  WNS candidate-" + candidate.SSID);
            connectToNetwork(candidate);
            return true;
        } else {
            if (mWifiState == WIFI_STATE_DISCONNECTED) {
                mOpenNetworkNotifier.handleScanResults(
                        mNetworkSelector.getFilteredScanDetailsForOpenUnsavedNetworks());
            }
            return false;
        }
    }

处理过程分析如下:

1. 更新 WifiChannelUtilization 统计信息;

2. 更新和释放 Block 的 ssid 列表信息;

3. 判断当前是否处理 transite 状态,如果是的话则不再进一步处理;

4. 开始进行 WiFi 网络选择处理过程:

① 通过 NetworkSelector 类的 getCandidatesFromScan 方法对扫描结果进行处理,获取 candidates 列表,类型为 WifiCandidates.Candidate;

② 更新 mLatestCandidates 为最新,并且记录其 timestamp 信息(mLatestCandidatesTimestampMs);

③ 如果设备处于高速移动(WifiManager.DEVICE_MOBILITY_STATE_HIGH_MVMT)且可以进行高速移动下的优化选择,则调用 filterCandidatesHighMovement 对获取到的 candidates 进行过滤;

④ 继续调用 NetworkSelector 的 selectNetwork 方法选择网络,结果为 WifiConfiguration 类型,同时更新选择时间戳;

⑤ 更新 WifiLastResortWatchdog 中记录的可用网络信息,用于更准确的网络模块重启操作;

⑥ 更新 WifiMetrics 信息;

⑦ 如果存在被选中的 candidates,则进行连接过程 connectToNetwork;

⑧ 否则如果当前处于 WIFI_STATE_DISCONNECTED 状态,则调用 OpenNetworkNotifier 的 handleScanResults 接口进行处理,主要是在扫描结果中选择网络推荐给应用进行连接;

这里最重要的是三个点:WifiMetrics 类相关方法和功能的实现,NetworkSelector 的实现以及 connectToNetwork,也包括 WifiConfiguration 类作为参数传递给 connectToNetwork,下面分别进行分析。

WifiConnectivityManager 的启动和初始化

1. WifiConnectivityManager 对象在 ClientModeImpl 中创建,在其构造函数中通过 WifiInjector 的 makeWifiConnectivityManager 方法完成创建,在 ConnectModeState 状态进入时其 enter 方法中执行了 WifiConnectivityManager 对象的 setWifiEnabled,将 mWifiEnabled 状态修改为 true,并且调用了其 updateRunningState 方法,这里会执行 WifiConnectivityManager 的 start 或者 stop 方法,如果 mWifiEnabled 为 true 且 mAutoJoinEnabled 也为 true,则会启动 WifiConnectivityManager,如前面所分析的,注册对应的回调,在事件发生时可以进行处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值