Android13 WifiService startScan流程

首先看WifiServiceImpl的startScan方法:

//packages/modules/Wifi/service/java/com/android/server/wifi/WifiServiceImpl.java
public class WifiServiceImpl extends BaseWifiService {
    private final ScanRequestProxy mScanRequestProxy;
    private final WifiPermissionsUtil mWifiPermissionsUtil;
    public boolean startScan(String packageName, String featureId) {
        if (enforceChangePermission(packageName) != MODE_ALLOWED) {
            return false;
        }
        int callingUid = Binder.getCallingUid();
        mWifiPermissionsUtil.checkPackage(callingUid, packageName);


        long ident = Binder.clearCallingIdentity();
        mLog.info("startScan uid=%").c(callingUid).flush();
        synchronized (this) {
            if (mInIdleMode) {
                // Need to send an immediate scan result broadcast in case the
                // caller is waiting for a result ..


                // TODO: investigate if the logic to cancel scans when idle can move to
                // WifiScanningServiceImpl.  This will 1 - clean up WifiServiceImpl and 2 -
                // avoid plumbing an awkward path to report a cancelled/failed scan.  This will
                // be sent directly until b/31398592 is fixed.
                sendFailedScanBroadcast();
                mScanPending = true;
                return false;
            }
        }
        try {
            mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, featureId, callingUid,
                    null); //用于确定调用方是否有权获取扫描结果的 API。如果调用方没有权限,则引发安全异常。
            Boolean scanSuccess = mWifiThreadRunner.call(() ->
                    mScanRequestProxy.startScan(callingUid, packageName), null); //调用ScanRequestProxy的startScan方法
            if (scanSuccess == null) {
                sendFailedScanBroadcast();
                return false;
            }
            if (!scanSuccess) {
                Log.e(TAG, "Failed to start scan");
                return false;
            }
        } catch (SecurityException e) {
            Log.w(TAG, "Permission violation - startScan not allowed for"
                    + " uid=" + callingUid + ", packageName=" + packageName + ", reason=" + e);
            return false;
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
        return true;
    }
}

调用ScanRequestProxy的startScan方法:

//packages/modules/Wifi/service/java/com/android/server/wifi/ScanRequestProxy.java
public class ScanRequestProxy {
    private WifiScanner mWifiScanner;
    public boolean startScan(int callingUid, String packageName) {
        if (!mScanningEnabled || !retrieveWifiScannerIfNecessary()) {
            Log.e(TAG, "Failed to retrieve wifiscanner");
            sendScanResultFailureBroadcastToPackage(packageName);
            return false;
        }
        boolean fromSettingsOrSetupWizard =
                mWifiPermissionsUtil.checkNetworkSettingsPermission(callingUid)
                        || mWifiPermissionsUtil.checkNetworkSetupWizardPermission(callingUid);
        // Check and throttle scan request unless,
        // a) App has either NETWORK_SETTINGS or NETWORK_SETUP_WIZARD permission.
        // b) Throttling has been disabled by user.
        int packageImportance = getPackageImportance(callingUid, packageName);
        if (!fromSettingsOrSetupWizard && mThrottleEnabled
                && shouldScanRequestBeThrottledForApp(callingUid, packageName, packageImportance)) {
            Log.i(TAG, "Scan request from " + packageName + " throttled");
            sendScanResultFailureBroadcastToPackage(packageName);
            return false;
        }
        // Create a worksource using the caller's UID.
        WorkSource workSource = new WorkSource(callingUid, packageName);
        mWifiMetrics.getScanMetrics().setWorkSource(workSource);
        mWifiMetrics.getScanMetrics().setImportance(packageImportance);


        // 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.SCAN_TYPE_HIGH_ACCURACY;
        } else {
            if (SdkLevel.isAtLeastS()) {
                // since the scan request is from a normal app, do not scan all 6Ghz channels.
                settings.set6GhzPscOnlyEnabled(true);
            }
        }
        settings.band = WifiScanner.WIFI_BAND_ALL;
        settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
                | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
        if (mScanningForHiddenNetworksEnabled) {
            settings.hiddenNetworks.clear();
            // retrieve the list of hidden network SSIDs from saved network to scan for, if enabled.
            settings.hiddenNetworks.addAll(mWifiConfigManager.retrieveHiddenNetworkList(false));
            // retrieve the list of hidden network SSIDs from Network suggestion to scan for.
            settings.hiddenNetworks.addAll(
                    mWifiInjector.getWifiNetworkSuggestionsManager()
                    .retrieveHiddenNetworkList(false));
        }
        mWifiScanner.startScan(settings, new HandlerExecutor(mHandler),
                new ScanRequestProxyScanListener(), workSource); //调用WifiScanner的startScan方法,new一个监听器并作为参数传递,以便HAL层返回扫描结果
        return true;
    }
}

调用WifiScanner的startScan方法:

//packages/modules/Wifi/framework/java/android/net/wifi/WifiScanner.java
public class WifiScanner {
    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
    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); //将侦听器添加到侦听器map中
        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); //发送CMD_START_SINGLE_SCAN消息
    }
}

发送的消息由WifiScanningServiceImpl内部类ClientHandler的handleMessage方法处理:

//packages/modules/Wifi/framework/java/android/net/wifi/scanner/WifiScanningServiceImpl.java
public class WifiScanningServiceImpl extends IWifiScanner.Stub {
    private WifiSingleScanStateMachine mSingleScanStateMachine;
    private class ClientHandler extends Handler {


        ClientHandler(String tag, Looper looper) {
            super(looper);
        }


        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
                    if (msg.replyTo == null) {
                        logw("msg.replyTo is null");
                        return;
                    }
                    ExternalClientInfo client = (ExternalClientInfo) mClients.get(msg.replyTo);
                    if (client != null) {
                        logw("duplicate client connection: " + msg.sendingUid + ", messenger="
                                + msg.replyTo);
                        client.mChannel.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
                                AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED);
                        return;
                    }


                    AsyncChannel ac = new AsyncChannel();
                    ac.connected(mContext, this, msg.replyTo);


                    client = new ExternalClientInfo(msg.sendingUid, msg.replyTo, ac);
                    client.register();


                    ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
                            AsyncChannel.STATUS_SUCCESSFUL);
                    localLog("client connected: " + client);
                    return;
                }
                case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
                    ExternalClientInfo client = (ExternalClientInfo) mClients.get(msg.replyTo);
                    if (client != null) {
                        client.mChannel.disconnect();
                    }
                    return;
                }
                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
                    ExternalClientInfo client = (ExternalClientInfo) mClients.get(msg.replyTo);
                    if (client != null && msg.arg1 != AsyncChannel.STATUS_SEND_UNSUCCESSFUL
                            && msg.arg1
                            != AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED) {
                        localLog("client disconnected: " + client + ", reason: " + msg.arg1);
                        client.cleanup();
                    }
                    return;
                }
            }


            try {
                enforcePermission(msg.sendingUid, msg);
            } catch (SecurityException e) {
                localLog("failed to authorize app: " + e);
                replyFailed(msg, WifiScanner.REASON_NOT_AUTHORIZED, "Not authorized");
                return;
            }


            // Since the CMD_GET_SCAN_RESULTS and CMD_GET_SINGLE_SCAN_RESULTS messages are
            // sent from WifiScanner using |sendMessageSynchronously|, handle separately since
            // the |msg.replyTo| field does not actually correspond to the Messenger that is
            // registered for that client.
            if (msg.what == WifiScanner.CMD_GET_SCAN_RESULTS) {
                mBackgroundScanStateMachine.sendMessage(Message.obtain(msg));
                return;
            }
            if (msg.what == WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS) {
                mSingleScanStateMachine.sendMessage(Message.obtain(msg));
                return;
            }


            ClientInfo ci = mClients.get(msg.replyTo);
            if (ci == null) {
                loge("Could not find client info for message " + msg.replyTo + ", msg=" + msg);
                replyFailed(msg, WifiScanner.REASON_INVALID_LISTENER, "Could not find listener");
                return;
            }


            switch (msg.what) {
                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(WifiManager.API_SCANNING_ENABLED, msg.arg1,
                            msg.sendingUid, msg.arg2, (String) msg.obj, true);
                    break;
                case WifiScanner.CMD_DISABLE:
                    Log.i(TAG, "Received a request to disable scanning, UID = " + msg.sendingUid);
                    teardownScannerImpls();
                    mBackgroundScanStateMachine.sendMessage(Message.obtain(msg));
                    mSingleScanStateMachine.sendMessage(Message.obtain(msg));
                    mPnoScanStateMachine.sendMessage(Message.obtain(msg));
                    mLastCallerInfoManager.put(WifiManager.API_SCANNING_ENABLED, msg.arg1,
                            msg.sendingUid, msg.arg2, (String) msg.obj, false);
                    break;
                case WifiScanner.CMD_START_BACKGROUND_SCAN:
                case WifiScanner.CMD_STOP_BACKGROUND_SCAN:
                    mBackgroundScanStateMachine.sendMessage(Message.obtain(msg));
                    break;
                case WifiScanner.CMD_START_PNO_SCAN:
                case WifiScanner.CMD_STOP_PNO_SCAN:
                    mPnoScanStateMachine.sendMessage(Message.obtain(msg));
                    break;
                case WifiScanner.CMD_START_SINGLE_SCAN:
                case WifiScanner.CMD_STOP_SINGLE_SCAN:
                    mSingleScanStateMachine.sendMessage(Message.obtain(msg)); //调用WifiSingleScanStateMachine的sendMessage方法发送CMD_START_SINGLE_SCAN消息
                    break;
                case WifiScanner.CMD_REGISTER_SCAN_LISTENER:
                    logScanRequest("registerScanListener", ci, msg.arg2, null, null, null);
                    mSingleScanListeners.addRequest(ci, msg.arg2, null, null);
                    replySucceeded(msg);
                    break;
                case WifiScanner.CMD_DEREGISTER_SCAN_LISTENER:
                    logScanRequest("deregisterScanListener", ci, msg.arg2, null, null, null);
                    mSingleScanListeners.removeRequest(ci, msg.arg2);
                    break;
                default:
                    replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "Invalid request");
                    break;
            }
        }
    }
}

发给内部状态机WifiSingleScanStateMachine进行处理:

//packages/modules/Wifi/framework/java/android/net/wifi/scanner/WifiScanningServiceImpl.java
public class WifiScanningServiceImpl extends IWifiScanner.Stub {
    class WifiSingleScanStateMachine extends StateMachine {
        class DefaultState extends State {
            @Override
            public void enter() {
                mActiveScans.clear();
                mPendingScans.clear();
            }
            @Override
            public boolean processMessage(Message msg) {
                ClientInfo ci = mClients.get(msg.replyTo);


                switch (msg.what) {
                    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;
                    case WifiScanner.CMD_DISABLE:
                        transitionTo(mDefaultState);
                        return HANDLED;
                    case WifiScanner.CMD_START_SINGLE_SCAN:
                        handleScanStartMessage(ci, msg);
                        return HANDLED;
                    case WifiScanner.CMD_STOP_SINGLE_SCAN:
                        removeSingleScanRequest(ci, msg.arg2);
                        return HANDLED;
                    case CMD_SCAN_RESULTS_AVAILABLE:
                        if (DBG) localLog("ignored scan results available event");
                        return HANDLED;
                    case CMD_FULL_SCAN_RESULTS:
                        if (DBG) localLog("ignored full scan result event");
                        return HANDLED;
                    case WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS:
                        msg.obj = new WifiScanner.ParcelableScanResults(
                            filterCachedScanResultsByAge());
                        replySucceeded(msg);
                        return HANDLED;
                    default:
                        return NOT_HANDLED;
                }
            }


            /**
             * Filter out  any scan results that are older than
             * {@link #CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS}.
             *
             * @return Filtered list of scan results.
             */
            private ScanResult[] filterCachedScanResultsByAge() {
                // Using ScanResult.timestamp here to ensure that we use the same fields as
                // WificondScannerImpl for filtering stale results.
                long currentTimeInMillis = mClock.getElapsedSinceBootMillis();
                return mCachedScanResults.stream()
                        .filter(scanResult
                                -> ((currentTimeInMillis - (scanResult.timestamp / 1000))
                                        < CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS))
                        .toArray(ScanResult[]::new);
            }
        }
    }
}

由状态机WifiSingleScanStateMachine的handleScanStartMessage方法处理:

//packages/modules/Wifi/framework/java/android/net/wifi/scanner/WifiScanningServiceImpl.java
public class WifiScanningServiceImpl extends IWifiScanner.Stub {
    class WifiSingleScanStateMachine extends StateMachine {
        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() == mDefaultState && !scanSettings.ignoreLocationSettings) {
                    // Reject regular scan requests if scanning is disabled.
                    replyFailed(msg, WifiScanner.REASON_UNSPECIFIED, "not available");
                    return;
                }
                mWifiMetrics.incrementOneshotScanCount();
                if ((scanSettings.band & WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY) != 0) {
                    mWifiMetrics.incrementOneshotScanWithDfsCount();
                }
                logScanRequest("addSingleScanRequest", ci, handler, workSource,
                        scanSettings, null);
                replySucceeded(msg);


                if (scanSettings.ignoreLocationSettings) {
                    // Inform wifi manager that an emergency scan is in progress (regardless of
                    // whether scanning is currently enabled or not). This ensures that
                    // the wifi chip remains on for the duration of this scan.
                    mWifiManager.setEmergencyScanRequestInProgress(true);
                }


                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(); //如果是Idle状态,调用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);
            }
        }
    }
}

如果是Idle状态,调用tryToStartNewScan方法:

//packages/modules/Wifi/framework/java/android/net/wifi/scanner/WifiScanningServiceImpl.java
public class WifiScanningServiceImpl extends IWifiScanner.Stub {
    class WifiSingleScanStateMachine extends StateMachine {
        private final ScannerImplsTracker mScannerImplsTracker;
        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();
            WifiScanner.ChannelSpec[][] available6GhzChannels =
                    mChannelHelper.getAvailableScanChannels(WifiScanner.WIFI_BAND_6_GHZ);
            boolean are6GhzChannelsAvailable = available6GhzChannels.length > 0
                    && available6GhzChannels[0].length > 0;
            List<WifiNative.HiddenNetwork> hiddenNetworkList = new ArrayList<>();
            for (RequestInfo<ScanSettings> entry : mPendingScans) {
                settings.scanType = mergeScanTypes(settings.scanType, entry.settings.type);
                if (are6GhzChannelsAvailable) {
                    settings.enable6GhzRnr = mergeRnrSetting(
                            settings.enable6GhzRnr, entry.settings);
                } else {
                    settings.enable6GhzRnr = false;
                }
                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");
            }
        }
}

调用ScannerImplsTracker的startSingleScan方法:

//packages/modules/Wifi/framework/java/android/net/wifi/scanner/WifiScanningServiceImpl.java
public class WifiScanningServiceImpl extends IWifiScanner.Stub {
    class WifiSingleScanStateMachine extends StateMachine {
        private final class ScannerImplsTracker {
            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)); //调用WifiScannerImpl的startSingleScan方法
                    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;
            }
        }
    }
}

调用WifiScannerImpl的startSingleScan方法,WifiScannerImpl是一个抽象类,其具体实现为HalWifiScannerImpl,因此会调用HalWifiScannerImpl的startSingleScan方法:

//packages/modules/Wifi/framework/java/android/net/wifi/scanner/HalWifiScannerImpl.java
/**
 * WifiScanner implementation that takes advantage of the gscan HAL API
 * The gscan API is used to perform background scans and wificond is used for oneshot scans.
 * @see com.android.server.wifi.scanner.WifiScannerImpl for more details on each method.
 */
public class HalWifiScannerImpl extends WifiScannerImpl implements Handler.Callback {
    private final WificondScannerImpl mWificondScannerDelegate;
    public boolean startSingleScan(WifiNative.ScanSettings settings,
            WifiNative.ScanEventHandler eventHandler) {
        return mWificondScannerDelegate.startSingleScan(settings, eventHandler); 
    }
}

调用WificondScannerImpl的startSingleScan方法:

//packages/modules/Wifi/framework/java/android/net/wifi/scanner/WificondScannerImpl.java
/**
 * Implementation of the WifiScanner HAL API that uses wificond to perform all scans
 * @see com.android.server.wifi.scanner.WifiScannerImpl for more details on each method.
 */
public class WificondScannerImpl extends WifiScannerImpl implements Handler.Callback { 
    private final WifiNative mWifiNative;
    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) {
                boolean executeRoundRobin = true;
                int maxNumScanSsids = mMaxNumScanSsids;
                if (maxNumScanSsids <= 0) {
                    // Subtract 1 to account for the wildcard/broadcast probe request that
                    // wificond adds to the scan set.
                    mMaxNumScanSsids = mWifiNative.getMaxSsidsPerScan(getIfaceName()) - 1;
                    if (mMaxNumScanSsids > 0) {
                        maxNumScanSsids = mMaxNumScanSsids;
                    } else {
                        maxNumScanSsids = DEFAULT_NUM_HIDDEN_NETWORK_IDS_PER_SCAN;
                        executeRoundRobin = false;
                    }
                }
                int numHiddenNetworksPerScan =
                        Math.min(settings.hiddenNetworks.length, maxNumScanSsids);
                if (numHiddenNetworksPerScan == settings.hiddenNetworks.length
                        || mNextHiddenNetworkScanId >= settings.hiddenNetworks.length
                        || !executeRoundRobin) {
                    mNextHiddenNetworkScanId = 0;
                }
                if (DBG) {
                    Log.d(TAG, "Scanning for " + numHiddenNetworksPerScan + " out of "
                            + settings.hiddenNetworks.length + " total hidden networks");
                    Log.d(TAG, "Scan hidden networks starting at id=" + mNextHiddenNetworkScanId);
                }


                int id = mNextHiddenNetworkScanId;
                for (int i = 0; i < numHiddenNetworksPerScan; i++, id++) {
                    hiddenNetworkSSIDSet.add(
                            settings.hiddenNetworks[id % settings.hiddenNetworks.length].ssid);
                }
                mNextHiddenNetworkScanId = id % settings.hiddenNetworks.length;
            }
            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); //调用WifiNative的scan方法
                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");
            }
            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;
        }
    }
}

 调用WifiNative的scan方法:

//packages/modules/Wifi/service/java/com/android/server/wifi/WifiNative.java
/**
 * Native calls for bring up/shut down of the supplicant daemon and for
 * sending requests to the supplicant daemon
 *
 * {@hide}
 */
public class WifiNative {
    private final WifiNl80211Manager mWifiCondManager;
    public boolean scan(
            @NonNull String ifaceName, @WifiAnnotations.ScanType int scanType, Set<Integer> freqs,
            List<String> hiddenNetworkSSIDs, boolean enable6GhzRnr) {
        List<byte[]> hiddenNetworkSsidsArrays = new ArrayList<>();
        for (String hiddenNetworkSsid : hiddenNetworkSSIDs) {
            try {
                hiddenNetworkSsidsArrays.add(
                        NativeUtil.byteArrayFromArrayList(
                                NativeUtil.decodeSsid(hiddenNetworkSsid)));
            } catch (IllegalArgumentException e) {
                Log.e(TAG, "Illegal argument " + hiddenNetworkSsid, e);
                continue;
            }
        }
        // enable6GhzRnr is a new parameter first introduced in Android S.
        if (SdkLevel.isAtLeastS()) {
            Bundle extraScanningParams = new Bundle();
            extraScanningParams.putBoolean(WifiNl80211Manager.SCANNING_PARAM_ENABLE_6GHZ_RNR,
                    enable6GhzRnr);
            return mWifiCondManager.startScan(ifaceName, scanType, freqs, hiddenNetworkSsidsArrays,
                    extraScanningParams); //调用WifiCondManager的startScan方法
        } else {
            return mWifiCondManager.startScan(ifaceName, scanType, freqs, hiddenNetworkSsidsArrays); //调用WifiCondManager的startScan方法
        }
    }
}

调用WifiNl80211Manager的startScan方法:

//frameworks/base/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
public class WifiNl80211Manager {
    //使用指定的参数启动扫描。扫描是一种异步操作。操作结果在使用 设置接口时注册的 {@link 扫描事件回调} 中返回
    public boolean startScan(@NonNull String ifaceName, @WifiAnnotations.ScanType int scanType,
            @SuppressLint("NullableCollection") @Nullable Set<Integer> freqs,
            @SuppressLint("NullableCollection") @Nullable List<byte[]> hiddenNetworkSSIDs,
            @SuppressLint("NullableCollection") @Nullable Bundle extraScanningParams) {
        IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
        if (scannerImpl == null) {
            Log.e(TAG, "No valid wificond scanner interface handler for iface=" + ifaceName);
            return false;
        }
        SingleScanSettings settings = new SingleScanSettings();
        try {
            settings.scanType = getScanType(scanType);
        } catch (IllegalArgumentException e) {
            Log.e(TAG, "Invalid scan type ", e);
            return false;
        }
        settings.channelSettings  = new ArrayList<>();
        settings.hiddenNetworks  = new ArrayList<>();
        if (extraScanningParams != null) {
            settings.enable6GhzRnr = extraScanningParams.getBoolean(SCANNING_PARAM_ENABLE_6GHZ_RNR);
        }


        if (freqs != null) {
            for (Integer freq : freqs) {
                ChannelSettings channel = new ChannelSettings();
                channel.frequency = freq;
                settings.channelSettings.add(channel);
            }
        }
        if (hiddenNetworkSSIDs != null) {
            for (byte[] ssid : hiddenNetworkSSIDs) {
                HiddenNetwork network = new HiddenNetwork();
                network.ssid = ssid;


                // settings.hiddenNetworks is expected to be very small, so this shouldn't cause
                // any performance issues.
                if (!settings.hiddenNetworks.contains(network)) {
                    settings.hiddenNetworks.add(network);
                }
            }
        }


        try {
            return scannerImpl.scan(settings); //调用IWifiScannerImpl的scan方法
        } catch (RemoteException e1) {
            Log.e(TAG, "Failed to request scan due to remote exception");
        }
        return false;
    }
}

调用IWifiScannerImpl的scan方法,IWifiScannerImpl是一个AIDL接口,由wificond的ScannerImp类实现,之后就是HAL层的处理了,这里就不再介绍了。

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值