【Android-WIFI】(二) Wifi 扫描

1 扫描服务注册

//frameworks/base/services/java/com/android/server/SystemServer.java
if (context.getPackageManager().hasSystemFeature(
        PackageManager.FEATURE_WIFI)) {
    // Wifi Service must be started first for wifi-related services.
    //...
    t.traceBegin("StartWifiScanning");
    mSystemServiceManager.startServiceFromJar(
            WIFI_SCANNING_SERVICE_CLASS, WIFI_APEX_SERVICE_JAR_PATH);
    t.traceEnd();
}

在 SystemServer 中注册 并启动 WiFiScanning 服务,创建了 WifiScanningService。

//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WifiScanningService.java
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();
    }
}

创建 WifiScanningService 实例对象的时候创建了 WifiScanningServiceImpl,也就是 WifiScanningService 的实际实现类。并且将 WifiScanningServiceImpl 注册到 ServiceManager 中。此处主要还创建了 ScannerImplFactory。

在 PHASE_SYSTEM_SERVICES_READY 阶段,SystemServer 将会通过其内部的 SystemServiceManager 来挨个调用自己管理的系统服务的 onBootPhase,也就包括 WifiScanningService,接下来调用到 WifiServiceScanningImpl 的 startService 方法中。

//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
public void startService() {
    mWifiThreadRunner.post(() -> {
        mBackgroundScanStateMachine = new WifiBackgroundScanStateMachine(mLooper);
        mSingleScanStateMachine = new WifiSingleScanStateMachine(mLooper);
        mPnoScanStateMachine = new WifiPnoScanStateMachine(mLooper);

        mBackgroundScanStateMachine.start();
        mSingleScanStateMachine.start();
        mPnoScanStateMachine.start();

        // Create client handler only after StateMachines are ready.
        mClientHandler = new ClientHandler(TAG, mLooper);
    });
}

其中创建了并启动了各种状态机:WifiBackgroundScanStateMachine,WifiSingleScanStateMachine,WifiPnoScanStateMachine。还创建了一个 ClientHandler,用于处理来自 WifiScanner 发过来的消息。

2 启动服务

在 ConcreteClientModeManager 的 ConnectModeState 状态下,创建了 ClientModeImpl 以后,调用了 setRoleInternalAndInvokeCallback。

//packages/modules/Wifi/service/java/com/android/server/wifi/ConcreteClientModeManager.java
private void setRoleInternalAndInvokeCallback(@NonNull RoleChangeInfo roleChangeInfo) {
    if (roleChangeInfo.role == mRole) return;
    if (mRole == null) {
        Log.v(getTag(), "ClientModeManager started in role: " + roleChangeInfo);
        setRoleInternal(roleChangeInfo);
        mModeListener.onStarted(ConcreteClientModeManager.this);
    } else {
        Log.v(getTag(), "ClientModeManager role changed: " + roleChangeInfo);
        setRoleInternal(roleChangeInfo);
        reset();
        mModeListener.onRoleChanged(ConcreteClientModeManager.this);
    }
    if (mClientModeImpl != null) {
        mClientModeImpl.onRoleChanged();
    }
}
//packages/modules/Wifi/service/java/com/android/server/wifi/ActiveModeWarden.java/ClientListener.class
private void onStartedOrRoleChanged(ConcreteClientModeManager clientModeManager) {
    updateClientScanMode();
    updateBatteryStats();
    configureHwForMultiStaIfNecessary();
    if (mExternalRequestListener != null) {
        mExternalRequestListener.onAnswer(clientModeManager);
        mExternalRequestListener = null; // reset after one shot.
    }

    // Report to SarManager
    reportWifiStateToSarManager();
}

ConcreClientManager 内部的状态机状态转换成 ConnectModeState 时,通过 setRoleInternalAndInvokeCallback 调用到 ModeListener,由于此时是 Client 模式,所以这里的 Listener 是 ClientListener。如果是启动 WiFi 则回调到 onStart,如果是 role 切换则回调到 onRoleChanged。onStart 和 onRoleChanged 都会调用到 onStartedOrRoleChanged。

//packages/modules/Wifi/service/java/com/android/server/wifi/ActiveModeWarden.java
private void updateClientScanMode() {
    boolean scanEnabled = hasAnyClientModeManager();
    boolean scanningForHiddenNetworksEnabled;

    if (mContext.getResources().getBoolean(R.bool.config_wifiScanHiddenNetworksScanOnlyMode)) {
        scanningForHiddenNetworksEnabled = hasAnyClientModeManager();
    } else {
        scanningForHiddenNetworksEnabled = hasAnyClientModeManagerInConnectivityRole();
    }
    mScanRequestProxy.enableScanning(scanEnabled, scanningForHiddenNetworksEnabled);
}

基于 ClientMode 来更新 ScanMode。接着启动扫描,这里传入的两个参数都是 true。

//packages/modules/Wifi/service/java/com/android/server/wifi/ScanRequestProxy.java
public void enableScanning(boolean enable, boolean enableScanningForHiddenNetworks) {
    if (enable) {
        enableScanningInternal(true);
        mScanningForHiddenNetworksEnabled = enableScanningForHiddenNetworks;
        Log.i(TAG, "Scanning for hidden networks is "
                + (enableScanningForHiddenNetworks ? "enabled" : "disabled"));
    } else {
        enableScanningInternal(false);
    }
    mScanningEnabled = enable;
}

private void enableScanningInternal(boolean enable) {
    if (!retrieveWifiScannerIfNecessary()) {
        Log.e(TAG, "Failed to retrieve wifiscanner");
        return;
    }
    mWifiScanner.setScanningEnabled(enable);
    sendScanAvailableBroadcast(mContext, enable);
    if (!enable) clearScanResults();
    Log.i(TAG, "Scanning is " + (enable ? "enabled" : "disabled"));
}

private void sendScanAvailableBroadcast(Context context, boolean available) {
    Log.d(TAG, "Sending scan available broadcast: " + available);
    final Intent intent = new Intent(WifiManager.ACTION_WIFI_SCAN_AVAILABILITY_CHANGED);
    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, available);
    context.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}

//packages/modules/Wifi/framework/java/android/net/wifi/WifiScanner.java
public void setScanningEnabled(boolean enable) {
    validateChannel();
    mAsyncChannel.sendMessage(enable ? CMD_ENABLE : CMD_DISABLE, Process.myTid(),
            Binder.getCallingPid(), mContext.getOpPackageName());
}

enableScanning 先是调用 WifiScanner 的 setScanningEnabled 方法来启动扫描。接着调用 sendScanAvailableBroadcast 发送一个扫描可用的的广播。WifiScanner 中的 setScanningEnabled 方法主要是向内部的 AsyncChannel 发送了一个 CMD_ENABLE。AsyncChannel 的对端是 WifiScanneingServiceImpl,所以由 ClientHandler 来处理这个消息。

//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java/ClientHandler.class
case WifiScanner.CMD_ENABLE:
    Log.i(TAG, "Received a request to enable scanning, UID = " + msg.sendingUid);
    setupScannerImpls();
    mBackgroundScanStateMachine.sendMessage(Message.obtain(msg));
    mSingleScanStateMachine.sendMessage(Message.obtain(msg));
    mPnoScanStateMachine.sendMessage(Message.obtain(msg));
    mLastCallerInfoManager.put(LastCallerInfoManager.SCANNING_ENABLED, msg.arg1,
            msg.sendingUid, msg.arg2, (String) msg.obj, true);
    break;

ClientHandler 处理 CMD_ENABLE 消息主要是通过 ScannerImplFactory 创建了所有 Sta 接口的 ScannerImpl,并向 WifiScanningServiceImpl 内部的几个状态机转发了自己收到的消息。

//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java/WifiBackgroundScanStateMachine.class/DefaultState.class
case WifiScanner.CMD_ENABLE:
    if (mScannerImpls.isEmpty()) {
        loge("Failed to start bgscan scan state machine because scanner impl"
                + " is null");
        return HANDLED;
    }
    // Pick any impl available and stick to it until disable.
    mScannerImpl = mScannerImpls.entrySet().iterator().next().getValue();
    mChannelHelper = mScannerImpl.getChannelHelper();

    mBackgroundScheduler = new BackgroundScanScheduler(mChannelHelper);

    WifiNative.ScanCapabilities capabilities =
            new WifiNative.ScanCapabilities();
    if (!mScannerImpl.getScanCapabilities(capabilities)) {
        loge("could not get scan capabilities");
        return HANDLED;
    }
    if (capabilities.max_scan_buckets <= 0) {
        loge("invalid max buckets in scan capabilities "
                + capabilities.max_scan_buckets);
        return HANDLED;
    }
    mBackgroundScheduler.setMaxBuckets(capabilities.max_scan_buckets);
    mBackgroundScheduler.setMaxApPerScan(capabilities.max_ap_cache_per_scan);

    Log.i(TAG, "wifi driver loaded with scan capabilities: "
            + "max buckets=" + capabilities.max_scan_buckets);

    transitionTo(mStartedState);
    return HANDLED;

WifiBackgroundScanStateMachine 中收到的 CMD_ENABLE 消息在 DefaultState 状态下被处理,然后转换到 StartedState。

//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java/WifiPnoScanStateMachine.class/DefaultState.class
case WifiScanner.CMD_ENABLE:
    if (mScannerImpls.isEmpty()) {
        loge("Failed to start pno scan state machine because scanner impl"
                + " is null");
        return HANDLED;
    }
    transitionTo(mStartedState);
    break;

WifiPnoScanStateMachine 中收到的 CMD_ENABLE 消息在 DefaultState 状态下被处理,然后转换到 StartedState。

//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java/WifiSingleScanStateMachine.class/DefaultState.class
case WifiScanner.CMD_ENABLE:
    if (mScannerImpls.isEmpty()) {
        loge("Failed to start single scan state machine because scanner impl"
                + " is null");
        return HANDLED;
    }
    transitionTo(mIdleState);
    return HANDLED;

//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java/WifiSingleScanStateMachine.class/IdleState.class
public void enter() {
    tryToStartNewScan();
}

WifiSingleScanStateMachine 中收到的 CMD_ENABLE 消息在 DefaultState 状态下被处理,然后转换到 IdleState。IdleState 状态的 enter 函数下调用 tryToStartNewScan 开始了新的扫描。

//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
void tryToStartNewScan() {
    if (mPendingScans.size() == 0) { // no pending requests
        return;
    }
    //...
}

在初次启动服务,进入 WifiSingleScanStateMachine 的 IdleState 状态的时候,应该是没有待处理的扫描请求(mPendingScans.size() == 0),所以会在最开始跳出。所以 tryToStartNewScan 在后面再详细分析。

3 启动时中周期扫描

ClientModeImpl 继承自一个 StateMachine,在构造函数中启动了该状态机,初始状态为 DisconnectedState。进入该状态时,进入到 enter 函数中。

///packages/modules/Wifi/service/java/com/android/server/wifi/ClientModeImpl.java/DisconnectedState.class
mWifiConnectivityManager.handleConnectionStateChanged(
        mClientModeManager,
        WifiConnectivityManager.WIFI_STATE_DISCONNECTED);

DisconnectedState 的 enter 函数中调用了 WifiConnectivityManager 对象的 handleConnectionStateChanged 函数来处理连接状态。

//packages/modules/Wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java
public void handleConnectionStateChanged(
        ConcreteClientModeManager clientModeManager, int state) {
    //...

    mWifiState = state;

    // Reset BSSID of last connection attempt and kick off
    // the watchdog timer if entering disconnected state.
    if (mWifiState == WIFI_STATE_DISCONNECTED) {
        scheduleWatchdogTimer();
        // Switch to the disconnected scanning schedule
        setSingleScanningSchedule(mDisconnectedSingleScanScheduleSec);
        startConnectivityScan(SCAN_IMMEDIATELY);
    } 
    //other state
}

传给 handleConnectionStateChanged 的状态是 WIFI_STATE_DISCONNECTED。首先设置看门狗定时器,看门狗定时器会在系统从休眠状态唤醒时触发,执行特定的操作(可能是为了监视连接状态并采取措施)。定时器的间隔时间由配置资源中的值定义。接着设置单个扫描计划的间隔时间。最后启动连接扫描,传入参数为 SCAN_IMMEDIATELY。

//packages/modules/Wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java
private void startConnectivityScan(boolean scanImmediately) {
    //...
    // Always stop outstanding connectivity scan if there is any
    stopConnectivityScan();

    // Don't start a connectivity scan while Wifi is in the transition
    // between connected and disconnected states.
    //...

    if (mScreenOn) {
        startPeriodicScan(scanImmediately);
    } else {
        if (mWifiState == WIFI_STATE_DISCONNECTED && !mPnoScanStarted) {
            startDisconnectedPnoScan();
        }
    }
}

如果屏幕是亮的状态,则调用 startPeriodicScan 方法开始定期扫描 WiFi 网络,同时传入 scanImmediately 参数,也就是之前传入的 SCAN_IMMEDIATELY。该参数决定是否立即开始扫描。如果屏幕是灭的状态,并且 WiFi 状态是断开的状态,并且当前没有进行 Pno 扫描,则调用startDisconnectedPnoScan方法开始断开连接时的低功耗网络扫描。

//packages/modules/Wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java
private void startPeriodicScan(boolean scanImmediately) {
    mPnoScanListener.resetLowRssiNetworkRetryDelay();
    //...
    mPeriodicSingleScanInterval = PERIODIC_SCAN_INTERVAL_MS;
    startPeriodicSingleScan();
}

设置周期扫描的周期为PERIODIC_SCAN_INTERVAL_MS (PERIODIC_SCAN_INTERVAL_MS 为20s) ,调用startPeriodicSingleScan。

//packages/modules/Wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java
private void startPeriodicSingleScan() {
    // Reaching here with scanning schedule is null means this is a false timer alarm
    //...
    boolean isScanNeeded = true;
    boolean isFullBandScan = true;

    //...
    if (isScanNeeded) {
        mLastPeriodicSingleScanTimeStamp = currentTimeStamp;

        if (mWifiState == WIFI_STATE_DISCONNECTED
                && mInitialScanState == INITIAL_SCAN_STATE_START) {
            startSingleScan(false, WIFI_WORK_SOURCE);

            // Note, initial partial scan may fail due to lack of channel history
            // Hence, we verify state before changing to AWIATING_RESPONSE
            if (mInitialScanState == INITIAL_SCAN_STATE_START) {
                setInitialScanState(INITIAL_SCAN_STATE_AWAITING_RESPONSE);
                mWifiMetrics.incrementInitialPartialScanCount();
            }
        } else {
            startSingleScan(isFullBandScan, WIFI_WORK_SOURCE);
        }
        schedulePeriodicScanTimer(
                getScheduledSingleScanIntervalMs(mCurrentSingleScanScheduleIndex));

        // Set up the next scan interval in an exponential backoff fashion.
        mCurrentSingleScanScheduleIndex++;
    } else {
        // Since we already skipped this scan, keep the same scan interval for next scan.
        schedulePeriodicScanTimer(
                getScheduledSingleScanIntervalMs(mCurrentSingleScanScheduleIndex));
    }
}

第一次打开 WiFi 时,mWifiState 为 WIFI_STATE_DISCONNECTED ,所以 isScanNeeded 和 isFullBandScan 都为true。mInitialScanState 的值根据配置文件来确定,目前为 INITIAL_SCAN_STATE_COMPLETE,所以走到 else 分支中,调用 startSingleScan。然后在启动定时器,时间到了再触发一次扫描。

接下来调用 startSingleScan -> startForcedSingleScan。

//packages/modules/Wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java
private void startForcedSingleScan(boolean isFullBandScan, WorkSource workSource) {
    mPnoScanListener.resetLowRssiNetworkRetryDelay();

    ScanSettings settings = new ScanSettings();
    if (!isFullBandScan) {
        if (!setScanChannels(settings)) {
            isFullBandScan = true;
            // Skip the initial scan since no channel history available
            setInitialScanState(INITIAL_SCAN_STATE_COMPLETE);
        } else {
            mInitialPartialScanChannelCount = settings.channels.length;
        }
    }
    settings.type = WifiScanner.SCAN_TYPE_HIGH_ACCURACY; // always do high accuracy scans.
    settings.band = getScanBand(isFullBandScan);
    // Only enable RNR for full scans since we already have a known channel list for
    // partial scan. We do not want to enable RNR for partial scan since it could end up
    // wasting time scanning for 6Ghz APs that the device doesn't have credential to.
    if (SdkLevel.isAtLeastS()) {
        settings.setRnrSetting(isFullBandScan ? WifiScanner.WIFI_RNR_ENABLED
                : WifiScanner.WIFI_RNR_NOT_NEEDED);
        settings.set6GhzPscOnlyEnabled(isFullBandScan
                ? mContext.getResources().getBoolean(R.bool.config_wifiEnable6ghzPscScanning)
                : false);
    }
    settings.reportEvents = WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT
                        | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
    settings.numBssidsPerScan = 0;
    settings.hiddenNetworks.clear();
    // retrieve the list of hidden network SSIDs from saved network to scan for
    settings.hiddenNetworks.addAll(mConfigManager.retrieveHiddenNetworkList());
    // retrieve the list of hidden network SSIDs from Network suggestion to scan for
    settings.hiddenNetworks.addAll(mWifiNetworkSuggestionsManager.retrieveHiddenNetworkList());

    SingleScanListener singleScanListener =
            new SingleScanListener(isFullBandScan);
    mScanner.startScan(
            settings, new HandlerExecutor(mEventHandler), singleScanListener, workSource);
    mWifiMetrics.incrementConnectivityOneshotScanCount();
}

首先,方法调用了mPnoScanListener.resetLowRssiNetworkRetryDelay(),重置低信号强度网络的重试延迟。然后创建了一个ScanSettings对象,并根据isFullBandScan是否为true来设置扫描通道。如果不进行全频段扫描,则调用setScanChannels方法来设置扫描通道,如果设置失败,则将isFullBandScan设置为true,并将初始扫描状态设置为COMPLETE。如果设置成功,则记录初始部分扫描的通道数量。然后,将扫描类型设置为高准确度,并根据isFullBandScan来设置扫描的频段。对于全频段扫描,设置RNR(Restricted Neighbor Report)为启用,同时设置6GHz PSC(Primary Channel Setting)只针对全频段扫描进行启用。接下来,设置报告事件的类型为完整扫描结果和每次扫描后的事件。然后,设置每次扫描的BSSID数量为0,并清除隐藏网络的列表。最后,从保存的网络和网络建议中检索隐藏网络的列表,并添加到隐藏网络的列表中。创建一个 SingleScanListener 对象,并开始扫描。

//packages/modules/Wifi/framework/java/android/net/wifi/WifiScanner.java
public void startScan(ScanSettings settings, @Nullable @CallbackExecutor Executor executor,
        ScanListener listener, WorkSource workSource) {
    Objects.requireNonNull(listener, "listener cannot be null");
    int key = addListener(listener, executor);
    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);
    scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
    scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
    mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
}

//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java/ClientHandler.class
case WifiScanner.CMD_START_SINGLE_SCAN:
    mSingleScanStateMachine.sendMessage(Message.obtain(msg));
    break;

通过 AsyncChannel 发送一个 CMD_START_SINGLE_SCAN 消息,WifiScanningServiceImpl 中的 ClientHandler 收到这个消息以后,将消息转发到 WifiSingleScanStateMachine 中,由它来处理。

//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java/WifiSingleScanStateMachine.class/DefaultState.class
case WifiScanner.CMD_START_SINGLE_SCAN:
    handleScanStartMessage(ci, msg);
    return HANDLED;
   
//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java/WifiSingleScanStateMachine.class
private void handleScanStartMessage(ClientInfo ci, Message msg) {
    int handler = msg.arg2;
    Bundle scanParams = (Bundle) msg.obj;
    if (scanParams == null) {
        logCallback("singleScanInvalidRequest",  ci, handler, "null params");
        replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "params null");
        return;
    }
    ScanSettings scanSettings = null;
    WorkSource workSource = null;
    try {
        scanSettings =
                scanParams.getParcelable(
                        WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY);
        workSource =
                scanParams.getParcelable(
                        WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY);
    } catch (BadParcelableException e) {
        Log.wtf(TAG, "Failed to get parcelable params", e);
        logCallback("singleScanInvalidRequest",  ci, handler,
                "bad parcel params");
        replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST,
                "bad parcel params");
        return;
    }
    if (validateScanRequest(ci, handler, scanSettings)) {
        /

        if (getCurrentState() == mScanningState) {
            // If there is an active scan that will fulfill the scan request then
            // mark this request as an active scan, otherwise mark it pending.
            if (activeScanSatisfies(scanSettings)) {
                mActiveScans.addRequest(ci, handler, workSource, scanSettings);
            } else {
                mPendingScans.addRequest(ci, handler, workSource, scanSettings);
            }
        } else if (getCurrentState() == mIdleState) {
            // If were not currently scanning then try to start a scan. Otherwise
            // this scan will be scheduled when transitioning back to IdleState
            // after finishing the current scan.
            mPendingScans.addRequest(ci, handler, workSource, scanSettings);
            tryToStartNewScan();
        } else if (getCurrentState() == mDefaultState) {
            // If scanning is disabled and the request is for emergency purposes
            // (checked above), add to pending list. this scan will be scheduled when
            // transitioning to IdleState when wifi manager enables scanning as a part of
            // processing WifiManager.setEmergencyScanRequestInProgress(true)
            mPendingScans.addRequest(ci, handler, workSource, scanSettings);
        }
    } else {
        logCallback("singleScanInvalidRequest",  ci, handler, "bad request");
        replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
        mWifiMetrics.incrementScanReturnEntry(
                WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION, 1);
    }
}

从消息中获取 Handler 和扫描参数 scanParams,并尝试从 scanParams 中获取 scanSettings 和 workSource。验证扫描请求的有效性。如果有效,则继续处理;否则,记录回调日志,回复消息,返回,并增加扫描失败指标。

  • 如果当前状态为 ScanningState,则根据活动扫描是否能满足扫描请求来将请求标记为活动扫描或挂起扫描。
  • 如果当前状态为 IdleState,将请求添加到挂起扫描列表,并调用 tryToStartNewScan 尝试启动新的扫描。
  • 如果当前状态为 DefaultState,并且扫描是为紧急目的(在上面检查过),将请求添加到挂起扫描列表。
//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
void tryToStartNewScan() {
    if (mPendingScans.size() == 0) { // no pending requests
        return;
    }
    mChannelHelper.updateChannels();
    // TODO move merging logic to a scheduler
    WifiNative.ScanSettings settings = new WifiNative.ScanSettings();
    settings.num_buckets = 1;
    WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings();
    bucketSettings.bucket = 0;
    bucketSettings.period_ms = 0;
    bucketSettings.report_events = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;

    ChannelCollection channels = mChannelHelper.createChannelCollection();
    List<WifiNative.HiddenNetwork> hiddenNetworkList = new ArrayList<>();
    for (RequestInfo<ScanSettings> entry : mPendingScans) {
        settings.scanType = mergeScanTypes(settings.scanType, entry.settings.type);
        settings.enable6GhzRnr = mergeRnrSetting(settings.enable6GhzRnr, entry.settings);
        channels.addChannels(entry.settings);
        for (ScanSettings.HiddenNetwork srcNetwork : entry.settings.hiddenNetworks) {
            WifiNative.HiddenNetwork hiddenNetwork = new WifiNative.HiddenNetwork();
            hiddenNetwork.ssid = srcNetwork.ssid;
            hiddenNetworkList.add(hiddenNetwork);
        }
        if ((entry.settings.reportEvents & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)
                != 0) {
            bucketSettings.report_events |= WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
        }

        if (entry.clientInfo != null) {
            mWifiMetrics.getScanMetrics().setClientUid(entry.clientInfo.mUid);
        }
        mWifiMetrics.getScanMetrics().setWorkSource(entry.workSource);
    }

    if (hiddenNetworkList.size() > 0) {
        settings.hiddenNetworks = new WifiNative.HiddenNetwork[hiddenNetworkList.size()];
        int numHiddenNetworks = 0;
        for (WifiNative.HiddenNetwork hiddenNetwork : hiddenNetworkList) {
            settings.hiddenNetworks[numHiddenNetworks++] = hiddenNetwork;
        }
    }

    channels.fillBucketSettings(bucketSettings, Integer.MAX_VALUE);
    settings.buckets = new WifiNative.BucketSettings[] {bucketSettings};

    if (mScannerImplsTracker.startSingleScan(settings)) {
        mWifiMetrics.getScanMetrics().logScanStarted(
                WifiMetrics.ScanMetrics.SCAN_TYPE_SINGLE);

        // store the active scan settings
        mActiveScanSettings = settings;
        // swap pending and active scan requests
        RequestList<ScanSettings> tmp = mActiveScans;
        mActiveScans = mPendingScans;
        mPendingScans = tmp;
        // make sure that the pending list is clear
        mPendingScans.clear();
        transitionTo(mScanningState);
    } else {
        mWifiMetrics.incrementScanReturnEntry(
                WifiMetricsProto.WifiLog.SCAN_UNKNOWN, mPendingScans.size());
        mWifiMetrics.getScanMetrics().logScanFailedToStart(
                WifiMetrics.ScanMetrics.SCAN_TYPE_SINGLE);

        // notify and cancel failed scans 
        sendOpFailedToAllAndClear(mPendingScans, WifiScanner.REASON_UNSPECIFIED,
                "Failed to start single scan");
    }
}

检查是否有待处理的扫描请求,如果没有,则直接返回。调用 ChannelHelper 的 updateChannels 方法,更新通道信息。创建 ScanSettings 对象,并设置扫描的配置参数,包括扫描的 bucket、周期、报告事件等。使用 ChannelHelper 创建 ChannelCollection。创建 hiddenNetworkList 列表,用于存储扫描请求中的隐藏网络信息。遍历 PendingScans 列表中的每个请求,将相关的扫描设置合并到 settings 对象中,并将对应的 settings 添加到 channels 中。同时,将隐藏网络的相关信息添加到 hiddenNetworkList 中。根据扫描请求中的报告事件类型,更新bucketSettings 中的报告事件设置。如果扫描请求关联了客户端信息,将客户端 UID 设置到扫描指标中。如果存在隐藏网络列表,将其转换为数组,并设置到 settings 对象的 hiddenNetworks 成员中。使用 channels 填充 bucketSettings,并将其设置为 settings 的 buckets 成员的唯一元素。调用 ScannerImplsTracker 的 startSingleScan 方法启动单次扫描操作,并且根据结果设置相应的记录,然后转换到 ScanningState 状态。

//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java/WifiSingleScanStateMachine.class/ScannerImplsTracker.class
public boolean startSingleScan(WifiNative.ScanSettings scanSettings) {
    mStatusPerImpl.clear();
    boolean anySuccess = false;
    for (Map.Entry<String, WifiScannerImpl> entry : mScannerImpls.entrySet()) {
        String ifaceName = entry.getKey();
        WifiScannerImpl impl = entry.getValue();
        boolean success = impl.startSingleScan(
                scanSettings, new ScanEventHandler(ifaceName));
        if (!success) {
            Log.e(TAG, "Failed to start single scan on " + ifaceName);
            mStatusPerImpl.put(ifaceName, STATUS_FAILED);
            continue;
        }
        mStatusPerImpl.put(ifaceName, STATUS_PENDING);
        anySuccess = true;
    }
    return anySuccess;
}

mScannerImpls 中的成员都是 WificondScannerImpl 或者 HalWifiScannerImpl 对象,这两个对象都调用到 WificondScannerImpl 中的 startSingleScan 函数。

//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
public boolean startSingleScan(WifiNative.ScanSettings settings,
        WifiNative.ScanEventHandler eventHandler) {
    if (eventHandler == null || settings == null) {
        Log.w(TAG, "Invalid arguments for startSingleScan: settings=" + settings
                + ",eventHandler=" + eventHandler);
        return false;
    }
    synchronized (mSettingsLock) {
        if (mLastScanSettings != null) {
            Log.w(TAG, "A single scan is already running");
            return false;
        }

        ChannelCollection allFreqs = mChannelHelper.createChannelCollection();
        boolean reportFullResults = false;

        for (int i = 0; i < settings.num_buckets; ++i) {
            WifiNative.BucketSettings bucketSettings = settings.buckets[i];
            if ((bucketSettings.report_events
                            & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
                reportFullResults = true;
            }
            allFreqs.addChannels(bucketSettings);
        }

        List<String> hiddenNetworkSSIDSet = new ArrayList<>();
        if (settings.hiddenNetworks != null) {
            int numHiddenNetworks =
                    Math.min(settings.hiddenNetworks.length, MAX_HIDDEN_NETWORK_IDS_PER_SCAN);
            for (int i = 0; i < numHiddenNetworks; i++) {
                hiddenNetworkSSIDSet.add(settings.hiddenNetworks[i].ssid);
            }
        }
        mLastScanSettings = new LastScanSettings(
                mClock.getElapsedSinceBootNanos(),
                reportFullResults, allFreqs, eventHandler);

        boolean success = false;
        Set<Integer> freqs = Collections.emptySet();
        if (!allFreqs.isEmpty()) {
            freqs = allFreqs.getScanFreqs();
            success = mWifiNative.scan(
                    getIfaceName(), settings.scanType, freqs, hiddenNetworkSSIDSet,
                    settings.enable6GhzRnr);
            if (!success) {
                Log.e(TAG, "Failed to start scan, freqs=" + freqs);
            }
        } else {
            // There is a scan request but no available channels could be scanned for.
            // We regard it as a scan failure in this case.
            Log.e(TAG, "Failed to start scan because there is no available channel to scan" + getIfaceName());
        }
        if (success) {
            if (DBG) {
                Log.d(TAG, "Starting wifi scan for freqs=" + freqs
                        + " on iface " + getIfaceName());
            }

            mScanTimeoutListener = new AlarmManager.OnAlarmListener() {
                @Override public void onAlarm() {
                    handleScanTimeout();
                }
            };

            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                    mClock.getElapsedSinceBootMillis() + SCAN_TIMEOUT_MS,
                    TIMEOUT_ALARM_TAG, mScanTimeoutListener, mEventHandler);
        } else {
            // indicate scan failure async
            mEventHandler.post(() -> reportScanFailure());
        }

        return true;
    }
}

这段代码的核心在于如下两个分支:

如果 allFreqs 不为空,则获取所有要扫描的频率集合 freqs,调用 WifiNative.scan 方法开始扫描,并将扫描结果的状态保存在 success 变量中。

//packages/modules/Wifi/service/java/android/server/wifi/WifiNative.java
public void onScan(ArrayList<WifiAPInfo> apInfos) throws RemoteException {
    Log.d(TAG, "scan Result");

    isScanning = false;
    synchronized(mScanList){
        int size = apInfos.size();
        mScanList.clear();
        for (int i = 0; i < size; i++) {
            Log.d(TAG, "apInfo.bssid = " + apInfos.get(i).bssid.toLowerCase() + ", Tether.bssid = " + mWifiMonitor.getBssid().toString());
            if(apInfos.get(i).bssid.toLowerCase().equals(mWifiMonitor.getBssid().toString())) {
                Log.d(TAG, "skip");
                continue;
            }
            mScanList.add(apInfoToScanResult(apInfos.get(i)));
        }
    }

    mScanEventHandlers.get("sawlan").OnScanResultReady();
}

//packages/modules/Wifi/service/java/android/server/wifi/WifiNative.java/NormalScanEventCallback.class
public void onScanResultReady() {
    Log.d(TAG, "send onScanResultReady " + mIfaceName);
    mWifiMonitor.broadcastScanResultEvent(mIfaceName);
}

//packages/modules/Wifi/service/java/android/server/wifi/WifiMonitor.java
public void broadcastScanResultEvent(String iface) {
    sendMessage(iface, SCAN_RESULTS_EVENT);
}

保存扫描结果,然后回调到 ScanEventHandlers -> NormalScanEventCallback的 OnScanResultReady 方法。OnScanResultReady 通过 WifiMonitor 发送一个广播,通知其注册的所有事件 Handler,扫描结果已经准备好。这个广播实际上是对其注册的所有事件 Handler 发送一个 SCAN_RESULTS_EVENT 事件。

//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
wifiMonitor.registerHandler(getIfaceName(),
        WifiMonitor.SCAN_RESULTS_EVENT, mEventHandler);

//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
case WifiMonitor.SCAN_RESULTS_EVENT:
    cancelScanTimeout();
    pollLatestScanData();
    break;

早先 WificondScannerImpl 注册过 SCAN_RESULTS_EVENT 的 Handler。收到这个事件消息以后调用 cancelScanTimeout 和 pollLatestScanData 来处理。已获取到扫描结果,所以cancelScanTimeout 取消扫描超时定时器。

//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
private void pollLatestScanData() {
    synchronized (mSettingsLock) {
        Log.d(TAG, "entry pollLatestScanData");
        if (mLastScanSettings == null) {
             // got a scan before we started scanning or after scan was canceled
            return;
        }
        boolean notcheckfreq;
        if (getIfaceName().equals("sawlan")){
            notcheckfreq = true;
            mNativeScanResults = mWifiNative.getScanResults(getIfaceName());
        }
        else{
            notcheckfreq = false;
            mNativeScanResults = mWifiNative.getScanResults(getIfaceName());
        }
        List<ScanResult> singleScanResults = new ArrayList<>();
        int numFilteredScanResults = 0;
        for (int i = 0; i < mNativeScanResults.size(); ++i) {
            ScanResult result = mNativeScanResults.get(i).getScanResult();
            // nanoseconds -> microseconds
            if (result.timestamp >= mLastScanSettings.startTimeNanos / 1_000) {
                if (notcheckfreq || mLastScanSettings.singleScanFreqs.containsChannel(
                                result.frequency)) {
                    singleScanResults.add(result);
                }
            } else {
                numFilteredScanResults++;
            }
        }
        if (numFilteredScanResults != 0) {
            Log.d(TAG, "Filtering out " + numFilteredScanResults + " scan results.");
        }

        if (mLastScanSettings.singleScanEventHandler != null) {
            if (mLastScanSettings.reportSingleScanFullResults) {
                for (ScanResult scanResult : singleScanResults) {
                    // ignore buckets scanned since there is only one bucket for a single scan
                    mLastScanSettings.singleScanEventHandler.onFullScanResult(scanResult,
                            /* bucketsScanned */ 0);
                }
            }
            Collections.sort(singleScanResults, SCAN_RESULT_SORT_COMPARATOR);
            mLatestSingleScanResult = new WifiScanner.ScanData(0, 0, 0,
                    getScannedBandsInternal(mLastScanSettings.singleScanFreqs),
                    singleScanResults.toArray(new ScanResult[singleScanResults.size()]));
            mLastScanSettings.singleScanEventHandler
                    .onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
        }

        mLastScanSettings = null;
    }
}

pollLatestScanData 中首先从 WifiNative中获取扫描结果,接着对其进行一些处理过滤,获取有用的结果,然后 回调到 ScanEventHandler 的 onScanStatus 方法。

//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java/WifiSingleScanStateMachine.class/ScannerImplsTracker.class/ScanEventHandler.class
public void onScanStatus(int event) {
    if (DBG) {
        localLog("onScanStatus event received, event=" + event
                + ", iface=" + mImplIfaceName);
    }
    switch (event) {
        case WifiNative.WIFI_SCAN_RESULTS_AVAILABLE:
        case WifiNative.WIFI_SCAN_THRESHOLD_NUM_SCANS:
        case WifiNative.WIFI_SCAN_THRESHOLD_PERCENT:
            reportScanStatusForImpl(mImplIfaceName, STATUS_SUCCEEDED);
            break;
        case WifiNative.WIFI_SCAN_FAILED:
            reportScanStatusForImpl(mImplIfaceName, STATUS_FAILED);
            break;
        default:
            Log.e(TAG, "Unknown scan status event: " + event);
            break;
    }
}

//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java/WifiSingleScanStateMachine.class/ScannerImplsTracker.class
private void reportScanStatusForImpl(@NonNull String implIfaceName, int newStatus) {
    Integer currentStatus = mStatusPerImpl.get(implIfaceName);
    if (currentStatus != null && currentStatus == STATUS_PENDING) {
        mStatusPerImpl.put(implIfaceName, newStatus);
    }
    // Now check if all the scanner impls scan status is available.
    int consolidatedStatus = getConsolidatedStatus();
    if (consolidatedStatus == STATUS_SUCCEEDED) {
        sendMessage(CMD_SCAN_RESULTS_AVAILABLE);
    } else if (consolidatedStatus == STATUS_FAILED) {
        sendMessage(CMD_SCAN_FAILED);
    }
}

WifiSingleScanStateMachine 状态机中收到这个消息,继续报告扫描结果,向自己发送一个 CMD_SCAN_RESULTS_AVAILABLE 消息。在 ScanningState 状态中处理这个消息。

//packages/modules/Wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java/WifiSingleScanStateMachine.class/ScanningState.class
case CMD_SCAN_RESULTS_AVAILABLE:
    ScanData latestScanResults =
            mScannerImplsTracker.getLatestSingleScanResults();
    if (latestScanResults != null) {
        handleScanResults(latestScanResults);
    } else {
        Log.e(TAG, "latest scan results null unexpectedly");
    }
    transitionTo(mIdleState);
    return HANDLED;

调用 handleScanResults 处理,然后继续转回 IdleState 状态。

handleScanResults -> reportScanResults -> reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableResultsToDeliver)。

WifiScanner 收到这个消息发送给 AllSingleScanListener,然后回调到 onResults,其中调用了 handleScanResults。然后接下来就是 Wifi 连接中的流程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值